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

Adding MCX synthesis plugins #12961

Merged
merged 42 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d3e882c
moving high-level-synthesis plugins to a separate file
alexanderivrii Aug 12, 2024
a64597a
Adding the remaining MCX synthesis functions and exposting all of the…
alexanderivrii Aug 12, 2024
e548257
adding entry points for MCX plugins
alexanderivrii Aug 12, 2024
dccd30f
adding documentation section for MCX plugins
alexanderivrii Aug 13, 2024
d5458ce
renaming file
alexanderivrii Aug 13, 2024
014b8a2
Adding pending deprecation warnings
alexanderivrii Aug 13, 2024
cab6cb5
placeholder for MCX plugin tests
alexanderivrii Aug 13, 2024
a79e2f9
adding flag pending=True to deprecate
alexanderivrii Aug 13, 2024
364cf75
changing checks from isinstance to name-based: a CCCX gate is called …
alexanderivrii Aug 13, 2024
bc4238c
merging main
alexanderivrii Aug 14, 2024
fa94424
futher exposing C3X and C4X synthesis
alexanderivrii Aug 14, 2024
306361f
updating MCX synthesis functions to avoid returning C3X and C4X gates
alexanderivrii Aug 15, 2024
e54706b
fix compose to append
alexanderivrii Aug 15, 2024
c3c1927
renaming synthesized circuits for c3x and for c4x back to 'mcx' to av…
alexanderivrii Aug 15, 2024
b21f3ea
test qasm fixes
alexanderivrii Aug 15, 2024
f0f3de9
randomly spotted typo
alexanderivrii Aug 15, 2024
01d76b2
fixing how QuantumCircuit.decompose works in the presence of gates_to…
alexanderivrii Aug 15, 2024
d739065
updating MCX plugins to check isinstance
alexanderivrii Aug 15, 2024
d856c88
fixing test
alexanderivrii Aug 15, 2024
08051f3
pylint fixes
alexanderivrii Aug 15, 2024
d73d941
properly fixing test
alexanderivrii Aug 15, 2024
73d4502
additional tests
alexanderivrii Aug 16, 2024
4135344
adding new synthesis functions to synthesis docs
alexanderivrii Aug 16, 2024
efb55c2
release notes
alexanderivrii Aug 16, 2024
b6702c5
docstrings improvements followin review
alexanderivrii Aug 16, 2024
247d414
Adding refernce to Vale et al paper for the MCXPhase gate implementation
alexanderivrii Aug 18, 2024
458c10d
fixes to deprecation warnings and adding deprecation for get_num_anci…
alexanderivrii Aug 18, 2024
055e365
docstring fixes
alexanderivrii Aug 18, 2024
6bb46d5
renaming mcphase to v24
alexanderivrii Aug 20, 2024
e5cd0b8
removing unncessary checks
alexanderivrii Aug 20, 2024
d6226b9
addressing the rest of review comments
alexanderivrii Aug 20, 2024
9278d26
and of course updating qasm checking after we've slightly changed the…
alexanderivrii Aug 20, 2024
3879cdd
yet another renaming
alexanderivrii Aug 20, 2024
1c05061
Update qiskit/circuit/library/standard_gates/x.py
alexanderivrii Aug 20, 2024
40228f0
Update qiskit/circuit/library/standard_gates/x.py
alexanderivrii Aug 20, 2024
0649bc9
Update releasenotes/notes/add-mcx-plugins-85e5b248692a36db.yaml
alexanderivrii Aug 20, 2024
5a8ba64
release notes
alexanderivrii Aug 20, 2024
5422990
formatting
alexanderivrii Aug 20, 2024
e0765ec
fixing docs
alexanderivrii Aug 21, 2024
5f14493
Merge branch 'main' into mcx-plugins
alexanderivrii Aug 21, 2024
82586cb
removing references from the first sentence of plugin descriptions
alexanderivrii Aug 22, 2024
c0746ec
Merge branch 'mcx-plugins' of github.com:alexanderivrii/qiskit-terra …
alexanderivrii Aug 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,29 @@ aqc = "qiskit.transpiler.passes.synthesis.aqc_plugin:AQCSynthesisPlugin"
sk = "qiskit.transpiler.passes.synthesis.solovay_kitaev_synthesis:SolovayKitaevSynthesis"

