Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add StatePrep support #146

Merged
merged 14 commits into from
Aug 22, 2023
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, '3.10']
python-version: [3.9, '3.10', '3.11']

steps:
- name: Cancel Previous Runs
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Release 0.32.0-dev
# Release 0.32.0

albi3ro marked this conversation as resolved.
Show resolved Hide resolved
### New features since last release

Expand All @@ -12,10 +12,14 @@

### Bug fixes 🐛

* The plugin is updated to take `qml.StatePrep` operators, the new name for `qml.QubitStateVector`.

albi3ro marked this conversation as resolved.
Show resolved Hide resolved
### Contributors ✍️

This release contains contributions from (in alphabetical order):

Christina Lee

---
# Release 0.31.0

Expand Down
5 changes: 3 additions & 2 deletions pennylane_cirq/cirq_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def __init__(self, wires, shots, qubits=None):
**{f"Pow({k})": v for k, v in _pow_operation_map.items()},
"BasisState": None,
"QubitStateVector": None,
"StatePrep": None,
"QubitUnitary": CirqOperation(cirq.MatrixGate),
"PauliX": CirqOperation(lambda: cirq.X),
"PauliY": CirqOperation(lambda: cirq.Y),
Expand Down Expand Up @@ -271,14 +272,14 @@ def apply(self, operations, **kwargs):
rotations = kwargs.pop("rotations", [])

for i, operation in enumerate(operations):
if i > 0 and operation.name in {"BasisState", "QubitStateVector"}:
if i > 0 and operation.name in {"BasisState", "QubitStateVector", "StatePrep"}:
albi3ro marked this conversation as resolved.
Show resolved Hide resolved
raise qml.DeviceError(
f"The operation {operation.name} is only supported at the beginning of a circuit."
)

if operation.name == "BasisState":
self._apply_basis_state(operation)
elif operation.name == "QubitStateVector":
elif operation.name in {"StatePrep", "QubitStateVector"}:
self._apply_qubit_state_vector(operation)
else:
self._apply_operation(operation)
Expand Down
2 changes: 2 additions & 0 deletions pennylane_cirq/qsim_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def operations(self):
# pylint: disable=missing-function-docstring
return set(self._base_operation_map) - {
"QubitStateVector",
"StatePrep",
"BasisState",
"CRX",
"CRY",
Expand Down Expand Up @@ -122,6 +123,7 @@ def operations(self):
# pylint: disable=missing-function-docstring
return set(self._base_operation_map) - {
"QubitStateVector",
"StatePrep",
"BasisState",
"CRX",
"CRY",
Expand Down
6 changes: 3 additions & 3 deletions pennylane_cirq/simulator_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def reset(self):
def capabilities(self): # pylint: disable=missing-function-docstring
capabilities = super().capabilities().copy()
capabilities.update(
returns_state=(self.shots is None) # State information is only set if obtaining shots
returns_state=self.shots is None # State information is only set if obtaining shots
)
return capabilities

Expand All @@ -94,7 +94,7 @@ def _apply_qubit_state_vector(self, qubit_state_vector_operation):
# pylint: disable=missing-function-docstring
if self.shots is not None:
raise qml.DeviceError(
"The operation QubitStateVector is only supported in analytic mode."
"The operations StatePrep and QubitStateVector are only supported in analytic mode."
)

self._initial_state = qubit_state_vector_operation.state_vector(
Expand Down Expand Up @@ -240,7 +240,7 @@ def __init__(self, wires, shots=None, qubits=None):
def capabilities(self): # pylint: disable=missing-function-docstring
capabilities = super().capabilities().copy()
capabilities.update(
returns_state=(self.shots is None) # State information is only set if obtaining shots
returns_state=self.shots is None # State information is only set if obtaining shots
)
return capabilities

Expand Down
32 changes: 16 additions & 16 deletions tests/test_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def test_qubit_state_vector(self, init_state, shots, tol):
state = init_state(1)

with mimic_execution_for_apply(dev):
dev.apply([qml.QubitStateVector(state, wires=[0])])
dev.apply([qml.StatePrep(state, wires=[0])])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can also rename the test

albi3ro marked this conversation as resolved.
Show resolved Hide resolved

res = dev._state
expected = state
Expand All @@ -127,7 +127,7 @@ def test_single_qubit_no_parameters(self, init_state, shots, name, mat, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0]),
qml.StatePrep(state, wires=[0]),
qml.__getattribute__(name)(wires=[0]),
]
)
Expand All @@ -146,7 +146,7 @@ def test_single_qubit_parameters(self, init_state, shots, name, func, theta, tol
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0]),
qml.StatePrep(state, wires=[0]),
qml.__getattribute__(name)(theta, wires=[0]),
]
)
Expand All @@ -165,7 +165,7 @@ def test_rotation(self, init_state, shots, tol):
c = -0.654

