Skip to content

Commit

Permalink
Merge branch 'master' into qutrit_channel_depolarizing
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabriel-Bottrill authored May 14, 2024
2 parents a37c0e6 + 57e8d93 commit 1b7f58b
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 35 deletions.
8 changes: 6 additions & 2 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,19 @@

<h3>Bug fixes 🐛</h3>

* Use vanilla NumPy arrays in `test_projector_expectation` to avoid differentiating `qml.Projector` with respect to the state attribute.
[(#5683)](https://github.com/PennyLaneAI/pennylane/pull/5683)

* `qml.Projector` is now compatible with jax-jit.
[(#5595)](https://github.com/PennyLaneAI/pennylane/pull/5595)

* Finite shot circuits with a `qml.probs` measurement, both with a `wires` or `op` argument, can now be compiled with `jax.jit`.
[(#5619)](https://github.com/PennyLaneAI/pennylane/pull/5619)

* `param_shift`, `finite_diff`, `compile`, `merge_rotations`, and `transpile` now all work
with circuits with non-commuting measurements.
* `param_shift`, `finite_diff`, `compile`, `insert`, `merge_rotations`, and `transpile` now
all work with circuits with non-commuting measurements.
[(#5424)](https://github.com/PennyLaneAI/pennylane/pull/5424)
[(#5681)](https://github.com/PennyLaneAI/pennylane/pull/5681)

* A correction is added to `bravyi_kitaev` to call the correct function for a FermiSentence input.
[(#5671)](https://github.com/PennyLaneAI/pennylane/pull/5671)
Expand Down
10 changes: 6 additions & 4 deletions pennylane/devices/tests/test_compare_default_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests that a device gives the same output as the default device."""
import numpy as np

# pylint: disable=no-self-use,no-member
import pytest
from flaky import flaky
Expand Down Expand Up @@ -90,10 +92,10 @@ def workload():
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
pnp.array([1, 1, 0, 0]) / pnp.sqrt(2),
pnp.array([0, 1, 0, 1]) / pnp.sqrt(2),
pnp.array([1, 1, 1, 0]) / pnp.sqrt(3),
pnp.array([1, 1, 1, 1]) / 2,
np.array([1, 1, 0, 0]) / np.sqrt(2),
np.array([0, 1, 0, 1]) / np.sqrt(2),
np.array([1, 1, 1, 0]) / np.sqrt(3),
np.array([1, 1, 1, 1]) / 2,
],
)
def test_projector_expectation(self, device, state, tol, benchmark):
Expand Down
32 changes: 17 additions & 15 deletions pennylane/transforms/insert_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ def insert(
Raises:
QuantumFunctionError: if some observables in the tape are not qubit-wise commuting
ValueError: if a single operation acting on multiple wires is passed to ``op``
ValueError: if the requested ``position`` argument is not ``'start'``, ``'end'`` or
``'all'`` OR PennyLane Operation
Expand All @@ -100,9 +99,11 @@ def insert(
.. code-block:: python3
from functools import partial
dev = qml.device("default.mixed", wires=2)
@partial(qml.transforms.insert, qml.AmplitudeDamping, 0.2, position="end")
@partial(qml.transforms.insert, op=qml.AmplitudeDamping, op_args=0.2, position="end")
@qml.qnode(dev)
def f(w, x, y, z):
qml.RX(w, wires=0)
Expand Down Expand Up @@ -141,7 +142,7 @@ def op(x, y, wires):
dev = qml.device("default.qubit", wires=2)
@qml.qnode(dev)
@qml.transforms.insert(op, [0.2, 0.3], position="end")
@partial(qml.transforms.insert, op=op, op_args=[0.2, 0.3], position="end")
def f(w, x, y, z):
qml.RX(w, wires=0)
qml.RY(x, wires=1)
Expand Down Expand Up @@ -175,7 +176,7 @@ def f(w, x, y, z):
We can add the :class:`~.AmplitudeDamping` channel to the end of the circuit using:
>>> from pennylane.transforms import insert
>>> noisy_tape = insert(tape, qml.AmplitudeDamping, 0.05, position="end")
>>> [noisy_tape], _ = insert(tape, qml.AmplitudeDamping, 0.05, position="end")
>>> print(qml.drawer.tape_text(noisy_tape, decimals=2))
0: ──RX(0.90)─╭●──RY(0.50)──AmplitudeDamping(0.05)─┤ ╭<Z@Z>
1: ──RY(0.40)─╰X──RX(0.60)──AmplitudeDamping(0.05)─┤ ╰<Z@Z>
Expand Down Expand Up @@ -210,17 +211,18 @@ def f(w, x, y, z):
>>> qnode_noisy(0.9, 0.4, 0.5, 0.6)
tensor(0.72945434, requires_grad=True)
"""
# decompose templates and their adjoints (which fixes a bug in the tutorial_error_mitigation demo)
# TODO: change this to be cleaner and more robust
try:
tape = tape.expand(
stop_at=lambda op: not hasattr(qml.templates, op.name) and not isinstance(op, Adjoint)
)
except qml.QuantumFunctionError as e:
raise qml.QuantumFunctionError(
"The insert transform cannot transform a circuit measuring non-commuting observables. "
"Consider wrapping the gates in their own function and transforming only that function."
) from e

# decompose templates and their adjoints to fix a bug in the tutorial_error_mitigation demo
def stop_at(obj):
if not isinstance(obj, qml.operation.Operator):
return True
if not obj.has_decomposition:
return True
return not (hasattr(qml.templates, obj.name) or isinstance(obj, Adjoint))

error_type = (qml.operation.DecompositionUndefinedError,)
decompose = qml.devices.preprocess.decompose
[tape], _ = decompose(tape, stopping_condition=stop_at, name="insert", error=error_type)

if not isinstance(op, FunctionType) and op.num_wires != 1:
raise ValueError("Only single-qubit operations can be inserted into the circuit")
Expand Down
2 changes: 1 addition & 1 deletion requirements-ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ autograd
toml
appdirs
semantic_version
autoray
autoray>=0.6.1,<0.6.10
matplotlib
requests
tomli # Drop once minimum Python version is 3.11
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ autograd~=1.4
toml~=0.10
appdirs~=1.4
semantic_version~=2.10
autoray>=0.6.1
autoray>=0.6.1,<0.6.10
matplotlib~=3.5
opt_einsum~=3.3
requests~=2.31.0
Expand Down
28 changes: 16 additions & 12 deletions tests/transforms/test_insert_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,28 +602,32 @@ def f2(w1, w2):
assert np.allclose(f1(w1, w2), f2(w1, w2))


def test_insert_decorator_causes_custom_insert_error_non_qwc_obs():
def test_insert_transform_works_with_non_qwc_obs():
"""Test that the insert transform catches and reports errors from the enclosed function."""

# pylint: disable=unused-argument

def noise(noise_param, wires):
def op(noise_param, wires):
# pylint: disable=unused-argument
qml.CRX(noise_param, wires=[0, 1])
qml.CNOT(wires=[1, 0])

dev = qml.device("default.mixed", wires=2)
dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)
@partial(insert, op=noise, op_args=0.3, position="all")
@partial(insert, op=op, op_args=0.3, position="all")
def noisy_circuit(circuit_param):
qml.RY(circuit_param, wires=0)
qml.Hadamard(wires=0)
qml.T(wires=0)
return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliY(0)), qml.expval(qml.PauliZ(0))

# This tape's expansion fails, but shouldn't cause a downstream IndexError. See issue #3103
with pytest.raises(
qml.QuantumFunctionError,
match="The insert transform cannot transform a circuit measuring non-commuting observables",
):
noisy_circuit(0.4)
@qml.qnode(dev)
def explicit_circuit(circuit_param):
qml.RY(circuit_param, wires=0)
op(0.3, None)
qml.Hadamard(wires=0)
op(0.3, None)
qml.T(wires=0)
op(0.3, None)
return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliY(0)), qml.expval(qml.PauliZ(0))

assert np.allclose(noisy_circuit(0.4), explicit_circuit(0.4))

0 comments on commit 1b7f58b

Please sign in to comment.