[project.entry-points."qiskit.synthesis"]
"clifford.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:DefaultSynthesisClifford"
"clifford.ag" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:AGSynthesisClifford"
"clifford.bm" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BMSynthesisClifford"
"clifford.greedy" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:GreedySynthesisClifford"
"clifford.layers" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:LayerSynthesisClifford"
"clifford.lnn" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:LayerLnnSynthesisClifford"
"linear_function.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:DefaultSynthesisLinearFunction"
"linear_function.kms" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisLinearFunction"
"linear_function.pmh" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:PMHSynthesisLinearFunction"
"permutation.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation"
"permutation.kms" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisPermutation"
"permutation.basic" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation"
"permutation.acg" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:ACGSynthesisPermutation"
"qft.full" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisFull"
"qft.line" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisLine"
"qft.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisFull"
"permutation.token_swapper" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:TokenSwapperSynthesisPermutation"
"clifford.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:DefaultSynthesisClifford"
"clifford.ag" = "qiskit.transpiler.passes.synthesis.hls_plugins:AGSynthesisClifford"
"clifford.bm" = "qiskit.transpiler.passes.synthesis.hls_plugins:BMSynthesisClifford"
"clifford.greedy" = "qiskit.transpiler.passes.synthesis.hls_plugins:GreedySynthesisClifford"
"clifford.layers" = "qiskit.transpiler.passes.synthesis.hls_plugins:LayerSynthesisClifford"
"clifford.lnn" = "qiskit.transpiler.passes.synthesis.hls_plugins:LayerLnnSynthesisClifford"
"linear_function.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:DefaultSynthesisLinearFunction"
"linear_function.kms" = "qiskit.transpiler.passes.synthesis.hls_plugins:KMSSynthesisLinearFunction"
"linear_function.pmh" = "qiskit.transpiler.passes.synthesis.hls_plugins:PMHSynthesisLinearFunction"
"mcx.n_dirty_i15" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisNDirtyI15"
"mcx.n_clean_m15" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisNCleanM15"
"mcx.1_clean_b95" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesis1CleanB95"
"mcx.gray_code" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisGrayCode"
"mcx.noaux_v24" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisNoAuxV24"
"mcx.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisDefault"
"permutation.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:BasicSynthesisPermutation"
"permutation.kms" = "qiskit.transpiler.passes.synthesis.hls_plugins:KMSSynthesisPermutation"
"permutation.basic" = "qiskit.transpiler.passes.synthesis.hls_plugins:BasicSynthesisPermutation"
"permutation.acg" = "qiskit.transpiler.passes.synthesis.hls_plugins:ACGSynthesisPermutation"
"qft.full" = "qiskit.transpiler.passes.synthesis.hls_plugins:QFTSynthesisFull"
"qft.line" = "qiskit.transpiler.passes.synthesis.hls_plugins:QFTSynthesisLine"
"qft.default" = "qiskit.transpiler.passes.synthesis.hls_plugins:QFTSynthesisFull"
"permutation.token_swapper" = "qiskit.transpiler.passes.synthesis.hls_plugins:TokenSwapperSynthesisPermutation"

[project.entry-points."qiskit.transpiler.init"]
default = "qiskit.transpiler.preset_passmanagers.builtin_plugins:DefaultInitPassManager"
Expand Down
77 changes: 53 additions & 24 deletions qiskit/circuit/library/standard_gates/x.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit._utils import _ctrl_state_to_int, with_gate_array, with_controlled_gate_array
from qiskit._accelerate.circuit import StandardGate
from qiskit.utils.deprecation import deprecate_func

_X_ARRAY = [[0, 1], [1, 0]]
_SX_ARRAY = [[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]]
Expand Down Expand Up @@ -1168,6 +1169,19 @@ def inverse(self, annotated: bool = False):
return MCXGate(num_ctrl_qubits=self.num_ctrl_qubits, ctrl_state=self.ctrl_state)

@staticmethod
@deprecate_func(
additional_msg=(
"For an MCXGate it is no longer possible to know the number of ancilla qubits "
"that would be eventually used by the transpiler when the gate is created. "
"Instead, it is recommended to use MCXGate and let HighLevelSynthesis choose "
"the best synthesis method depending on the number of ancilla qubits available. "
"However, if a specific synthesis method using a specific number of ancilla "
"qubits is require, one can create a custom gate by calling the corresponding "
"synthesis function directly."
),
since="1.3",
pending=True,
)
def get_num_ancilla_qubits(num_ctrl_qubits: int, mode: str = "noancilla") -> int:
"""Get the number of required ancilla qubits without instantiating the class.

Expand All @@ -1185,23 +1199,10 @@ def get_num_ancilla_qubits(num_ctrl_qubits: int, mode: str = "noancilla") -> int
def _define(self):
"""This definition is based on MCPhaseGate implementation."""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from qiskit.synthesis.multi_controlled import synth_mcx_noaux_v24

q = QuantumRegister(self.num_qubits, name="q")
qc = QuantumCircuit(q)
if self.num_qubits == 4:
qc._append(C3XGate(), q[:], [])
self.definition = qc
elif self.num_qubits == 5:
qc._append(C4XGate(), q[:], [])
self.definition = qc
else:
q_controls = list(range(self.num_ctrl_qubits))
q_target = self.num_ctrl_qubits
qc.h(q_target)
qc.mcp(numpy.pi, q_controls, q_target)
qc.h(q_target)
self.definition = qc
qc = synth_mcx_noaux_v24(self.num_ctrl_qubits)
self.definition = qc

@property
def num_ancilla_qubits(self):
Expand Down Expand Up @@ -1280,6 +1281,17 @@ def __new__(
return gate
return super().__new__(cls)

@deprecate_func(
additional_msg=(
"It is recommended to use MCXGate and let HighLevelSynthesis choose "
"the best synthesis method depending on the number of ancilla qubits available. "
"If this specific synthesis method is required, one can specify it using the "
"high-level-synthesis plugin `gray_code` for MCX gates, or, alternatively, "
"one can use synth_mcx_gray_code to construct the gate directly."
),
since="1.3",
pending=True,
)
def __init__(
self,
num_ctrl_qubits: int,
Expand All @@ -1305,15 +1317,9 @@ def inverse(self, annotated: bool = False):
def _define(self):
"""Define the MCX gate using the Gray code."""
# pylint: disable=cyclic-import
from qiskit.circuit.quantumcircuit import QuantumCircuit
from .u1 import MCU1Gate
from .h import HGate
from qiskit.synthesis.multi_controlled import synth_mcx_gray_code

q = QuantumRegister(self.num_qubits, name="q")
qc = QuantumCircuit(q, name=self.name)
qc._append(HGate(), [q[-1]], [])
qc._append(MCU1Gate(numpy.pi, num_ctrl_qubits=self.num_ctrl_qubits), q[:], [])
qc._append(HGate(), [q[-1]], [])
qc = synth_mcx_gray_code(self.num_ctrl_qubits)
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved
self.definition = qc


Expand All @@ -1330,6 +1336,17 @@ class MCXRecursive(MCXGate):
2. Iten et al., 2015. https://arxiv.org/abs/1501.06911
"""