with mimic_execution_for_apply(dev):
dev.apply([qml.QubitStateVector(state, wires=[0]), qml.Rot(a, b, c, wires=[0])])
dev.apply([qml.StatePrep(state, wires=[0]), qml.Rot(a, b, c, wires=[0])])

res = dev._state
expected = rot(a, b, c) @ state
Expand All @@ -180,7 +180,7 @@ def test_two_qubit_no_parameters(self, init_state, shots, name, mat, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0, 1]),
qml.StatePrep(state, wires=[0, 1]),
qml.__getattribute__(name)(wires=[0, 1]),
]
)
Expand All @@ -198,7 +198,7 @@ def test_qubit_unitary(self, init_state, shots, mat, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=list(range(N))),
qml.StatePrep(state, wires=list(range(N))),
qml.QubitUnitary(mat, wires=list(range(N))),
]
)
Expand All @@ -225,7 +225,7 @@ def test_three_qubit_no_parameters(self, init_state, shots, name, mat, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0, 1, 2]),
qml.StatePrep(state, wires=[0, 1, 2]),
qml.__getattribute__(name)(wires=[0, 1, 2]),
]
)
Expand All @@ -244,7 +244,7 @@ def test_two_qubits_parameters(self, init_state, shots, name, func, theta, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0, 1]),
qml.StatePrep(state, wires=[0, 1]),
qml.__getattribute__(name)(theta, wires=[0, 1]),
]
)
Expand Down Expand Up @@ -294,7 +294,7 @@ def test_qubit_state_vector(self, init_state, shots, tol):
state = init_state(1)

with mimic_execution_for_apply(dev):
dev.apply([qml.QubitStateVector(state, wires=[0])])
dev.apply([qml.StatePrep(state, wires=[0])])

res = dev._state
expected = state
Expand All @@ -310,7 +310,7 @@ def test_single_qubit_no_parameters(self, init_state, shots, name, mat, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0]),
qml.StatePrep(state, wires=[0]),
qml.__getattribute__(name)(wires=[0]),
]
)
Expand All @@ -330,7 +330,7 @@ def test_single_qubit_parameters(self, init_state, shots, name, func, theta, tol
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0]),
qml.StatePrep(state, wires=[0]),
qml.__getattribute__(name)(theta, wires=[0]),
]
)
Expand All @@ -350,7 +350,7 @@ def test_rotation(self, init_state, shots, tol):
c = -0.654

with mimic_execution_for_apply(dev):
dev.apply([qml.QubitStateVector(state, wires=[0]), qml.Rot(a, b, c, wires=[0])])
dev.apply([qml.StatePrep(state, wires=[0]), qml.Rot(a, b, c, wires=[0])])

