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

Adds global phase to the PhaseShift decomposition #4657

Merged
merged 12 commits into from
Dec 13, 2023
2 changes: 1 addition & 1 deletion pennylane/ops/qubit/parametric_ops_single_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ def compute_decomposition(phi, wires):
[RZ(1.234, wires=[0])]

"""
return [RZ(phi, wires=wires)]
return [RZ(phi, wires=wires), qml.GlobalPhase(phi / 2)]

def adjoint(self):
return PhaseShift(-self.data[0], wires=self.wires)
Expand Down
2 changes: 1 addition & 1 deletion pennylane/transforms/optimization/optimization_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def fuse_rot_angles(angles_1, angles_2):


def _fuse_global_phases(operations):
obliviateandsurrender marked this conversation as resolved.
Show resolved Hide resolved
"""Fuse all the global phase operations into single one
"""Fuse all the global phase operations into single one.

Args:
operations (list[Operation]): list of operations to be iterated over
Expand Down
11 changes: 9 additions & 2 deletions tests/ops/qubit/test_parametric_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def test_phase_decomposition(self, phi, tol):
op = qml.PhaseShift(phi, wires=0)
res = op.decomposition()

assert len(res) == 1
assert len(res) == 2

assert res[0].name == "RZ"

Expand All @@ -273,6 +273,10 @@ def test_phase_decomposition(self, phi, tol):

decomposed_matrix = res[0].matrix()
global_phase = np.exp(-1j * phi / 2)[..., np.newaxis, np.newaxis]

assert res[1].name == "GlobalPhase"
assert np.allclose(qml.matrix(res[1]), np.exp(-1j * phi / 2))

assert np.allclose(decomposed_matrix, global_phase * op.matrix(), atol=tol, rtol=0)

def test_phase_decomposition_broadcasted(self, tol):
Expand All @@ -281,7 +285,7 @@ def test_phase_decomposition_broadcasted(self, tol):
op = qml.PhaseShift(phi, wires=0)
res = op.decomposition()

assert len(res) == 1
assert len(res) == 2

assert res[0].name == "RZ"

Expand All @@ -291,6 +295,9 @@ def test_phase_decomposition_broadcasted(self, tol):
decomposed_matrix = res[0].matrix()
global_phase = np.exp(-1j * phi / 2)[..., np.newaxis, np.newaxis]

assert res[1].name == "GlobalPhase"
assert np.allclose(qml.matrix(res[1]), np.exp(-1j * phi / 2))

assert np.allclose(decomposed_matrix, global_phase * op.matrix(), atol=tol, rtol=0)

def test_Rot_decomposition(self):
Expand Down
32 changes: 25 additions & 7 deletions tests/transforms/test_batch_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,11 @@ def my_transform(self, tape):
spy_expand.assert_called()

input_tape = spy_transform.call_args[0][1]
assert len(input_tape.operations) == 1
assert len(input_tape.operations) == 2
assert input_tape.operations[0].name == "RZ"
assert input_tape.operations[1].name == "GlobalPhase"
assert input_tape.operations[0].parameters == [0.5]
assert input_tape.operations[1].parameters == [0.25]

@pytest.mark.parametrize("perform_expansion", [True, False])
def test_expand_fn_with_kwarg(self, mocker, perform_expansion):
Expand Down Expand Up @@ -249,9 +251,17 @@ def my_transform(self, tape, **kwargs):
spy_expand.assert_called() # The expand_fn of transform_fn always is called

input_tape = spy_transform.call_args[0][1]
assert len(input_tape.operations) == 1
assert input_tape.operations[0].name == ("RZ" if perform_expansion else "PhaseShift")
assert input_tape.operations[0].parameters == [0.5]

if perform_expansion:
assert len(input_tape.operations) == 2
assert input_tape.operations[0].name == "RZ"
assert input_tape.operations[0].parameters == [0.5]
assert input_tape.operations[1].name == "GlobalPhase"
assert input_tape.operations[1].parameters == [0.25]
else:
assert len(input_tape.operations) == 1
assert input_tape.operations[0].name == "PhaseShift"
assert input_tape.operations[0].parameters == [0.5]

@pytest.mark.parametrize("perform_expansion", [True, False])
def test_expand_qnode_with_kwarg(self, mocker, perform_expansion):
Expand Down Expand Up @@ -287,9 +297,17 @@ def qnode(x):
spy_transform.assert_called()
spy_expand.assert_called() # The expand_fn of transform_fn always is called
input_tape = spy_transform.call_args[0][1]
assert len(input_tape.operations) == 1
assert input_tape.operations[0].name == ("RZ" if perform_expansion else "PhaseShift")
assert input_tape.operations[0].parameters == [0.5]

if perform_expansion:
assert len(input_tape.operations) == 2
assert input_tape.operations[0].name == "RZ"
assert input_tape.operations[0].parameters == [0.5]
assert input_tape.operations[1].name == "GlobalPhase"
assert input_tape.operations[1].parameters == [0.25]
else:
assert len(input_tape.operations) == 1
assert input_tape.operations[0].name == "PhaseShift"
assert input_tape.operations[0].parameters == [0.5]

def test_parametrized_transform_tape(self):
"""Test that a parametrized transform can be applied
Expand Down
8 changes: 6 additions & 2 deletions tests/transforms/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
merge_rotations,
single_qubit_fusion,
)
from pennylane.transforms.optimization.optimization_utils import _fuse_global_phases


