Repository: PennyLaneAI/pennylane
Pull request #2121 (2022-01-24 05:13:18)

Use a single wires keyword in MultiControlledX #1679
**Context:** The method MultiControlledX received two keywords for wires: _control_wires_ and wires for the _target_wire_. Which was unnecessary, confusing, and could be improved to just one keyword that received both the _control_wires_ and the _target_wire_. The method accepts both cases but gives a warning in the old case to start deprecation cycle. 

**Description of the Change:** The object initialization changed to receive just the keyword _wires_ of type _Wires_, a _sequence_ or an _int_. Also, the old version could be used with the keywords _control_wires_ and _wires_ but, it raises a UserWarning. There are more test cases to include the new and the old versions of the args in the tests "test_invalid_mixed_polarity_controls" and "test_mixed_polarity_controls"; The same adjustment to receive just the keyword wires in MultiControlledX was made in test "test_mixed_polarity_controls". The arrays _label_data_ and _control_data_ in the **test_non_parametric_ops.py** file and _PARAMETRIZED_OPERATIONS_ in the **test_parametric_ops.py** file were modified to add a second case with the new args for the MultiControlledX operation. Finally, the documentation of the MultiControlledX class was modified given the new args.  

**Benefits:** It is easier to use the gate MultiControlledX given a single set of wires. 


**Related GitHub Issues:** #1679 


