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

Remove expand_depth in compile transform and max_expansion in clifford_t_decomposition transform #6531

Merged
merged 9 commits into from
Nov 11, 2024
22 changes: 11 additions & 11 deletions doc/development/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,6 @@ Pending deprecations
- Deprecated in v0.40
- Will be removed in v0.41

* The ``max_expansion`` argument for :func:`~pennylane.transforms.decompositions.clifford_t_decomposition`
has been deprecated.

- Deprecated in v0.39
- Will be removed in v0.40

* The ``expand_depth`` argument for :func:`~pennylane.transforms.compile` has been deprecated.

- Deprecated in v0.39
- Will be removed in v0.40

* The ``'ancilla'`` argument for :func:`~pennylane.iterative_qpe` has been deprecated. Instead, use the ``'aux_wire'``
argument.

Expand Down Expand Up @@ -122,6 +111,17 @@ Other deprecations
Completed deprecation cycles
----------------------------

* The ``max_expansion`` argument for :func:`~pennylane.transforms.decompositions.clifford_t_decomposition`
has been removed.

- Deprecated in v0.39
- Removed in v0.40

* The ``expand_depth`` argument for :func:`~pennylane.transforms.compile` has been removed.

- Deprecated in v0.39
- Removed in v0.40

* The ``qml.shadows.shadow_expval`` transform has been removed. Instead, please use the
``qml.shadow_expval`` measurement process.

Expand Down
6 changes: 6 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@

<h3>Breaking changes 💔</h3>