def build_qfunc(wires):
Expand Down Expand Up @@ -250,7 +251,7 @@ def test_compile_decompose_into_basis_gates(self, wires):

pipeline = [partial(commute_controlled, direction="left"), cancel_inverses, merge_rotations]

basis_set = ["CNOT", "RX", "RY", "RZ"]
basis_set = ["CNOT", "RX", "RY", "RZ", "GlobalPhase"]

transformed_qfunc = compile(qfunc, pipeline=pipeline, basis_set=basis_set)
transformed_qnode = qml.QNode(transformed_qfunc, dev)
Expand All @@ -273,6 +274,7 @@ def test_compile_decompose_into_basis_gates(self, wires):
"CNOT",
"RY",
"CNOT",
"GlobalPhase",
]

wires_expected = [
Expand All @@ -289,9 +291,11 @@ def test_compile_decompose_into_basis_gates(self, wires):
Wires([wires[1], wires[2]]),
Wires(wires[2]),
Wires([wires[1], wires[2]]),
Wires([]),
]

compare_operation_lists(transformed_qnode.qtape.operations, names_expected, wires_expected)
tansformed_ops = _fuse_global_phases(transformed_qnode.qtape.operations)
compare_operation_lists(tansformed_ops, names_expected, wires_expected)

def test_compile_template(self):
"""Test that functions with templates are correctly expanded and compiled."""
Expand Down
15 changes: 9 additions & 6 deletions tests/transforms/test_tape_expand.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,10 @@ def generator(self):
tape = qml.tape.QuantumScript.from_queue(q)
new_tape = qml.transforms.expand_nonunitary_gen(tape)
assert tape.operations[:2] == new_tape.operations[:2]
exp_op = new_tape.operations[2]
exp_op, gph_op = new_tape.operations[2:4]
assert exp_op.name == "RZ" and exp_op.data == (2.1,) and exp_op.wires == qml.wires.Wires(1)
assert tape.operations[3:] == new_tape.operations[3:]
assert gph_op.name == "GlobalPhase" and gph_op.data == (2.1 * 0.5,)
assert tape.operations[3:] == new_tape.operations[4:]

def test_expand_nonunitary_generator(self):
"""Test that a tape with single-parameter operations with
Expand All @@ -246,9 +247,10 @@ def test_expand_nonunitary_generator(self):
new_tape = qml.transforms.expand_nonunitary_gen(tape)

assert tape.operations[:2] == new_tape.operations[:2]
exp_op = new_tape.operations[2]
exp_op, gph_op = new_tape.operations[2:4]
assert exp_op.name == "RZ" and exp_op.data == (2.1,) and exp_op.wires == qml.wires.Wires(1)
assert tape.operations[3:] == new_tape.operations[3:]
assert gph_op.name == "GlobalPhase" and gph_op.data == (2.1 * 0.5,)
assert tape.operations[3:] == new_tape.operations[4:]

def test_decompose_all_nonunitary_generator(self):
"""Test that decompositions actually only contain unitarily
Expand Down Expand Up @@ -332,8 +334,9 @@ class NonDiffPhaseShift(qml.PhaseShift):

assert new_tape.operations[0].name == "RZ"
assert new_tape.operations[0].grad_method == "A"
assert new_tape.operations[1].name == "RY"
assert new_tape.operations[2].name == "CNOT"
assert new_tape.operations[1].name == "GlobalPhase"
assert new_tape.operations[2].name == "RY"
assert new_tape.operations[3].name == "CNOT"

def test_nontrainable_nondiff(self, mocker):
"""Test that a circuit with non-differentiable
Expand Down
Loading