Skip to content

Commit

Permalink
Fix coverage due to removal of max_expansion in `clifford_t_decompo…
Browse files Browse the repository at this point in the history
…sition.py` (#6571)

**Context:**

#6531 was accidentally merged into master with a net negative hit to the
project code coverage. This PR is designed to reconcile that impact and
clean-up the coverage.

**Description of the Change:**

The following logic branches were removed because they are not possible
to reach given the deprecation/removal of `expand_depth` in
`compile.py`.

For the sake of record keeping, comments by me are attached to each
logic branch indicating why it was removed.

**Benefits:** Restore original project code coverage.

**Possible Drawbacks:** None that I know of.

[sc-77499]
  • Loading branch information
andrijapau authored Nov 15, 2024
1 parent 9c2993a commit 93e9667
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 49 deletions.
1 change: 1 addition & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@

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

* The `expand_depth` argument for `qml.compile` has been removed.
[(#6531)](https://github.com/PennyLaneAI/pennylane/pull/6531)
Expand Down
43 changes: 5 additions & 38 deletions pennylane/transforms/decompositions/clifford_t_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def circuit(x, y):

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

# Compile the tape according to depth provided by the user and expand it
Expand Down Expand Up @@ -411,44 +411,11 @@ def circuit(x, y):
d_ops = _two_qubit_decompose(op)
decomp_ops.extend(d_ops)

# For special multi-qubit gates and ones constructed from matrix
# If we don't know how to decompose the operation
else:
try:
# Attempt decomposing the operation
md_ops = op.decomposition()
idx = 0 # might not be fast but at least is not recursive
while idx < len(md_ops):
md_op = md_ops[idx]
if md_op.name not in basis_set or not check_clifford_t(md_op):
# For the gates acting on one qubit
if len(md_op.wires) == 1:
if md_op.name in basis_set: # For known recipe
d_ops = _rot_decompose(md_op)
else: # Resort to decomposing manually
d_ops, g_op = _one_qubit_decompose(md_op)
gphase_ops.append(g_op)

# For the gates acting on two qubits
elif len(md_op.wires) == 2:
# Resort to decomposing manually
d_ops = _two_qubit_decompose(md_op)

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

# Expand the list and iterate over
del md_ops[idx]
md_ops[idx:idx] = d_ops
idx += 1

decomp_ops.extend(md_ops)

# If we don't know how to decompose the operation
except Exception as exc:
raise ValueError(
f"Cannot unroll {op} into the Clifford+T basis as no rule exists for its decomposition"
) from exc
raise ValueError(
f"Cannot unroll {op} into the Clifford+T basis as no rule exists for its decomposition"
)

# Merge RZ rotations together
merged_ops, number_ops = _merge_param_gates(decomp_ops, merge_ops=["RZ"])
Expand Down
59 changes: 48 additions & 11 deletions tests/transforms/test_cliffordt_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@
PI = math.pi


# pylint: disable=too-few-public-methods
class CustomOneQubitOperation(qml.operation.Operation):
num_wires = 1

@staticmethod
def compute_matrix():
return qml.math.conj(qml.math.transpose(qml.S.compute_matrix()))


# pylint: disable=too-few-public-methods
class CustomTwoQubitOperation(qml.operation.Operation):
num_wires = 2

@staticmethod
def compute_matrix():
return qml.math.conj(qml.math.transpose(qml.CNOT.compute_matrix()))


def circuit_1():
"""Circuit 1 with quantum chemistry gates"""
qml.RZ(1.0, wires=[0])
Expand Down Expand Up @@ -81,13 +99,6 @@ def circuit_5():
return qml.expval(qml.PauliZ(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:
"""Unit tests for clifford compilation function."""

Expand All @@ -111,7 +122,7 @@ def test_clifford_checker(self, op, res):

@pytest.mark.parametrize(
"circuit",
[circuit_1, circuit_2, circuit_3, circuit_4, circuit_5, circuit_6],
[circuit_1, circuit_2, circuit_3, circuit_4, circuit_5],
)
def test_decomposition(self, circuit):
"""Test decomposition for the Clifford transform."""
Expand Down Expand Up @@ -181,9 +192,7 @@ def test_total_error(self, epsilon, circuit):

@pytest.mark.parametrize(
"op",
[
qml.RY(qml.numpy.pi / 4, wires=0),
],
[CustomOneQubitOperation(wires=0)],
)
def test_zxz_rotation_decomposition(self, op):
"""Test single-qubit gates are decomposed correctly using ZXZ rotations"""
Expand All @@ -209,6 +218,34 @@ def circuit():
)
qml.math.isclose(res1, tape_fn([res2]), atol=1e-2)

@pytest.mark.parametrize(
"op",
[CustomTwoQubitOperation(wires=[0, 1])],
)
def test_su4_rotation_decomposition(self, op):
"""Test two-qubit gates are decomposed correctly using SU(4) 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)

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

0 comments on commit 93e9667

Please sign in to comment.