codecov[bot]: # [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
> Merging [#2121](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (c8eb1c7) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/6d165f9ee83f41c34048fd93318b1a625353d89b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (6d165f9) will **decrease** coverage by `2.13%`.
> The diff coverage is `78.57%`.

[![Impacted file tree graph](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/graphs/tree.svg?width=650&height=150&src=pr&token=9S3YzlUgGk&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)

```diff
@@            Coverage Diff             @@
##           master    #2121      +/-   ##
==========================================
- Coverage   99.19%   97.05%   -2.14%     
==========================================
  Files         228      228              
  Lines       17476    17485       +9     
==========================================
- Hits        17335    16970     -365     
- Misses        141      515     +374     
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Coverage Δ | |
|---|---|---|
| [pennylane/ops/qubit/non\_parametric\_ops.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL29wcy9xdWJpdC9ub25fcGFyYW1ldHJpY19vcHMucHk=) | `96.62% <78.57%> (-0.62%)` | :arrow_down: |
| [pennylane/interfaces/batch/jax.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2ludGVyZmFjZXMvYmF0Y2gvamF4LnB5) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [pennylane/interfaces/jax.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2ludGVyZmFjZXMvamF4LnB5) | `0.00% <0.00%> (-97.44%)` | :arrow_down: |
| [pennylane/devices/default\_qubit\_jax.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2RldmljZXMvZGVmYXVsdF9xdWJpdF9qYXgucHk=) | `0.00% <0.00%> (-96.63%)` | :arrow_down: |
| [pennylane/qnn/cost.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL3Fubi9jb3N0LnB5) | `42.85% <0.00%> (-57.15%)` | :arrow_down: |
| [pennylane/transforms/classical\_jacobian.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL3RyYW5zZm9ybXMvY2xhc3NpY2FsX2phY29iaWFuLnB5) | `77.08% <0.00%> (-22.92%)` | :arrow_down: |
| [pennylane/math/utils.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL21hdGgvdXRpbHMucHk=) | `84.41% <0.00%> (-15.59%)` | :arrow_down: |
| [pennylane/math/multi\_dispatch.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL21hdGgvbXVsdGlfZGlzcGF0Y2gucHk=) | `87.73% <0.00%> (-12.27%)` | :arrow_down: |
| [pennylane/math/is\_independent.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL21hdGgvaXNfaW5kZXBlbmRlbnQucHk=) | `88.50% <0.00%> (-11.50%)` | :arrow_down: |
| [pennylane/collections/sum.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL2NvbGxlY3Rpb25zL3N1bS5weQ==) | `89.47% <0.00%> (-10.53%)` | :arrow_down: |
| ... and [13 more](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Last update [6d165f9...c8eb1c7](https://codecov.io/gh/PennyLaneAI/pennylane/pull/2121?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).

antalszava: Hi @mafemorris, thanks for the contribution! :slightly_smiling_face: We'll be reviewing the changes that you've made.
mafemorris: Hi @albi3ro , last week I made the changes you asked for, but I have had this error when running tests. I have not touched that test or something related to it, so maybe someone could help with what to do. 
![image](https://user-images.githubusercontent.com/55843194/151843024-5308d7de-4bc4-473b-99fe-3b1e7260d26e.png)

albi3ro: Does the test still fail for you on PennyLane master branch?

Could you post a full traceback (run pytest with -vvv) and the output of `import pennylane as qml; qml.about()`?
albi3ro: @mafemorris Inconveniently, black released a new version last week that changed the spacing around `**` from `a ** b` to `a**b`. Upgrading your version of black and running the most recent version on the `pennylane` folder and `tests` folder should fix the problem.

We are also releasing a new version of pennylane tomorrow, so the changelog entry might have gotten lost in merge conflicts when the development changelog was reset.

Little annoyances we sometimes have to deal with.
mafemorris: Hi @albi3ro  , I already fixed the black problem. On the other side, what you mean is to recover all the names that were before in the changelog?

Patch:
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 444b97d8d..afed6a8ec 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -26,6 +26,10 @@
 
 <h3>Breaking changes</h3>
 
+* The `MultiControlledX` operation now accepts a single `wires` keyword argument for both `control_wires` and `wires`.
+  The single `wires` keyword should be all the control wires followed by a single target wire. 
+  [(#2121)](https://github.com/PennyLaneAI/pennylane/pull/2121)
+
 <h3>Deprecations</h3>
 
 <h3>Bug fixes</h3>
@@ -44,4 +48,4 @@
 
 This release contains contributions from (in alphabetical order):
 
-Thomas Bromley, Anthony Hayes, Josh Izaac, David Wierichs
+Thomas Bromley, Anthony Hayes, Josh Izaac, Maria Fernanda Morris, David Wierichs
diff --git a/pennylane/ops/qubit/non_parametric_ops.py b/pennylane/ops/qubit/non_parametric_ops.py
index 385b7eba9..042cf5273 100644
--- a/pennylane/ops/qubit/non_parametric_ops.py
+++ b/pennylane/ops/qubit/non_parametric_ops.py
@@ -17,6 +17,7 @@ not depend on any parameters.
 """
 # pylint:disable=abstract-method,arguments-differ,protected-access
 import cmath
+import warnings
 import numpy as np
 from scipy.linalg import block_diag
 
@@ -877,13 +878,16 @@ class MultiControlledX(Operation):
     * Gradient recipe: None
 
     Args:
-        control_wires (Union[Wires, Sequence[int], or int]): the control wire(s)
-        wires (Union[Wires or int]): a single target wire the operation acts on
+        control_wires (Union[Wires, Sequence[int], or int]): Deprecated way to indicate the control wires.
+            Now users should use "wires" to indicate both the control wires and the target wire.
+        wires (Union[Wires, Sequence[int], or int]): control wire(s) followed by a single target wire where
+            the operation acts on
         control_values (str): a string of bits representing the state of the control
             qubits to control on (default is the all 1s state)
         work_wires (Union[Wires, Sequence[int], or int]): optional work wires used to decompose
             the operation into a series of Toffoli gates
 
+
     .. note::
 
         If ``MultiControlledX`` is not supported on the targeted device, PennyLane will decompose
@@ -907,17 +911,6 @@ class MultiControlledX(Operation):
         Note that the state of the work wires before and after the decomposition takes place is
         unchanged.
 
-    **Example**
-
-    The ``MultiControlledX`` operation (sometimes called a mixed-polarity
-    multi-controlled Toffoli) is a commonly-encountered case of the
-    :class:`~.pennylane.ControlledQubitUnitary` operation wherein the applied
-    unitary is the Pauli X (NOT) gate. It can be used in the same manner as
-    ``ControlledQubitUnitary``, but there is no need to specify a matrix
-    argument:
-
-    >>> qml.MultiControlledX(control_wires=[0, 1, 2, 3], wires=4, control_values='1110')
-
     """
     is_self_inverse = True
     num_wires = AnyWires
@@ -934,12 +927,29 @@ class MultiControlledX(Operation):
         work_wires=None,
         do_queue=True,
     ):
-        wires = Wires(wires)
-        control_wires = Wires(control_wires)
-        work_wires = Wires([]) if work_wires is None else Wires(work_wires)
+        if wires is None:
+            raise ValueError("Must specify the wires where the operation acts on")
+        if control_wires is None:
+            if len(wires) > 1:
+                control_wires = Wires(wires[:-1])
+                wires = Wires(wires[-1])
+            else:
+                raise ValueError(
+                    "MultiControlledX: wrong number of wires. 1 wire given. Need at least 2."
+                )
+        else:
+            wires = Wires(wires)
+            control_wires = Wires(control_wires)
+
+            warnings.warn(
+                "The control_wires keyword will be removed soon. Use wires = (control_wires,target_wire). See the documentation for more information.",
+                category=UserWarning,
+            )
+
+            if len(wires) != 1:
+                raise ValueError("MultiControlledX accepts a single target wire.")
 
-        if len(wires) != 1:
-            raise ValueError("MultiControlledX accepts a single target wire.")
+        work_wires = Wires([]) if work_wires is None else Wires(work_wires)
 
         if Wires.shared_wires([wires, work_wires]) or Wires.shared_wires(
             [control_wires, work_wires]
@@ -1096,23 +1106,19 @@ class MultiControlledX(Operation):
 
         gates = [
             MultiControlledX(
-                control_wires=first_part,
-                wires=work_wire,
+                wires=first_part + work_wire,
                 work_wires=second_part + target_wire,
             ),
             MultiControlledX(
-                control_wires=second_part + work_wire,
-                wires=target_wire,
+                wires=second_part + work_wire + target_wire,
                 work_wires=first_part,
             ),
             MultiControlledX(
-                control_wires=first_part,
-                wires=work_wire,
+                wires=first_part + work_wire,
                 work_wires=second_part + target_wire,
             ),
             MultiControlledX(
-                control_wires=second_part + work_wire,
-                wires=target_wire,
+                wires=second_part + work_wire + target_wire,
                 work_wires=first_part,
             ),
         ]


Test patch:
diff --git a/tests/ops/qubit/test_non_parametric_ops.py b/tests/ops/qubit/test_non_parametric_ops.py
index ebcbdc7f2..bea764a35 100644
--- a/tests/ops/qubit/test_non_parametric_ops.py
+++ b/tests/ops/qubit/test_non_parametric_ops.py
@@ -575,26 +575,58 @@ class TestMultiControlledX:
 
     X = np.array([[0, 1], [1, 0]])
 
+    @pytest.mark.parametrize(
+        "control_wires,wires,control_values,expected_warning_message",
+        [
+            ([0], 1, "0", "The control_wires keyword will be removed soon."),
+        ],
+    )
+    def test_warning_depractation_controlwires(
+        self, control_wires, wires, control_values, expected_warning_message
+    ):
+        target_wires = wires
+        with pytest.warns(UserWarning, match=expected_warning_message):
+            qml.MultiControlledX(
+                control_wires=control_wires, wires=target_wires, control_values=control_values
+            )
+
     @pytest.mark.parametrize(
         "control_wires,wires,control_values,expected_error_message",
         [
-            ([0, 1], 2, "ab", "String of control values can contain only '0' or '1'."),
-            ([0, 1], 2, "011", "Length of control bit string must equal number of control wires."),
-            ([0, 1], 2, [0, 1], "Alternative control values must be passed as a binary string."),
+            (None, None, "10", "Must specify the wires where the operation acts on"),
+            (None, [0, 1, 2], "ab", "String of control values can contain only '0' or '1'."),
             (
+                None,
+                [0, 1, 2],
+                "011",
+                "Length of control bit string must equal number of control wires.",
+            ),
+            (
+                None,
+                [0, 1, 2],
                 [0, 1],
-                [2, 3],
-                "10",
-                "MultiControlledX accepts a single target wire.",
+                "Alternative control values must be passed as a binary string.",
+            ),
+            (
+                None,
+                [1],
+                "1",
+                "MultiControlledX: wrong number of wires. 1 wire given. Need at least 2.",
             ),
+            ([0], None, "", "Must specify the wires where the operation acts on"),
+            ([0, 1], 2, "ab", "String of control values can contain only '0' or '1'."),
+            ([0, 1], 2, "011", "Length of control bit string must equal number of control wires."),
+            ([0, 1], 2, [0, 1], "Alternative control values must be passed as a binary string."),
+            ([0, 1], [2, 3], "10", "MultiControlledX accepts a single target wire."),
         ],
     )
+    @pytest.mark.filterwarnings("ignore:The control_wires keyword will be removed soon.")
     def test_invalid_mixed_polarity_controls(
         self, control_wires, wires, control_values, expected_error_message
     ):
         """Test if MultiControlledX properly handles invalid mixed-polarity
         control values."""
-        target_wires = Wires(wires)
+        target_wires = wires
 
         with pytest.raises(ValueError, match=expected_error_message):
             qml.MultiControlledX(
@@ -615,11 +647,12 @@ class TestMultiControlledX:
             ([0, 1, 2, 5, 3, 6], 4, "100001"),
         ],
     )
-    def test_mixed_polarity_controls(self, control_wires, wires, control_values):
+    @pytest.mark.filterwarnings("ignore:The control_wires keyword will be removed soon.")
+    def test_mixed_polarity_controls_old(self, control_wires, wires, control_values):
         """Test if MultiControlledX properly applies mixed-polarity
-        control values."""
-        target_wires = Wires(wires)
+        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
@@ -662,6 +695,67 @@ class TestMultiControlledX:
 
         assert np.allclose(mpmct_state, pauli_x_state)
 
+    @pytest.mark.parametrize(
+        "wires,control_values",
+        [
+            ([0, 1], "0"),
+            ([0, 1, 2], "00"),
+            ([0, 1, 2], "10"),
+            ([1, 0, 2], "10"),
+            ([0, 1, 2], "11"),
+            ([0, 2, 1], "10"),
+            ([1, 2, 0, 3], "100"),
+            ([1, 0, 2, 4, 3], "1001"),
+            ([0, 1, 2, 5, 3, 6, 4], "100001"),
+        ],
+    )
+    def test_mixed_polarity_controls(self, wires, control_values):
+        """Test if MultiControlledX properly applies mixed-polarity
+        control values."""
+
+        control_wires = Wires(wires[:-1])
+        target_wires = Wires(wires[-1])
+
+        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(wires=Wires(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()
+
+        mpmct_state = circuit_mpmct()
+        pauli_x_state = circuit_pauli_x()
+
+        assert np.allclose(mpmct_state, pauli_x_state)
+
     @pytest.mark.parametrize("n_ctrl_wires", range(3, 6))
     def test_decomposition_with_many_workers(self, n_ctrl_wires):
         """Test that the decomposed MultiControlledX gate performs the same unitary as the
@@ -682,7 +776,7 @@ class TestMultiControlledX:
         @qml.qnode(dev)
         def f(bitstring):
             qml.BasisState(bitstring, wires=range(n_ctrl_wires + 1))
-            qml.MultiControlledX(control_wires=control_wires, wires=target_wire).inv()
+            qml.MultiControlledX(wires=list(control_wires) + [target_wire]).inv()
             for op in tape.operations:
                 op.queue()
             return qml.probs(wires=range(n_ctrl_wires + 1))
@@ -715,7 +809,7 @@ class TestMultiControlledX:
         @qml.qnode(dev)
         def f(bitstring):
             qml.BasisState(bitstring, wires=range(n_ctrl_wires + 1))
-            qml.MultiControlledX(control_wires=control_wires, wires=target_wire).inv()
+            qml.MultiControlledX(wires=list(control_wires) + [target_wire]).inv()
             for op in tape.operations:
                 op.queue()
             return qml.probs(wires=range(n_ctrl_wires + 1))
@@ -728,9 +822,8 @@ class TestMultiControlledX:
     def test_not_enough_workers(self):
         """Test that a ValueError is raised when more than 2 control wires are to be decomposed with
         no work wires supplied"""
-        control_wires = range(3)
-        target_wire = 4
-        op = qml.MultiControlledX(control_wires=control_wires, wires=target_wire)
+        control_target_wires = range(4)
+        op = qml.MultiControlledX(wires=control_target_wires)
 
         match = (
             f"At least one work wire is required to decompose operation: {re.escape(op.__repr__())}"
@@ -740,15 +833,12 @@ class TestMultiControlledX:
 
     def test_not_unique_wires(self):
         """Test that a ValueError is raised when work_wires is not complementary to control_wires"""
-        control_wires = range(3)
-        target_wire = 4
+        control_target_wires = range(4)
         work_wires = range(2)
         with pytest.raises(
             ValueError, match="The work wires must be different from the control and target wires"
         ):
-            qml.MultiControlledX(
-                control_wires=control_wires, wires=target_wire, work_wires=work_wires
-            )
+            qml.MultiControlledX(wires=control_target_wires, work_wires=work_wires)
 
     @pytest.mark.parametrize("control_val", ["0", "1"])
     @pytest.mark.parametrize("n_ctrl_wires", range(1, 6))
@@ -757,8 +847,7 @@ class TestMultiControlledX:
         matrix-based version by checking if U^dagger U applies the identity to each basis
         state. This test focuses on varying the control values."""
         control_values = control_val * n_ctrl_wires
-        control_wires = range(n_ctrl_wires)
-        target_wire = n_ctrl_wires
+        control_target_wires = list(range(n_ctrl_wires)) + [n_ctrl_wires]
         work_wires = range(n_ctrl_wires + 1, 2 * n_ctrl_wires + 1)
 
         spy = mocker.spy(qml.MultiControlledX, "decomposition")
@@ -766,8 +855,7 @@ class TestMultiControlledX:
 
         with qml.tape.QuantumTape() as tape:
             qml.MultiControlledX(
-                control_wires=control_wires,
-                wires=target_wire,
+                wires=control_target_wires,
                 work_wires=work_wires,
                 control_values=control_values,
             )
@@ -777,9 +865,7 @@ class TestMultiControlledX:
         @qml.qnode(dev)
         def f(bitstring):
             qml.BasisState(bitstring, wires=range(n_ctrl_wires + 1))
-            qml.MultiControlledX(
-                control_wires=control_wires, wires=target_wire, control_values=control_values
-            ).inv()
+            qml.MultiControlledX(wires=control_target_wires, control_values=control_values).inv()
             for op in tape.operations:
                 op.queue()
             return qml.probs(wires=range(n_ctrl_wires + 1))
@@ -795,28 +881,25 @@ class TestMultiControlledX:
         matrix-based version by checking if U^dagger U applies the identity to each basis
         state. This test focuses on using custom wire labels."""
         n_ctrl_wires = 4
-        control_wires = [-1, "alice", 42, 3.14]
-        target_wire = ["bob"]
+        control_target_wires = [-1, "alice", 42, 3.14, "bob"]
         work_wires = ["charlie"]
-        all_wires = control_wires + target_wire + work_wires
+        all_wires = control_target_wires + work_wires
 
         spy = mocker.spy(qml.MultiControlledX, "decomposition")
         dev = qml.device("default.qubit", wires=all_wires)
 
         with qml.tape.QuantumTape() as tape:
-            qml.MultiControlledX(
-                control_wires=control_wires, wires=target_wire, work_wires=work_wires
-            )
+            qml.MultiControlledX(wires=control_target_wires, work_wires=work_wires)
         tape = tape.expand(depth=2)
         assert all(not isinstance(op, qml.MultiControlledX) for op in tape.operations)
 
         @qml.qnode(dev)
         def f(bitstring):
-            qml.BasisState(bitstring, wires=control_wires + target_wire)
-            qml.MultiControlledX(control_wires=control_wires, wires=target_wire).inv()
+            qml.BasisState(bitstring, wires=control_target_wires)
+            qml.MultiControlledX(wires=control_target_wires).inv()
             for op in tape.operations:
                 op.queue()
-            return qml.probs(wires=control_wires + target_wire)
+            return qml.probs(wires=control_target_wires)
 
         u = np.array(
             [f(np.array(b)) for b in itertools.product(range(2), repeat=n_ctrl_wires + 1)]
@@ -829,8 +912,7 @@ class TestMultiControlledX:
         them. To do this, a random state over all the qubits (control, target and workers) is
         loaded and U^dagger U(decomposed) is applied. If the workers are uncomputed, the output
         state will be the same as the input."""
-        control_wires = range(4)
-        target_wire = 4
+        control_target_wires = range(5)
         worker_wires = [5, 6]
         n_all_wires = 7
 
@@ -839,16 +921,14 @@ class TestMultiControlledX:
         dev = qml.device("default.qubit", wires=n_all_wires)
 
         with qml.tape.QuantumTape() as tape:
-            qml.MultiControlledX(
-                control_wires=control_wires, wires=target_wire, work_wires=worker_wires
-            )
+            qml.MultiControlledX(wires=control_target_wires, work_wires=worker_wires)
         tape = tape.expand(depth=1)
         assert all(not isinstance(op, qml.MultiControlledX) for op in tape.operations)
 
         @qml.qnode(dev)
         def f():
             qml.QubitStateVector(rnd_state, wires=range(n_all_wires))
-            qml.MultiControlledX(control_wires=control_wires, wires=target_wire).inv()
+            qml.MultiControlledX(wires=control_target_wires).inv()
             for op in tape.operations:
                 op.queue()
             return qml.state()
@@ -876,6 +956,7 @@ label_data = [
     (qml.CSWAP(wires=(0, 1, 2)), "SWAP", "SWAP"),
     (qml.Toffoli(wires=(0, 1, 2)), "X", "X"),
     (qml.MultiControlledX(control_wires=(0, 1, 2), wires=(3)), "X", "X"),
+    (qml.MultiControlledX(wires=(0, 1, 2, 3)), "X", "X"),
     (qml.Barrier(0), "||", "||"),
     (qml.WireCut(wires=0), "//", "//"),
 ]
@@ -907,6 +988,7 @@ control_data = [
     (qml.CSWAP(wires=(0, 1, 2)), Wires([0])),
     (qml.Toffoli(wires=(0, 1, 2)), Wires([0, 1])),
     (qml.MultiControlledX(control_wires=[0, 1, 2, 3], wires=4), Wires([0, 1, 2, 3])),
+    (qml.MultiControlledX(wires=[0, 1, 2, 3, 4]), Wires([0, 1, 2, 3])),
 ]
 
 
diff --git a/tests/ops/qubit/test_parametric_ops.py b/tests/ops/qubit/test_parametric_ops.py
index d3e8081c3..e35614a0e 100644
--- a/tests/ops/qubit/test_parametric_ops.py
+++ b/tests/ops/qubit/test_parametric_ops.py
@@ -64,6 +64,7 @@ PARAMETRIZED_OPERATIONS = [
     qml.DiagonalQubitUnitary(np.array([1.0, 1.0j]), wires=1),
     qml.ControlledQubitUnitary(np.eye(2) * 1j, wires=[0], control_wires=[2]),
     qml.MultiControlledX(control_wires=[0, 1], wires=2, control_values="01"),
+    qml.MultiControlledX(wires=[0, 1, 2], control_values="01"),
     qml.SingleExcitation(0.123, wires=[0, 3]),
     qml.SingleExcitationPlus(0.123, wires=[0, 3]),
     qml.SingleExcitationMinus(0.123, wires=[0, 3]),