* The `max_expansion` argument for `qml.transforms.clifford_t_decomposition` has been removed.
[(#6531)](https://github.com/PennyLaneAI/pennylane/pull/6531)

* The `expand_depth` argument for `qml.compile` has been removed.
[(#6531)](https://github.com/PennyLaneAI/pennylane/pull/6531)

* The `qml.shadows.shadow_expval` transform has been removed. Instead, please use the
`qml.shadow_expval` measurement process.
[(#6530)](https://github.com/PennyLaneAI/pennylane/pull/6530)
Expand Down
16 changes: 1 addition & 15 deletions pennylane/transforms/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Code for the high-level quantum function transform that executes compilation."""
import warnings

# pylint: disable=too-many-branches
from functools import partial

Expand All @@ -35,7 +33,7 @@

@transform
def compile(
tape: QuantumScript, pipeline=None, basis_set=None, num_passes=1, expand_depth=None
tape: QuantumScript, pipeline=None, basis_set=None, num_passes=1
) -> tuple[QuantumScriptBatch, PostprocessingFn]:
"""Compile a circuit by applying a series of transforms to a quantum function.

Expand All @@ -48,9 +46,6 @@ def compile(
- merging adjacent rotations of the same type
(:func:`~pennylane.transforms.merge_rotations`)

.. warning::
The ``expand_depth`` argument is deprecated and will be removed in version 0.40.

Args:
tape (QNode or QuantumTape or Callable): A quantum circuit.
pipeline (list[Callable]): A list of
Expand All @@ -65,7 +60,6 @@ def compile(
however, doing so may produce a new circuit where applying the set
of transforms again may yield further improvement, so the number of
such passes can be adjusted.
expand_depth (int): The depth to use for tape expansion into the basis gates.

Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]: The compiled circuit. The output type is explained in :func:`qml.transform <pennylane.transform>`.
Expand Down Expand Up @@ -167,13 +161,6 @@ def qfunc(x, y, z):
───RY(-1.57)─╰X─┤

"""
if expand_depth is not None:
warnings.warn(
"The expand_depth argument is deprecated and will be removed in version v0.40.",
qml.PennyLaneDeprecationWarning,
)
else:
expand_depth = 5

# Ensure that everything in the pipeline is a valid qfunc or tape transform
if pipeline is None:
Expand Down Expand Up @@ -205,7 +192,6 @@ def stop_at(obj):
[expanded_tape], _ = qml.devices.preprocess.decompose(
tape,
stopping_condition=stop_at,
max_expansion=expand_depth,
name="compile",
error=qml.operation.DecompositionUndefinedError,
skip_initial_state_prep=False,
Expand Down
26 changes: 3 additions & 23 deletions pennylane/transforms/decompositions/clifford_t_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,6 @@ def _merge_param_gates(operations, merge_ops=None):
def clifford_t_decomposition(
tape: QuantumScript,
epsilon=1e-4,
max_expansion=None,
method="sk",
**method_kwargs,
) -> tuple[QuantumScriptBatch, PostprocessingFn]:
Expand All @@ -328,13 +327,9 @@ def clifford_t_decomposition(
:math:`\epsilon > 0` error. By default, we use the Solovay-Kitaev algorithm described in
`Dawson and Nielsen (2005) <https://arxiv.org/abs/quant-ph/0505030>`_ for this.

.. warning::
The ``max_expansion`` argument is deprecated and will be removed in version 0.40.

Args:
tape (QNode or QuantumTape or Callable): The quantum circuit to be decomposed.
epsilon (float): The maximum permissible operator norm error of the complete circuit decomposition. Defaults to ``0.0001``.
max_expansion (int): The depth to be used for tape expansion before manual decomposition to Clifford+T basis is applied.
method (str): Method to be used for Clifford+T decomposition. Default value is ``"sk"`` for Solovay-Kitaev.
**method_kwargs: Keyword argument to pass options for the ``method`` used for decompositions.

Expand Down Expand Up @@ -373,29 +368,14 @@ def circuit(x, y):
>>> qml.math.allclose(result, approx, atol=1e-4)
True
"""
if max_expansion is not None:
warnings.warn(
"The max_expansion argument is deprecated and will be removed in version v0.40. ",
qml.PennyLaneDeprecationWarning,
)
else:
max_expansion = 6

with QueuingManager.stop_recording():
# Build the basis set and the pipeline for intial compilation pass
# Build the basis set and the pipeline for initial compilation pass
basis_set = [op.__name__ for op in _PARAMETER_GATES + _CLIFFORD_T_GATES]
pipelines = [remove_barrier, commute_controlled, cancel_inverses, merge_rotations]

# Compile the tape according to depth provided by the user and expand it
with warnings.catch_warnings():
warnings.filterwarnings(
mudit2812 marked this conversation as resolved.
Show resolved Hide resolved
action="ignore",
message=r"The expand_depth argument is deprecated",
category=qml.PennyLaneDeprecationWarning,
)
[compiled_tape], _ = qml.compile(
tape, pipelines, basis_set=basis_set, expand_depth=max_expansion
)
[compiled_tape], _ = qml.compile(tape, pipelines, basis_set=basis_set)

# Now iterate over the expanded tape operations
decomp_ops, gphase_ops = [], []
Expand Down Expand Up @@ -453,7 +433,7 @@ def circuit(x, y):
# Resort to decomposing manually
d_ops = _two_qubit_decompose(md_op)

# Final resort (should not enter in an ideal situtation)
# Final resort (should not enter in an ideal situation)
else:
d_ops = md_op.decomposition()

Expand Down
16 changes: 4 additions & 12 deletions tests/transforms/core/test_transform_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,25 +156,18 @@ class TestTransformContainer:
def test_repr(self):
"""Tests for the repr of a transform container."""
t1 = qml.transforms.core.TransformContainer(
qml.transforms.compile.transform, kwargs={"num_passes": 2, "expand_depth": 1}
qml.transforms.compile.transform, kwargs={"num_passes": 2}
)
assert repr(t1) == "<compile([], {'num_passes': 2, 'expand_depth': 1})>"
assert repr(t1) == "<compile([], {'num_passes': 2})>"

def test_equality(self):
"""Tests that we can compare TransformContainer objects with the '==' and '!=' operators."""

t1 = TransformContainer(
qml.transforms.compile.transform, kwargs={"num_passes": 2, "expand_depth": 1}
)
t2 = TransformContainer(
qml.transforms.compile.transform, kwargs={"num_passes": 2, "expand_depth": 1}
)
t1 = TransformContainer(qml.transforms.compile.transform, kwargs={"num_passes": 2})
t2 = TransformContainer(qml.transforms.compile.transform, kwargs={"num_passes": 2})
t3 = TransformContainer(
qml.transforms.transpile.transform, kwargs={"coupling_map": [(0, 1), (1, 2)]}
)
t4 = TransformContainer(
qml.transforms.compile.transform, kwargs={"num_passes": 2, "expand_depth": 2}
)

t5 = TransformContainer(qml.transforms.merge_rotations.transform, args=(1e-6,))
t6 = TransformContainer(qml.transforms.merge_rotations.transform, args=(1e-7,))
Expand All @@ -186,7 +179,6 @@ def test_equality(self):
assert t1 != t3
assert t2 != t3
assert t1 != 2
assert t1 != t4
assert t5 != t6
assert t5 != t1

Expand Down
8 changes: 2 additions & 6 deletions tests/transforms/core/test_transform_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,12 +311,8 @@ def test_repr_program(self):

def test_equality(self):
"""Tests that we can compare TransformProgram objects with the '==' and '!=' operators."""
t1 = TransformContainer(
qml.transforms.compile.transform, kwargs={"num_passes": 2, "expand_depth": 1}
)
t2 = TransformContainer(
qml.transforms.compile.transform, kwargs={"num_passes": 2, "expand_depth": 1}
)
t1 = TransformContainer(qml.transforms.compile.transform, kwargs={"num_passes": 2})
t2 = TransformContainer(qml.transforms.compile.transform, kwargs={"num_passes": 2})
t3 = TransformContainer(
qml.transforms.transpile.transform, kwargs={"coupling_map": [(0, 1), (1, 2)]}
)
Expand Down
99 changes: 76 additions & 23 deletions tests/transforms/test_cliffordt_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import pennylane as qml
from pennylane.transforms.decompositions.clifford_t_transform import (
_CLIFFORD_T_GATES,
_merge_param_gates,
_one_qubit_decompose,
_rot_decompose,
_two_qubit_decompose,
Expand Down Expand Up @@ -80,16 +81,11 @@ def circuit_5():
return qml.expval(qml.PauliZ(0))


def test_max_expansion_is_deprecated():
"""Tests that max_expansion is deprecated"""
with pytest.warns(
qml.PennyLaneDeprecationWarning,
match="The max_expansion argument is deprecated",
):
tape = qml.tape.QuantumScript([qml.QubitUnitary(qml.math.eye(8), wires=[0, 1, 2])])

with pytest.raises(ValueError, match="Cannot unroll"):
clifford_t_decomposition(tape, max_expansion=0)
def circuit_6():
"""Circuit 6 with skippable operations"""
qml.RZ(1.0, wires=[0])
qml.Barrier(wires=0)
return qml.expval(qml.PauliZ(0))


class TestCliffordCompile:
Expand All @@ -114,20 +110,15 @@ def test_clifford_checker(self, op, res):
assert check_clifford_t(op, use_decomposition=True) == res

@pytest.mark.parametrize(
("circuit, max_expansion"),
[(circuit_1, 1), (circuit_2, 0), (circuit_3, 0), (circuit_4, 1), (circuit_5, 0)],
"circuit",
[circuit_1, circuit_2, circuit_3, circuit_4, circuit_5, circuit_6],
)
def test_decomposition(self, circuit, max_expansion):
def test_decomposition(self, circuit):
"""Test decomposition for the Clifford transform."""

old_tape = qml.tape.make_qscript(circuit)()

with pytest.warns(
qml.PennyLaneDeprecationWarning, match="max_expansion argument is deprecated"
):
[new_tape], tape_fn = clifford_t_decomposition(
old_tape, max_expansion=max_expansion, max_depth=3
)
[new_tape], tape_fn = clifford_t_decomposition(old_tape, max_depth=3)

assert all(
isinstance(op, _CLIFFORD_PHASE_GATES)
Expand Down Expand Up @@ -188,6 +179,36 @@ def test_total_error(self, epsilon, circuit):
error = qml.math.sqrt(qml.math.real(qml.math.trace(qml.math.conj(diff).T @ diff)) / 2)
assert error < epsilon

@pytest.mark.parametrize(
"op",
[
qml.RY(qml.numpy.pi / 4, wires=0),
],
)
def test_zxz_rotation_decomposition(self, op):
"""Test single-qubit gates are decomposed correctly using ZXZ rotations"""

def circuit():
qml.apply(op)
return qml.probs(wires=0)

old_tape = qml.tape.make_qscript(circuit)()

[new_tape], tape_fn = clifford_t_decomposition(old_tape, max_depth=3)

assert all(
isinstance(op, _CLIFFORD_PHASE_GATES)
or isinstance(getattr(op, "base", None), _CLIFFORD_PHASE_GATES)
for op in new_tape.operations
)

dev = qml.device("default.qubit")
transform_program, _ = dev.preprocess()
res1, res2 = qml.execute(
[old_tape, new_tape], device=dev, transform_program=transform_program
)
qml.math.isclose(res1, tape_fn([res2]), atol=1e-2)

@pytest.mark.parametrize(
"op", [qml.RX(1.0, wires="a"), qml.U3(1, 2, 3, wires=[1]), qml.PhaseShift(1.0, wires=[2])]
)
Expand Down Expand Up @@ -290,16 +311,48 @@ def test_rot_decomposition(self, op):
)[qml.math.nonzero(qml.math.round(matrix_op, 10))]
assert qml.math.allclose(phase / phase[0], qml.math.ones(qml.math.shape(phase)[0]))

def test_merge_param_gates(self):
"""Test _merge_param_gates helper function"""
operations = [
qml.RX(0.1, wires=0),
qml.RX(0.2, wires=0),
qml.RY(0.3, wires=1),
qml.RY(0.4, wires=1),
qml.RX(0.5, wires=0),
]

merge_ops = {"RX", "RY"}

merged_ops, number_ops = _merge_param_gates(operations, merge_ops=merge_ops)

assert len(merged_ops) == 2
assert number_ops == 2

assert isinstance(merged_ops[0], qml.RX)
assert merged_ops[0].parameters == [0.8] # 0.1 + 0.2 + 0.5 for wire 0
assert isinstance(merged_ops[1], qml.RY)
assert merged_ops[1].parameters == [0.7] # 0.3 + 0.4 for wire 1

merge_ops.discard("RY")
merged_ops, number_ops = _merge_param_gates(operations, merge_ops=merge_ops)

assert len(merged_ops) == 3
assert number_ops == 1

assert isinstance(merged_ops[0], qml.RX)
assert merged_ops[0].parameters == [0.8] # 0.1 + 0.2 + 0.5 for wire 0
assert isinstance(merged_ops[1], qml.RY)
assert merged_ops[1].parameters == [0.3] # 0.3 for wire 1
assert isinstance(merged_ops[1], qml.RY)
assert merged_ops[2].parameters == [0.4] # 0.4 for wire 1

def test_raise_with_cliffordt_decomposition(self):
"""Test that exception is correctly raise when decomposing gates without any decomposition"""

tape = qml.tape.QuantumScript([qml.QubitUnitary(qml.math.eye(8), wires=[0, 1, 2])])

with pytest.raises(ValueError, match="Cannot unroll"):
with pytest.warns(
qml.PennyLaneDeprecationWarning, match="max_expansion argument is deprecated"
):
clifford_t_decomposition(tape, max_expansion=0)
clifford_t_decomposition(tape)

@pytest.mark.parametrize("op", [qml.U1(1.0, wires=["b"])])
def test_raise_with_rot_decomposition(self, op):
Expand Down
13 changes: 0 additions & 13 deletions tests/transforms/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,6 @@
from pennylane.wires import Wires


def test_expand_depth_is_deprecated():
"""Tests that expand_depth is deprecated"""
with pytest.warns(
qml.PennyLaneDeprecationWarning,
match="The expand_depth argument is deprecated",
):
ops = (qml.RX(0.1, 0), qml.RX(0.2, 0), qml.Barrier(only_visual=True), qml.X(0), qml.X(0))
ms = (qml.expval(qml.X(0)), qml.expval(qml.Y(0)))
tape = qml.tape.QuantumScript(ops, ms, shots=50)

_, _ = qml.compile(tape, expand_depth=2)


def build_qfunc(wires):
def qfunc(x, y, z):
qml.Hadamard(wires=wires[0])
Expand Down