@deprecate_func(
additional_msg=(
"It is recommended to use MCXGate and let HighLevelSynthesis choose "
"the best synthesis method depending on the number of ancilla qubits available. "
"If this specific synthesis method is required, one can specify it using the "
"high-level-synthesis plugin '1_clean_b95' for MCX gates, or, alternatively, "
"one can use synth_mcx_1_clean to construct the gate directly."
),
since="1.3",
pending=True,
)
def __init__(
self,
num_ctrl_qubits: int,
Expand Down Expand Up @@ -1409,6 +1426,18 @@ def __new__(
unit=unit,
)

@deprecate_func(
additional_msg=(
"It is recommended to use MCXGate and let HighLevelSynthesis choose "
"the best synthesis method depending on the number of ancilla qubits available. "
"If this specific synthesis method is required, one can specify it using the "
"high-level-synthesis plugins `n_clean_m15` (using clean ancillas) or "
"`n_dirty_i15` (using dirty ancillas) for MCX gates. Alternatively, one can "
"use synth_mcx_n_dirty_i15 and synth_mcx_n_clean_m15 to construct the gate directly."
),
since="1.3",
pending=True,
)
def __init__(
self,
num_ctrl_qubits: int,
Expand Down
9 changes: 8 additions & 1 deletion qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3212,10 +3212,17 @@ def decompose(
from qiskit.converters.dag_to_circuit import dag_to_circuit

dag = circuit_to_dag(self, copy_operations=True)
dag = HighLevelSynthesis().run(dag)

if gates_to_decompose is None:
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
# We should not rewrite the circuit using HLS when we have gates_to_decompose,
# or else HLS will rewrite all objects with available plugins (e.g., Cliffords,
# PermutationGates, and now also MCXGates)
dag = HighLevelSynthesis().run(dag)

pass_ = Decompose(gates_to_decompose)
for _ in range(reps):
dag = pass_.run(dag)

# do not copy operations, this is done in the conversion with circuit_to_dag
return dag_to_circuit(dag, copy_operations=False)

Expand Down
10 changes: 9 additions & 1 deletion qiskit/synthesis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@
.. autofunction:: synth_mcx_n_dirty_i15
.. autofunction:: synth_mcx_n_clean_m15
.. autofunction:: synth_mcx_1_clean_b95
.. autofunction:: synth_mcx_noaux_v24
.. autofunction:: synth_mcx_gray_code
.. autofunction:: synth_c3x
.. autofunction:: synth_c4x

"""

Expand Down Expand Up @@ -180,8 +184,12 @@
two_qubit_cnot_decompose,
TwoQubitWeylDecomposition,
)
from .multi_controlled.mcx_with_ancillas_synth import (
from .multi_controlled import (
synth_mcx_n_dirty_i15,
synth_mcx_n_clean_m15,
synth_mcx_1_clean_b95,
synth_mcx_noaux_v24,
synth_mcx_gray_code,
synth_c3x,
synth_c4x,
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved
)
6 changes: 5 additions & 1 deletion qiskit/synthesis/multi_controlled/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@

"""Module containing multi-controlled circuits synthesis"""

from .mcx_with_ancillas_synth import (
from .mcx_synthesis import (
synth_mcx_n_dirty_i15,
synth_mcx_n_clean_m15,
synth_mcx_1_clean_b95,
synth_mcx_gray_code,
synth_mcx_noaux_v24,
synth_c3x,
synth_c4x,
)
Loading
Loading