res = dev._state
expected = rot(a, b, c) @ state
Expand All @@ -366,7 +366,7 @@ def test_two_qubit_no_parameters(self, init_state, shots, name, mat, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0, 1]),
qml.StatePrep(state, wires=[0, 1]),
qml.__getattribute__(name)(wires=[0, 1]),
]
)
Expand All @@ -385,7 +385,7 @@ def test_qubit_unitary(self, init_state, shots, mat, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=list(range(N))),
qml.StatePrep(state, wires=list(range(N))),
qml.QubitUnitary(mat, wires=list(range(N))),
]
)
Expand Down Expand Up @@ -413,7 +413,7 @@ def test_three_qubit_no_parameters(self, init_state, shots, name, mat, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0, 1, 2]),
qml.StatePrep(state, wires=[0, 1, 2]),
qml.__getattribute__(name)(wires=[0, 1, 2]),
]
)
Expand All @@ -433,7 +433,7 @@ def test_two_qubits_parameters(self, init_state, shots, name, func, theta, tol):
with mimic_execution_for_apply(dev):
dev.apply(
[
qml.QubitStateVector(state, wires=[0, 1]),
qml.StatePrep(state, wires=[0, 1]),
qml.__getattribute__(name)(theta, wires=[0, 1]),
]
)
Expand Down
36 changes: 18 additions & 18 deletions tests/test_mixed_simulator_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,16 @@ def test_apply_operation_two_wires_no_parameters(
(qml.BasisState, [0, 0, 1, 0], [1, 0]),
(qml.BasisState, [0, 0, 1, 0], [1, 0]),
(qml.BasisState, [0, 0, 0, 1], [1, 1]),
(qml.QubitStateVector, [0, 0, 1, 0], [0, 0, 1, 0]),
(qml.QubitStateVector, [0, 0, 1, 0], [0, 0, 1, 0]),
(qml.QubitStateVector, [0, 0, 0, 1], [0, 0, 0, 1]),
(qml.StatePrep, [0, 0, 1, 0], [0, 0, 1, 0]),
(qml.StatePrep, [0, 0, 1, 0], [0, 0, 1, 0]),
(qml.StatePrep, [0, 0, 0, 1], [0, 0, 0, 1]),
(
qml.QubitStateVector,
qml.StatePrep,
[1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)],
[1 / math.sqrt(3), 0, 1 / math.sqrt(3), 1 / math.sqrt(3)],
),
(
qml.QubitStateVector,
qml.StatePrep,
[1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)],
[1 / math.sqrt(3), 0, -1 / math.sqrt(3), 1 / math.sqrt(3)],
),
Expand Down Expand Up @@ -438,17 +438,17 @@ def test_basis_state_not_at_beginning_error(self, simulator_device_1_wire):
simulator_device_1_wire.apply([qml.PauliX(0), qml.BasisState(np.array([0]), wires=[0])])

def test_qubit_state_vector_not_at_beginning_error(self, simulator_device_1_wire):
"""Tests that application of QubitStateVector raises an error if is not
"""Tests that application of StatePrep raises an error if is not
albi3ro marked this conversation as resolved.
Show resolved Hide resolved
the first operation."""

simulator_device_1_wire.reset()

with pytest.raises(
qml.DeviceError,
match="The operation QubitStateVector is only supported at the beginning of a circuit.",
match="The operation StatePrep is only supported at the beginning of a circuit.",
):
simulator_device_1_wire.apply(
[qml.PauliX(0), qml.QubitStateVector(np.array([0, 1]), wires=[0])]
[qml.PauliX(0), qml.StatePrep(np.array([0, 1]), wires=[0])]
)


Expand All @@ -464,21 +464,21 @@ def test_basis_state_not_analytic_error(self, simulator_device_1_wire):

with pytest.raises(
qml.DeviceError,
match="The operation BasisState is only supported in analytic mode.",
match="The operation BasisState are only supported in analytic mode.",
albi3ro marked this conversation as resolved.
Show resolved Hide resolved
):
simulator_device_1_wire.apply([qml.BasisState(np.array([0]), wires=[0])])

def test_qubit_state_vector_not_analytic_error(self, simulator_device_1_wire):
"""Tests that application of QubitStateVector raises an error if the device
"""Tests that application of StatePrep raises an error if the device
albi3ro marked this conversation as resolved.
Show resolved Hide resolved
is not in analytic mode."""

