Skip to content

Commit

Permalink
add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
obliviateandsurrender committed Oct 11, 2023
1 parent b51cf18 commit 5334132
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
the helper functions needed to compute it.
"""

from .cliffordt_transform import clifford_t_decomposition, check_clifford_t
from .cliffordt_transform import clifford_t_decomposition
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
qml.ISWAP,
]

_PARAMETER_GATES = [qml.RX, qml.RY, qml.RZ, qml.Rot, qml.GlobalPhase]
_PARAMETER_GATES = [qml.RX, qml.RY, qml.RZ, qml.Rot, qml.PhaseShift, qml.GlobalPhase]

_CLIFFORD_T_GATES = _CLIFFORD_T_ONE_GATES + _CLIFFORD_T_TWO_GATES

Expand Down Expand Up @@ -164,11 +164,11 @@ def _rot_decompose(op):
ops_ = _rot_decompose(op.base.adjoint())
elif isinstance(op, qml.RX):
ops_ = _simplify_param(theta, qml.PauliX(wires=wires))
if ops_ is None:
if ops_ is None: # Use Rx = H @ Rz @ H
ops_ = [qml.Hadamard(wires), qml.RZ(theta, wires), qml.Hadamard(wires)]
elif isinstance(op, qml.RY):
ops_ = _simplify_param(theta, qml.PauliY(wires=wires))
if ops_ is None:
if ops_ is None: # Use Ry = S @ H @ Rz @ H @ S.dag
ops_ = [
qml.S(wires),
qml.Hadamard(wires),
Expand All @@ -180,6 +180,13 @@ def _rot_decompose(op):
ops_ = _simplify_param(theta, qml.PauliZ(wires=wires))
if ops_ is None:
ops_ = [qml.RZ(theta, wires)]
elif isinstance(op, qml.PhaseShift):
ops_ = _simplify_param(theta, qml.PauliZ(wires=wires))
if ops_ is None:
ops_ = [qml.RZ(theta, wires), qml.GlobalPhase(theta / 2)]
else:
ops_.append(qml.GlobalPhase(-theta / 2))

else:
raise ValueError(
f"Operation {op} is not a valid Pauli rotation: qml.RX, qml.RY, qml.RZ and qml.Rot"
Expand Down Expand Up @@ -262,14 +269,15 @@ def _merge_pauli_rotations(operations, merge_ops=None):

# pylint: disable= too-many-nested-blocks, too-many-branches, too-many-statements, unnecessary-lambda-assignment
@transform
def clifford_t_decomposition(tape: QuantumTape, epsilon=1e-8) -> (Sequence[QuantumTape], Callable):
def clifford_t_decomposition(
tape: QuantumTape, epsilon=1e-8, max_depth=6
) -> (Sequence[QuantumTape], Callable):
r"""Unrolls the tape into Clifford+T basis"""

# Build the basis set and the pipeline for intial 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]
pipelines = [remove_barrier, commute_controlled, cancel_inverses, merge_rotations]

max_depth = 6 # can be tweaked
expanded_tape = tape.expand(depth=max_depth, stop_at=lambda op: op.name in basis_set)

for transf in pipelines:
Expand All @@ -287,8 +295,8 @@ def clifford_t_decomposition(tape: QuantumTape, epsilon=1e-8) -> (Sequence[Quant
gphase_ops.append(op)

# Check whether the operation is a Clifford or a T-gate
elif check_clifford_t(op) and len(op.parameters) < 2:
if len(op.parameters):
elif op.name in basis_set and check_clifford_t(op):
if op.num_params:
decomp_ops.extend(_rot_decompose(op))
else:
decomp_ops.append(op)
Expand Down
69 changes: 63 additions & 6 deletions tests/transforms/test_clifford_t/test_cliffordt_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,25 @@
from pennylane.transforms.decompositions.clifford_plus_t.cliffordt_transform import (
check_clifford_t,
clifford_t_decomposition,
_rot_decompose,
_one_qubit_decompose,
_two_qubit_decompose,
_CLIFFORD_T_GATES,
)

from pennylane.transforms.optimization.optimization_utils import _fuse_global_phases

_CLIFFORD_PHASE_GATES = _CLIFFORD_T_GATES + [qml.GlobalPhase]
_SKIP_GATES = [qml.Barrier, qml.Snapshot, qml.WireCut, qml.GlobalPhase]
_CLIFFORD_PHASE_GATES = _CLIFFORD_T_GATES + _SKIP_GATES


def circuit_1():
"""Circuit 1 with quantum chemistry gates"""
qml.RX(1.0, wires=[0])
qml.RZ(1.0, wires=[0])
qml.PhaseShift(1.0, wires=[1])
qml.SingleExcitation(2.0, wires=[1, 2])
qml.DoubleExcitation(2.0, wires=[1, 2, 3, 4])
qml.Snapshot()
return qml.expval(qml.PauliZ(0))


Expand Down Expand Up @@ -95,15 +98,18 @@ def test_clifford_checker(self, op, res):
"""Test Clifford checker operation for gate"""
assert check_clifford_t(op) == res

@pytest.mark.parametrize(("circuit"), [circuit_1, circuit_2, circuit_3, circuit_4, circuit_5])
def test_decomposition(self, circuit):
@pytest.mark.parametrize(
("circuit, max_depth"),
[(circuit_1, 1), (circuit_2, 2), (circuit_3, 3), (circuit_4, 4), (circuit_5, 5)],
)
def test_decomposition(self, circuit, max_depth):
"""Test decomposition for the Clifford transform."""

with qml.tape.QuantumTape() as tape:
circuit()

[tape], _ = clifford_t_decomposition(tape)

[tape], _ = clifford_t_decomposition(tape, max_depth=max_depth)
print(tape.operations)
assert all(
any(
(
Expand Down Expand Up @@ -189,3 +195,54 @@ def test_two_qubit_decomposition(self, op):
where=matrix_op != 0,
)[qml.math.nonzero(qml.math.round(matrix_op, 10))]
assert qml.math.allclose(phase / phase[0], qml.math.ones(qml.math.shape(phase)[0]))

@pytest.mark.parametrize(
("op"),
[
qml.adjoint(qml.RX(1.0, wires=["b"])),
qml.Rot(1, 2, 3, wires=[2]),
],
)
def test_rot_decomposition(self, op):
"""Test decomposition for the Clifford transform."""

decomp_ops = _fuse_global_phases(_rot_decompose(op))

assert all(
any(
(
isinstance(op, gate) or isinstance(getattr(op, "base", None), gate)
for gate in _CLIFFORD_PHASE_GATES + [qml.RZ]
)
)
for op in decomp_ops
)

decomp_ops, global_ops = decomp_ops[:-1], decomp_ops[-1]
matrix_op = reduce(
lambda x, y: x @ y, [qml.matrix(op) for op in decomp_ops][::-1]
) * qml.matrix(global_ops)

# check for matrice equivalence up to global phase
phase = qml.math.divide(
matrix_op,
qml.matrix(op),
out=qml.math.zeros_like(matrix_op, dtype=complex),
where=matrix_op != 0,
)[qml.math.nonzero(qml.math.round(matrix_op, 10))]
assert qml.math.allclose(phase / phase[0], qml.math.ones(qml.math.shape(phase)[0]))

@pytest.mark.parametrize(
("op"),
[
qml.U1(1.0, wires=["b"]),
],
)
def test_raise_with_rot_decomposition(self, op):
"""Test that exception is correctly raise when caclulating expectation values of multiple Hamiltonians"""

with pytest.raises(
ValueError,
match="qml.RX, qml.RY, qml.RZ and qml.Rot",
):
_fuse_global_phases(_rot_decompose(op))

0 comments on commit 5334132

Please sign in to comment.