Skip to content

Commit 9297eac

Browse files
authored
Better synthesis for multi-controlled U1Gate (#14061)
* improve the synthesis of MCU1Gate * update the synthesis of synth_mcx_gray_code * better bounds for multi-controlled U1Gate in the tests * add release notes * fix qasm strings for mcx_gray
1 parent bc10f8e commit 9297eac

6 files changed

Lines changed: 22 additions & 22 deletions

File tree

qiskit/circuit/library/standard_gates/u1.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -408,24 +408,16 @@ def __init__(
408408

409409
def _define(self):
410410
# pylint: disable=cyclic-import
411-
from qiskit.circuit import QuantumCircuit, QuantumRegister
412-
413-
q = QuantumRegister(self.num_qubits, "q")
414-
qc = QuantumCircuit(q, name=self.name)
415-
416411
if self.num_ctrl_qubits == 0:
417412
definition = U1Gate(self.params[0]).definition
418-
if self.num_ctrl_qubits == 1:
413+
elif self.num_ctrl_qubits == 1:
419414
definition = CU1Gate(self.params[0]).definition
420415
else:
421-
from .u3 import _gray_code_chain
416+
from .p import MCPhaseGate
422417

423-
scaled_lam = self.params[0] / (2 ** (self.num_ctrl_qubits - 1))
424-
bottom_gate = CU1Gate(scaled_lam)
425-
definition = _gray_code_chain(q, self.num_ctrl_qubits, bottom_gate)
426-
for instr, qargs, cargs in definition:
427-
qc._append(instr, qargs, cargs)
428-
self.definition = qc
418+
definition = MCPhaseGate(self.params[0], self.num_ctrl_qubits).definition
419+
420+
self.definition = definition
429421

430422
def control(
431423
self,

qiskit/synthesis/multi_controlled/mcx_synthesis.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from qiskit.circuit.quantumcircuit import QuantumCircuit
2020
from qiskit.circuit.library.standard_gates import (
2121
HGate,
22-
MCU1Gate,
2322
CU1Gate,
2423
RC3XGate,
2524
C3SXGate,
@@ -252,11 +251,17 @@ def synth_mcx_gray_code(num_ctrl_qubits: int) -> QuantumCircuit:
252251
Returns:
253252
The synthesized quantum circuit.
254253
"""
254+
from qiskit.circuit.library.standard_gates.u3 import _gray_code_chain
255+
255256
num_qubits = num_ctrl_qubits + 1
256257
q = QuantumRegister(num_qubits, name="q")
257258
qc = QuantumCircuit(q, name="mcx_gray")
258259
qc._append(HGate(), [q[-1]], [])
259-
qc._append(MCU1Gate(np.pi, num_ctrl_qubits=num_ctrl_qubits), q[:], [])
260+
scaled_lam = np.pi / (2 ** (num_ctrl_qubits - 1))
261+
bottom_gate = CU1Gate(scaled_lam)
262+
definition = _gray_code_chain(q, num_ctrl_qubits, bottom_gate)
263+
for instr, qargs, cargs in definition:
264+
qc._append(instr, qargs, cargs)
260265
qc._append(HGate(), [q[-1]], [])
261266
return qc
262267

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
features_circuits:
3+
- |
4+
Improve the synthesis of a multi-controlled :class:`.U1Gate`,
5+
so that it will not grow exponentially with the number of controls.

test/python/circuit/test_circuit_qasm.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,7 @@ def test_circuit_qasm_with_mcx_gate_variants(self):
412412
# param0 for "gate mcuq(param0) is not used inside the definition
413413
expected_qasm = f"""OPENQASM 2.0;
414414
include "qelib1.inc";
415-
gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }}
416-
gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; }}
415+
gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; h q5; }}
417416
gate mcx_vchain q0,q1,q2,q3,q4 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }}
418417
gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }}
419418
gate mcx_vchain_{mcx_vchain_id} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }}

test/python/qasm2/test_export.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,7 @@ def test_mcx_gate_variants(self):
402402
# param0 for "gate mcuq(param0) is not used inside the definition
403403
expected_qasm = f"""OPENQASM 2.0;
404404
include "qelib1.inc";
405-
gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }}
406-
gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; }}
405+
gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; h q5; }}
407406
gate mcx_vchain q0,q1,q2,q3,q4 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }}
408407
gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }}
409408
gate mcx_vchain_{mcx_vchain_id} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }}

test/python/synthesis/test_multi_controlled_synthesis.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,9 @@ def test_small_mc_gates_cx_count(self, num_ctrl_qubits, base_gate):
359359
if isinstance(base_gate, (XGate, YGate, ZGate, HGate)):
360360
# MCX gate and other locally equivalent multi-controlled gates
361361
expected = {1: 1, 2: 6, 3: 14, 4: 36, 5: 84, 6: 140, 7: 220, 8: 324}
362-
elif isinstance(base_gate, (PhaseGate, SGate, SdgGate, TGate, TdgGate, SXGate, SXdgGate)):
362+
elif isinstance(
363+
base_gate, (PhaseGate, SGate, SdgGate, TGate, TdgGate, SXGate, SXdgGate, U1Gate)
364+
):
363365
# MCPhase gate and other locally equivalent multi-controlled gates
364366
expected = {1: 2, 2: 6, 3: 20, 4: 44, 5: 84, 6: 140, 7: 220, 8: 324}
365367
elif isinstance(base_gate, RZGate):
@@ -368,8 +370,6 @@ def test_small_mc_gates_cx_count(self, num_ctrl_qubits, base_gate):
368370
expected = {1: 2, 2: 8, 3: 20, 4: 24, 5: 40, 6: 56, 7: 80, 8: 104}
369371
elif isinstance(base_gate, (UGate, U2Gate, U3Gate)):
370372
expected = {1: 2, 2: 22, 3: 54, 4: 92, 5: 164, 6: 252, 7: 380, 8: 532}
371-
elif isinstance(base_gate, U1Gate):
372-
expected = {1: 2, 2: 8, 3: 20, 4: 44, 5: 92, 6: 188, 7: 380, 8: 764}
373373
else:
374374
raise NotImplementedError
375375

0 commit comments

Comments
 (0)