From 482c8179719b629f2e1a2692ab5a322e482bbaa8 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sat, 9 Jan 2021 09:16:20 -0800 Subject: [PATCH 1/3] Make MCX a C3X or C4X if MCXGrayCode and 3 or 4 controls --- qiskit/circuit/library/standard_gates/x.py | 23 +++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index d2a479094f61..0a85dad6046d 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -728,19 +728,23 @@ def __array__(self, dtype=None): class MCXGate(ControlledGate): """The general, multi-controlled X gate.""" - def __new__(cls, num_ctrl_qubits=None, label=None, ctrl_state=None): + def __new__(cls, num_ctrl_qubits=None, label=None, ctrl_state=None, _name=None): """Create a new MCX instance. - Depending on the number of controls, this creates an explicit CX, CCX, C3X or C4X - instance or a generic MCX gate. + Depending on the number of controls and which mode of the MCX, this creates an + explicit CX, CCX, C3X or C4X instance or a generic MCX gate. """ - # these gates will always be implemented for all modes of the MCX if the number of control - # qubits matches this + # The CXGate and CCXGate will be implemented for all modes of the MCX, and + # the C3XGate and C4XGate will be implemented if an MCXGrayCode, if the number of + # control qubits matches this explicit = { 1: CXGate, - 2: CCXGate + 2: CCXGate, + 3: C3XGate, + 4: C4XGate } - if num_ctrl_qubits in explicit.keys(): + if num_ctrl_qubits in explicit.keys() and (num_ctrl_qubits < 3 or + _name == 'mcx_gray'): gate_class = explicit[num_ctrl_qubits] gate = gate_class.__new__(gate_class, label=label, ctrl_state=ctrl_state) # if __new__ does not return the same type as cls, init is not called @@ -815,6 +819,11 @@ class MCXGrayCode(MCXGate): This delegates the implementation to the MCU1 gate, since :math:`X = H \cdot U1(\pi) \cdot H`. """ + def __new__(cls, num_ctrl_qubits=None, label=None, ctrl_state=None, _name='mcx_gray'): + """Create a new MCXGrayCode instance.""" + return super().__new__(cls, num_ctrl_qubits=num_ctrl_qubits, label=label, + ctrl_state=ctrl_state, _name=_name) + def __init__(self, num_ctrl_qubits, label=None, ctrl_state=None): super().__init__(num_ctrl_qubits, label=label, ctrl_state=ctrl_state, _name='mcx_gray') From 57fd674d35130605243838825bc1f676a75dd3c8 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sat, 9 Jan 2021 10:19:42 -0800 Subject: [PATCH 2/3] Update test --- qiskit/circuit/library/standard_gates/x.py | 2 +- test/python/circuit/test_controlled_gate.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 0a85dad6046d..79ae2c62e093 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -734,7 +734,7 @@ def __new__(cls, num_ctrl_qubits=None, label=None, ctrl_state=None, _name=None): Depending on the number of controls and which mode of the MCX, this creates an explicit CX, CCX, C3X or C4X instance or a generic MCX gate. """ - # The CXGate and CCXGate will be implemented for all modes of the MCX, and + # The CXGate and CCXGate will be implemented for all modes of the MCX, and # the C3XGate and C4XGate will be implemented if an MCXGrayCode, if the number of # control qubits matches this explicit = { diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index f7aa5616f352..11de882aadfb 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -606,6 +606,14 @@ def test_mcx_gates_yield_explicit_gates(self, num_ctrl_qubits): explicit = {1: CXGate, 2: CCXGate} self.assertEqual(cls, explicit[num_ctrl_qubits]) + @data(1, 2, 3, 4) + def test_mcxgraycode_gates_yield_explicit_gates(self, num_ctrl_qubits): + """Test creating an mcx gate calls MCXGrayCode and yeilds explicit definition.""" + qc = QuantumCircuit(num_ctrl_qubits+1) + qc.mcx(list(range(num_ctrl_qubits)), [num_ctrl_qubits]) + explicit = {1: CXGate, 2: CCXGate, 3: C3XGate, 4: C4XGate} + self.assertEqual(type(qc[0][0]), explicit[num_ctrl_qubits]) + @data(3, 4, 5, 8) def test_mcx_gates(self, num_ctrl_qubits): """Test the mcx gates.""" From 9ec06d77049f498c4136ca26296b57e5f7333e4a Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sun, 10 Jan 2021 16:13:44 -0800 Subject: [PATCH 3/3] Place all explicit in MCXGrayCode --- qiskit/circuit/library/standard_gates/x.py | 34 ++++++++++++------- ...ate_explicit_c3x_c4x-d4475c0bb70fae49.yaml | 8 +++++ 2 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 releasenotes/notes/mcx_create_explicit_c3x_c4x-d4475c0bb70fae49.yaml diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 79ae2c62e093..3861384704bc 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -728,23 +728,19 @@ def __array__(self, dtype=None): class MCXGate(ControlledGate): """The general, multi-controlled X gate.""" - def __new__(cls, num_ctrl_qubits=None, label=None, ctrl_state=None, _name=None): + def __new__(cls, num_ctrl_qubits=None, label=None, ctrl_state=None): """Create a new MCX instance. Depending on the number of controls and which mode of the MCX, this creates an explicit CX, CCX, C3X or C4X instance or a generic MCX gate. """ # The CXGate and CCXGate will be implemented for all modes of the MCX, and - # the C3XGate and C4XGate will be implemented if an MCXGrayCode, if the number of - # control qubits matches this + # the C3XGate and C4XGate will be implemented in the MCXGrayCode class. explicit = { 1: CXGate, - 2: CCXGate, - 3: C3XGate, - 4: C4XGate + 2: CCXGate } - if num_ctrl_qubits in explicit.keys() and (num_ctrl_qubits < 3 or - _name == 'mcx_gray'): + if num_ctrl_qubits in explicit.keys(): gate_class = explicit[num_ctrl_qubits] gate = gate_class.__new__(gate_class, label=label, ctrl_state=ctrl_state) # if __new__ does not return the same type as cls, init is not called @@ -818,11 +814,23 @@ class MCXGrayCode(MCXGate): This delegates the implementation to the MCU1 gate, since :math:`X = H \cdot U1(\pi) \cdot H`. """ - - def __new__(cls, num_ctrl_qubits=None, label=None, ctrl_state=None, _name='mcx_gray'): - """Create a new MCXGrayCode instance.""" - return super().__new__(cls, num_ctrl_qubits=num_ctrl_qubits, label=label, - ctrl_state=ctrl_state, _name=_name) + def __new__(cls, num_ctrl_qubits=None, label=None, ctrl_state=None): + """Create a new MCXGrayCode instance + """ + # if 1 to 4 control qubits, create explicit gates + explicit = { + 1: CXGate, + 2: CCXGate, + 3: C3XGate, + 4: C4XGate + } + if num_ctrl_qubits in explicit.keys(): + gate_class = explicit[num_ctrl_qubits] + gate = gate_class.__new__(gate_class, label=label, ctrl_state=ctrl_state) + # if __new__ does not return the same type as cls, init is not called + gate.__init__(label=label, ctrl_state=ctrl_state) + return gate + return super().__new__(cls) def __init__(self, num_ctrl_qubits, label=None, ctrl_state=None): super().__init__(num_ctrl_qubits, label=label, ctrl_state=ctrl_state, _name='mcx_gray') diff --git a/releasenotes/notes/mcx_create_explicit_c3x_c4x-d4475c0bb70fae49.yaml b/releasenotes/notes/mcx_create_explicit_c3x_c4x-d4475c0bb70fae49.yaml new file mode 100644 index 000000000000..a5c1440678c4 --- /dev/null +++ b/releasenotes/notes/mcx_create_explicit_c3x_c4x-d4475c0bb70fae49.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + The class :class:`~qiskit.library.standard_gates.x.MCXGrayCode` will now create + a ``C3XGate`` if ``num_ctrl_qubits`` is 3 and a ``C4XGate`` if ``num_ctrl_qubits`` + is 4. This is in addition to the previous functionality where for any of the + modes of the :class:'qiskit.library.standard_gates.x.MCXGate`, if ``num_ctrl_bits`` + is 1, a ``CXGate`` is created, and if 2, a ``CCXGate`` is created.