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

Add support for multi-controlled zyz #6042

Merged
merged 24 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7c72ce2
multiple controlled, trainable special unitary decomp
albi3ro Jul 24, 2024
217fa96
Update ctrl_decomp_zyz
maliasadi Jul 25, 2024
568aec2
Update _multi_controlled_zyz
maliasadi Jul 25, 2024
7dc7523
Update tests
maliasadi Jul 25, 2024
bfaed33
Raise an error for len(work_wires) > 1
maliasadi Jul 25, 2024
bb9a257
Merge branch 'master' into multicontrolled-zyz
maliasadi Jul 26, 2024
8111ed8
Update format
maliasadi Jul 26, 2024
27432b7
Update changelog
maliasadi Jul 26, 2024
b6e5d01
Add tests with multiple working wires
maliasadi Jul 26, 2024
9fa9d70
Update changelog
maliasadi Jul 30, 2024
5e52210
Merge with master
maliasadi Jul 30, 2024
7f74a25
Update docs
maliasadi Aug 2, 2024
43c72d6
Merge with master
maliasadi Aug 2, 2024
5710549
Merge branch 'master' into multicontrolled-zyz
maliasadi Aug 2, 2024
e951938
Apply suggestions from code review
maliasadi Aug 8, 2024
a004948
Merge branch 'master' into multicontrolled-zyz
maliasadi Aug 8, 2024
1558bf4
Merge with master
maliasadi Aug 9, 2024
aff595d
Update support
maliasadi Aug 20, 2024
65ea9ad
Apply suggestions from code reviews
maliasadi Aug 20, 2024
4d8dfda
Update test_controlled_decompositions.py
maliasadi Aug 20, 2024
f145db6
Merge branch 'master' into multicontrolled-zyz
maliasadi Aug 20, 2024
575b457
Merge branch 'master' into multicontrolled-zyz
maliasadi Aug 21, 2024
1b2e67a
Merge branch 'master' into multicontrolled-zyz
maliasadi Aug 21, 2024
e8fe649
Merge branch 'master' into multicontrolled-zyz
maliasadi Aug 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,17 @@ coverage:
.PHONY:format
format:
ifdef check
isort --py 311 --profile black -l 100 -o autoray -p ./pennylane --skip __init__.py --filter-files ./pennylane ./tests --check
black -t py39 -t py310 -t py311 -l 100 ./pennylane ./tests --check
$(PYTHON) -m isort --py 311 --profile black -l 100 -o autoray -p ./pennylane --skip __init__.py --filter-files ./pennylane ./tests --check
$(PYTHON) -m black -t py39 -t py310 -t py311 -l 100 ./pennylane ./tests --check
else
isort --py 311 --profile black -l 100 -o autoray -p ./pennylane --skip __init__.py --filter-files ./pennylane ./tests
black -t py39 -t py310 -t py311 -l 100 ./pennylane ./tests
$(PYTHON) -m isort --py 311 --profile black -l 100 -o autoray -p ./pennylane --skip __init__.py --filter-files ./pennylane ./tests
$(PYTHON) -m black -t py39 -t py310 -t py311 -l 100 ./pennylane ./tests
endif

.PHONY: lint
lint:
pylint pennylane --rcfile .pylintrc
$(PYTHON) -m pylint pennylane --rcfile .pylintrc

.PHONY: lint-test
lint-test:
pylint tests pennylane/devices/tests --rcfile tests/.pylintrc
$(PYTHON) -m pylint tests pennylane/devices/tests --rcfile tests/.pylintrc
53 changes: 5 additions & 48 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,54 +37,8 @@

<h4>QChem improvements</h4>

