Skip to content

Commit

Permalink
Remove string support for control_values of MutliControlledX (#6835)
Browse files Browse the repository at this point in the history
**Context:**
In PL0.36 we deprecated the string type support for argument
`control_values` of the operator `MultiControlledX` initialization, e.g.
`control_values='01'` shall not be allowed anymore. In this PR we would
like to remove this entirely with a strict type check.

**Description of the Change:**
- Added a type check with `isinstance` to raise `ValueError` if the
`control_values` does not follow the designed pattern.
- Added a type hint at correpsonding position within the init func
signature
 - Removed a test that presumes the validity of str input
 - Alter the deprecation check into error check

**Benefits:**
Less redundancy

**Possible Drawbacks:**
Potential existence of uncovered indirect usage of string input in
`MultiControlledX`

**Related GitHub Issues:**
[sc-81527]
  • Loading branch information
JerryChen97 authored Jan 17, 2025
1 parent d7490d4 commit c2869dd
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 37 deletions.
10 changes: 5 additions & 5 deletions doc/development/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ Pending deprecations

- Deprecated in v0.36

* ``MultiControlledX`` is the only controlled operation that still supports specifying control
values with a bit string. In the future, it will no longer accepts strings as control values.

- Deprecated in v0.36

Completed removal of legacy operator arithmetic
-----------------------------------------------

Expand Down Expand Up @@ -58,6 +53,11 @@ for details on how to port your legacy code to the new system. The following fun
Completed deprecation cycles
----------------------------

* ``MultiControlledX`` no longer accepts strings as control values.

- Deprecated in v0.36
- Removed in v0.41

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

- Deprecated in v0.22
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 @@ -46,6 +46,9 @@

<h3>Breaking changes 💔</h3>

* `MultiControlledX` no longer accepts strings as control values.
[(#6835)](https://github.com/PennyLaneAI/pennylane/pull/6835)

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

Expand Down
25 changes: 17 additions & 8 deletions pennylane/ops/op_math/controlled_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import warnings
from collections.abc import Iterable
from functools import lru_cache
from typing import List, Union

import numpy as np
from scipy.linalg import block_diag
Expand Down Expand Up @@ -1154,23 +1155,31 @@ def _primitive_bind_call(cls, wires, control_values=None, work_wires=None, id=No
*wires, n_wires=len(wires), control_values=control_values, work_wires=work_wires
)

@staticmethod
def _validate_control_values(control_values):
if control_values is not None:
if not (
isinstance(control_values, (bool, int))
or (
(
isinstance(control_values, (list, tuple))
and all(isinstance(val, (bool, int)) for val in control_values)
)
)
):
raise ValueError(f"control_values must be boolean or int. Got: {control_values}")

# pylint: disable=too-many-arguments
def __init__(
self,
wires: WiresLike = (),
control_values=None,
control_values: Union[bool, List[bool], int, List[int]] = None,
work_wires: WiresLike = (),
):
wires = Wires(() if wires is None else wires)
work_wires = Wires(() if work_wires is None else work_wires)

# First raise deprecation warnings regardless of the validity of other arguments
if isinstance(control_values, str):
warnings.warn(
"Specifying control values using a bitstring is deprecated, and will not be "
"supported in future releases, Use a list of booleans or integers instead.",
qml.PennyLaneDeprecationWarning,
)
self._validate_control_values(control_values)

if len(wires) == 0:
raise ValueError("Must specify the wires where the operation acts on")
Expand Down
28 changes: 4 additions & 24 deletions tests/ops/qubit/test_non_parametric_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -606,11 +606,11 @@ class TestMultiControlledX:

X = np.array([[0, 1], [1, 0]])

def test_str_control_values_deprecation(self):
def test_str_control_values_error(self):
"""Tests that control_values specified with a bit string is deprecated."""
with pytest.warns(
qml.PennyLaneDeprecationWarning,
match="Specifying control values using a bitstring is deprecated",
with pytest.raises(
ValueError,
match="control_values must be boolean or int",
):
_ = qml.MultiControlledX(wires=[0, 1, 2], control_values="01")

Expand All @@ -631,26 +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(
"wires, control_values, error_message",
[
([0, 1, 2], "ab", "String of control values can contain only '0' or '1'."),
(
[0, 1, 2],
"011",
"Length of control values must equal number of control wires.",
),
],
)
def test_invalid_str_control_values(self, wires, control_values, error_message):
"""Tests control_values specified with invalid strings"""
with pytest.warns(
qml.PennyLaneDeprecationWarning,
match="Specifying control values using a bitstring is deprecated",
):
with pytest.raises(ValueError, match=error_message):
_ = qml.MultiControlledX(wires=wires, control_values=control_values)

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

0 comments on commit c2869dd

Please sign in to comment.