simulator_device_1_wire.reset()

with pytest.raises(
qml.DeviceError,
match="The operation QubitStateVector is only supported in analytic mode.",
match="The operations StatePrep and QubitStateVector are only supported in analytic mode.",
):
simulator_device_1_wire.apply([qml.QubitStateVector(np.array([0, 1]), wires=[0])])
simulator_device_1_wire.apply([qml.StatePrep(np.array([0, 1]), wires=[0])])


@pytest.mark.parametrize("shots", [None])
Expand Down Expand Up @@ -527,7 +527,7 @@ def test_expval_single_wire_no_parameters(

simulator_device_1_wire.reset()
simulator_device_1_wire.apply(
[qml.QubitStateVector(np.array(input), wires=[0])], rotations=op.diagonalizing_gates()
[qml.StatePrep(np.array(input), wires=[0])], rotations=op.diagonalizing_gates()
)

res = simulator_device_1_wire.expval(op)
Expand Down Expand Up @@ -556,7 +556,7 @@ def test_expval_single_wire_with_parameters(

simulator_device_1_wire.reset()
simulator_device_1_wire.apply(
[qml.QubitStateVector(np.array(input), wires=[0])], rotations=op.diagonalizing_gates()
[qml.StatePrep(np.array(input), wires=[0])], rotations=op.diagonalizing_gates()
)

res = simulator_device_1_wire.expval(op)
Expand Down Expand Up @@ -642,7 +642,7 @@ def test_expval_two_wires_with_parameters(

simulator_device_2_wires.reset()
simulator_device_2_wires.apply(
[qml.QubitStateVector(np.array(input), wires=[0, 1])],
[qml.StatePrep(np.array(input), wires=[0, 1])],
rotations=op.diagonalizing_gates(),
)

Expand Down Expand Up @@ -726,7 +726,7 @@ def test_var_single_wire_no_parameters(

simulator_device_1_wire.reset()
simulator_device_1_wire.apply(
[qml.QubitStateVector(np.array(input), wires=[0])],
[qml.StatePrep(np.array(input), wires=[0])],
rotations=op.diagonalizing_gates(),
)

Expand Down Expand Up @@ -762,7 +762,7 @@ def test_var_single_wire_with_parameters(

simulator_device_1_wire.reset()
simulator_device_1_wire.apply(
[qml.QubitStateVector(np.array(input), wires=[0])],
[qml.StatePrep(np.array(input), wires=[0])],
rotations=op.diagonalizing_gates(),
)

Expand Down Expand Up @@ -817,7 +817,7 @@ def test_var_two_wires_with_parameters(

simulator_device_2_wires.reset()
simulator_device_2_wires.apply(
[qml.QubitStateVector(np.array(input), wires=[0, 1])],
[qml.StatePrep(np.array(input), wires=[0, 1])],
rotations=op.diagonalizing_gates(),
)

Expand Down
6 changes: 3 additions & 3 deletions tests/test_qsim_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ def circuit(x, y, z):

@pytest.mark.parametrize("shots", [8192, None])
@pytest.mark.parametrize(
"op, params", [(qml.QubitStateVector, np.array([0, 1])), (qml.BasisState, np.array([1]))]
"op, params", [(qml.StatePrep, np.array([0, 1])), (qml.BasisState, np.array([1]))]
)
def test_decomposition(self, shots, op, params, mocker):
"""Test that QubitStateVector and BasisState are decomposed"""
"""Test that StatePrep and BasisState are decomposed"""

dev = qml.device("cirq.qsim", wires=1, shots=shots)

Expand Down Expand Up @@ -101,7 +101,7 @@ def test_adjoint_ops_not_supported(self):
@pytest.mark.parametrize(
"gate",
[
"QubitStateVector",
"StatePrep",
"BasisState",
"CRX",
"CRY",
Expand Down
Loading
Loading