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 input arg control wires of MultiControlledX #6832

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions doc/development/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ for details on how to port your legacy code to the new system. The following fun
Completed deprecation cycles
----------------------------

* The input argument ``control_wires`` of ``MultiControlledX`` has been removed.

- Deprecated in v0.22
JerryChen97 marked this conversation as resolved.
Show resolved Hide resolved
- Removed in v0.41

* The ``QNode.get_best_method`` and ``QNode.best_method_str`` methods have been removed.
Instead, use the ``qml.workflow.get_best_diff_method`` function.

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

<h3>Breaking changes 💔</h3>

* The input argument `control_wires` of `MultiControlledX` has been removed.
[(#6832)](https://github.com/PennyLaneAI/pennylane/pull/6832)

* The ``QNode.get_best_method`` and ``QNode.best_method_str`` methods have been removed.
Instead, use the ``qml.workflow.get_best_diff_method`` function.
[(#6823)](https://github.com/PennyLaneAI/pennylane/pull/6823)
Expand Down
26 changes: 7 additions & 19 deletions pennylane/ops/op_math/controlled_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1157,12 +1157,10 @@ def _primitive_bind_call(cls, wires, control_values=None, work_wires=None, id=No
# pylint: disable=too-many-arguments
def __init__(
self,
control_wires: WiresLike = (),
wires: WiresLike = (),
control_values=None,
work_wires: WiresLike = (),
):
control_wires = Wires(() if control_wires is None else control_wires)
wires = Wires(() if wires is None else wires)
work_wires = Wires(() if work_wires is None else work_wires)

Expand All @@ -1173,27 +1171,17 @@ def __init__(
"supported in future releases, Use a list of booleans or integers instead.",
qml.PennyLaneDeprecationWarning,
)
if len(control_wires) > 0:
warnings.warn(
"The control_wires keyword for MultiControlledX is deprecated, and will "
"be removed soon. Use wires = (*control_wires, target_wire) instead.",
UserWarning,
)

if len(wires) == 0:
raise ValueError("Must specify the wires where the operation acts on")

if len(control_wires) > 0:
if len(wires) != 1:
raise ValueError("MultiControlledX accepts a single target wire.")
else:
if len(wires) < 2:
raise ValueError(
f"MultiControlledX: wrong number of wires. {len(wires)} wire(s) given. "
f"Need at least 2."
)
control_wires = wires[:-1]
wires = wires[-1:]
if len(wires) < 2:
raise ValueError(
f"MultiControlledX: wrong number of wires. {len(wires)} wire(s) given. "
f"Need at least 2."
)
control_wires = wires[:-1]
wires = wires[-1:]

control_values = _check_and_convert_control_values(control_values, control_wires)

Expand Down
90 changes: 0 additions & 90 deletions tests/ops/qubit/test_non_parametric_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,33 +631,6 @@ def test_invalid_arguments_to_init(self, wires, control_values, error_message):
with pytest.raises(ValueError, match=error_message):
_ = qml.MultiControlledX(wires=wires, control_values=control_values)

@pytest.mark.parametrize(
"control_wires, wires, control_values, error_message",
[
(
[0, 1],
[2],
[0, 1, 0],
"Length of control values must equal number of control wires.",
),
([0], None, [1], "Must specify the wires where the operation acts on"),
([0, 1], 2, [0, 1, 1], "Length of control values must equal number of control wires."),
([0, 1], [2, 3], [1, 0], "MultiControlledX accepts a single target wire."),
],
)
def test_invalid_arguments_to_init_old(
self, control_wires, wires, control_values, error_message
):
"""Tests initializing a MultiControlledX with invalid arguments with the old interface"""
with pytest.warns(
UserWarning,
match="The control_wires keyword for MultiControlledX is deprecated",
):
with pytest.raises(ValueError, match=error_message):
_ = qml.MultiControlledX(
control_wires=control_wires, wires=wires, control_values=control_values
)

@pytest.mark.parametrize(
"wires, control_values, error_message",
[
Expand All @@ -678,69 +651,6 @@ def test_invalid_str_control_values(self, wires, control_values, error_message):
with pytest.raises(ValueError, match=error_message):
_ = qml.MultiControlledX(wires=wires, control_values=control_values)

@pytest.mark.parametrize(
"control_wires,wires,control_values",
[
([0], 1, [0]),
([0, 1], 2, [0, 0]),
([0, 1], 2, [1, 0]),
([1, 0], 2, [1, 0]),
([0, 1], 2, [1, 1]),
([0, 2], 1, [1, 0]),
([1, 2, 0], 3, [1, 0, 0]),
([1, 0, 2, 4], 3, [1, 0, 0, 1]),
([0, 1, 2, 5, 3, 6], 4, [1, 0, 0, 0, 0, 1]),
],
)
def test_mixed_polarity_controls_old(self, control_wires, wires, control_values):
"""Test if MultiControlledX properly applies mixed-polarity
control values with old version of the arguments."""

target_wires = Wires(wires)
dev = qml.device("default.qubit", wires=len(control_wires + target_wires))

# Pick random starting state for the control and target qubits
control_state_weights = np.random.normal(size=2 ** (len(control_wires) + 1) - 2)
target_state_weights = np.random.normal(size=2 ** (len(target_wires) + 1) - 2)

@qml.qnode(dev)
def circuit_mpmct():
qml.templates.ArbitraryStatePreparation(control_state_weights, wires=control_wires)
qml.templates.ArbitraryStatePreparation(target_state_weights, wires=target_wires)

qml.MultiControlledX(
control_wires=control_wires, wires=target_wires, control_values=control_values
)
return qml.state()

# The result of applying the mixed-polarity gate should be the same as
# if we conjugated the specified control wires with Pauli X and applied the
# "regular" ControlledQubitUnitary in between.

x_locations = [x for x in range(len(control_values)) if control_values[x] == 0]

@qml.qnode(dev)
def circuit_pauli_x():
qml.templates.ArbitraryStatePreparation(control_state_weights, wires=control_wires)
qml.templates.ArbitraryStatePreparation(target_state_weights, wires=target_wires)

for wire in x_locations:
qml.PauliX(wires=control_wires[wire])

qml.ControlledQubitUnitary(X, control_wires=control_wires, wires=target_wires)

for wire in x_locations:
qml.PauliX(wires=control_wires[wire])

return qml.state()

with pytest.warns(UserWarning, match="deprecated"):
mpmct_state = circuit_mpmct()

pauli_x_state = circuit_pauli_x()

assert qml.math.allclose(mpmct_state, pauli_x_state)

def test_decomposition_not_enough_wires(self):
"""Test that the decomposition raises an error if the number of wires is lower than two"""
with pytest.raises(ValueError, match="Wrong number of wires"):
Expand Down
Loading