* A new function `qml.registers` has been added, enabling the creation of registers, which are implemented as a dictionary of `Wires` instances.
[(#5957)](https://github.com/PennyLaneAI/pennylane/pull/5957)

* The `split_to_single_terms` transform is added. This transform splits expectation values of sums
into multiple single-term measurements on a single tape, providing better support for simulators
that can handle non-commuting observables but don't natively support multi-term observables.
[(#5884)](https://github.com/PennyLaneAI/pennylane/pull/5884)

* `SProd.terms` now flattens out the terms if the base is a multi-term observable.
[(#5885)](https://github.com/PennyLaneAI/pennylane/pull/5885)

* A new method `to_mat` has been added to the `FermiWord` and `FermiSentence` classes, which allows
computing the matrix representation of these Fermi operators.
[(#5920)](https://github.com/PennyLaneAI/pennylane/pull/5920)

* New functionality has been added to natively support exponential extrapolation when using the `mitigate_with_zne`. This allows
users to have more control over the error mitigation protocol without needing to add further dependencies.
[(#5972)](https://github.com/PennyLaneAI/pennylane/pull/5972)

<h3>Improvements 🛠</h3>

* Added the decomposition of zyz for special unitaries with multiple control wires.
[(#6042)](https://github.com/PennyLaneAI/pennylane/pull/6042)

* `qml.for_loop` can now be captured into plxpr.
[(#6041)](https://github.com/PennyLaneAI/pennylane/pull/6041)

* Removed `semantic_version` from the list of required packages in PennyLane.
[(#5836)](https://github.com/PennyLaneAI/pennylane/pull/5836)

* During experimental program capture, the qnode can now use closure variables.
[(#6052)](https://github.com/PennyLaneAI/pennylane/pull/6052)

* `GlobalPhase` now supports parameter broadcasting.
[(#5923)](https://github.com/PennyLaneAI/pennylane/pull/5923)

* `qml.devices.LegacyDeviceFacade` has been added to map the legacy devices to the new
device interface.
[(#5927)](https://github.com/PennyLaneAI/pennylane/pull/5927)

* Added the `compute_sparse_matrix` method for `qml.ops.qubit.BasisStateProjector`.
[(#5790)](https://github.com/PennyLaneAI/pennylane/pull/5790)

* `StateMP.process_state` defines rules in `cast_to_complex` for complex casting, avoiding a superfluous state vector copy in Lightning simulations
[(#5995)](https://github.com/PennyLaneAI/pennylane/pull/5995)

* Port the fast `apply_operation` implementation of `PauliZ` to `PhaseShift`, `S` and `T`.
[(#5876)](https://github.com/PennyLaneAI/pennylane/pull/5876)
* Molecules and Hamiltonians can now be constructed for all the elements present in the periodic table.
[(#5821)](https://github.com/PennyLaneAI/pennylane/pull/5821)

* `qml.UCCSD` now accepts an additional optional argument, `n_repeats`, which defines the number of
times the UCCSD template is repeated. This can improve the accuracy of the template by reducing
Expand Down Expand Up @@ -243,6 +197,9 @@

<h4>Other improvements</h4>

* Added the decomposition of zyz for special unitaries with multiple control wires.
[(#6042)](https://github.com/PennyLaneAI/pennylane/pull/6042)

* A new method `process_density_matrix` has been added to the `ProbabilityMP` and `DensityMatrixMP`
classes, allowing for more efficient handling of quantum density matrices, particularly with batch
processing support. This method simplifies the calculation of probabilities from quantum states
Expand Down
4 changes: 2 additions & 2 deletions pennylane/ops/op_math/controlled_decompositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def _multi_controlled_zyz(


def _single_control_zyz(rot_angles, global_phase, target_wire, control_wires: Wires):
# The decomposition of special zyz with multiple control wires
# The zyz decomposition of a general unitary with single control wire
# defined in Lemma 7.9 of https://arxiv.org/pdf/quant-ph/9503016

# Unpack the rotation angles
Expand Down Expand Up @@ -222,7 +222,7 @@ def ctrl_decomp_zyz(

This function decomposes both single and multiple controlled single-qubit
target operations using the decomposition defined in Lemma 4.3 and Lemma 5.1
for single `controlled_wires`, Lemma 7.9 for multiple `controlled_wires`
for single `controlled_wires`, and Lemma 7.9 for multiple `controlled_wires`
from `Barenco et al. (1995) <https://arxiv.org/abs/quant-ph/9503016>`_.

Args:
Expand Down
38 changes: 32 additions & 6 deletions tests/ops/op_math/test_controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -1050,17 +1050,35 @@ def test_non_differentiable_one_qubit_special_unitary(self):
decomp_mat = qml.matrix(op.decomposition, wire_order=op.wires)()
assert qml.math.allclose(op.matrix(), decomp_mat)

def test_differentiable_one_qubit_special_unitary(self):
"""Assert that a differentiable qubit special unitary uses the zyz decomposition."""
def test_differentiable_one_qubit_special_unitary_single_ctrl(self):
"""
Assert that a differentiable qubit special unitary uses the zyz decomposition with a single controlled wire.
"""

op = qml.ctrl(qml.RZ(qml.numpy.array(1.2), 0), (1, 2, 3, 4))
theta = 1.2
op = qml.ctrl(qml.RZ(qml.numpy.array(theta), 0), (1))
decomp = op.decomposition()

assert qml.equal(decomp[0], qml.CRZ(qml.numpy.array(1.2), [4, 0]))
qml.assert_equal(decomp[0], qml.PhaseShift(qml.numpy.array(theta / 2), 0))
qml.assert_equal(decomp[1], qml.CNOT(wires=(1, 0)))
qml.assert_equal(decomp[2], qml.PhaseShift(qml.numpy.array(-theta / 2), 0))
qml.assert_equal(decomp[3], qml.CNOT(wires=(1, 0)))

decomp_mat = qml.matrix(op.decomposition, wire_order=op.wires)()
assert qml.math.allclose(op.matrix(), decomp_mat)

def test_differentiable_one_qubit_special_unitary_multiple_ctrl(self):
"""Assert that a differentiable qubit special unitary uses the zyz decomposition with multiple controlled wires."""

theta = 1.2
op = qml.ctrl(qml.RZ(qml.numpy.array(theta), 0), (1, 2, 3, 4))
decomp = op.decomposition()

assert qml.equal(decomp[0], qml.CRZ(qml.numpy.array(theta), [4, 0]))
assert qml.equal(decomp[1], qml.MultiControlledX(wires=[1, 2, 3, 0]))
assert qml.equal(decomp[2], qml.CRZ(qml.numpy.array(-0.6), wires=[4, 0]))
assert qml.equal(decomp[2], qml.CRZ(qml.numpy.array(-theta / 2), wires=[4, 0]))
assert qml.equal(decomp[3], qml.MultiControlledX(wires=[1, 2, 3, 0]))
assert qml.equal(decomp[4], qml.CRZ(qml.numpy.array(-0.6), wires=[4, 0]))
assert qml.equal(decomp[4], qml.CRZ(qml.numpy.array(-theta / 2), wires=[4, 0]))

decomp_mat = qml.matrix(op.decomposition, wire_order=op.wires)()
assert qml.math.allclose(op.matrix(), decomp_mat)
Expand Down Expand Up @@ -1152,6 +1170,14 @@ def test_decomposition_undefined(self):
with pytest.raises(DecompositionUndefinedError):
op.decomposition()

def test_global_phase_decomp_raises_warning(self):
"""Test that ctrl(GlobalPhase).decomposition() raises a warning with more than one control."""
op = qml.ctrl(qml.GlobalPhase(1.23), control=[0, 1])
with pytest.warns(
UserWarning, match="Controlled-GlobalPhase currently decomposes to nothing"
):
assert op.decomposition() == []

def test_control_on_zero(self):
"""Test decomposition applies PauliX gates to flip any control-on-zero wires."""

Expand Down
7 changes: 2 additions & 5 deletions tests/ops/op_math/test_controlled_decompositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,6 @@ def test_invalid_op_error(self):
qml.RY(0.123, wires=0),
qml.RZ(0.123, wires=0),
qml.Rot(0.123, 0.456, 0.789, wires=0),
]

special_unitary_ops = [
qml.Hadamard(0),
qml.PauliZ(0),
qml.S(0),
Expand All @@ -114,7 +111,7 @@ def test_invalid_op_error(self):
qml.DiagonalQubitUnitary(np.array([1, -1]), wires=0),
]

@pytest.mark.parametrize("op", su2_ops + special_unitary_ops + general_unitary_ops)
@pytest.mark.parametrize("op", su2_ops + general_unitary_ops)
@pytest.mark.parametrize("control_wires", ([1], [2], [3]))
def test_decomposition_circuit_general_ops(self, op, control_wires, tol):
"""Tests that the controlled decomposition of a single-qubit operation
Expand Down Expand Up @@ -223,7 +220,7 @@ def test_correct_decomp(self):
qml.assert_equal(decomp_op, expected_op)
assert len(decomps) == 7

@pytest.mark.parametrize("op", su2_ops + special_unitary_ops + general_unitary_ops)
@pytest.mark.parametrize("op", su2_ops + general_unitary_ops)
@pytest.mark.parametrize("control_wires", ([1], [2], [3]))
def test_decomp_queues_correctly(self, op, control_wires, tol):
"""Test that any incorrect operations aren't queued when using
Expand Down
Loading