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 21 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.mcphase" = "qiskit.transpiler.passes.synthesis.hls_plugins:MCXSynthesisMCPhase"
"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
63 changes: 39 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 @@ -1185,23 +1186,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_mcphase

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_mcphase(self.num_ctrl_qubits)
self.definition = qc

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

@deprecate_func(
additional_msg=(
"It is recommended to use :class:`.MCXGate` and let :class:`.HighLevelSynthesis` choose "
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
"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 plugin "
"interface. Alternatively, one can use :func:`.synth_mcx_gray_code` to construct "
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
"the gate directly."
),
since="1.3",
pending=True,
)
def __init__(
self,
num_ctrl_qubits: int,
Expand All @@ -1305,15 +1304,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 +1323,17 @@ class MCXRecursive(MCXGate):
2. Iten et al., 2015. https://arxiv.org/abs/1501.06911
"""

@deprecate_func(
additional_msg=(
"It is recommended to use :class:`.MCXGate` and let :class:`.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 plugin "
"interface. Alternatively, one can use :func:`.synth_mcx_1_clean_b95` to construct "
"the gate directly."
),
since="1.3",
pending=True,
)
def __init__(
self,
num_ctrl_qubits: int,
Expand Down Expand Up @@ -1409,6 +1413,17 @@ def __new__(
unit=unit,
)

@deprecate_func(
additional_msg=(
"It is recommended to use :class:`.MCXGate` and let :class:`.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 plugin "
"interface. Alternatively, one can use :func:`.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
6 changes: 5 additions & 1 deletion qiskit/synthesis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,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_mcphase,
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved
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_mcphase,
synth_c3x,
synth_c4x,
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,28 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Module containing multi-controlled circuits synthesis with ancillary qubits."""
"""Module containing multi-controlled circuits synthesis with and without ancillary qubits."""

from math import ceil
import numpy as np

from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit.quantumcircuit import QuantumCircuit
from qiskit.circuit.library.standard_gates.x import C3XGate, C4XGate
from qiskit.circuit.library.standard_gates import (
HGate,
MCU1Gate,
CU1Gate,
RC3XGate,
C3SXGate,
)


def synth_mcx_n_dirty_i15(
num_ctrl_qubits: int,
relative_phase: bool = False,
action_only: bool = False,
):
"""
) -> QuantumCircuit:
r"""
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved
Synthesize a multi-controlled X gate with :math:`k` controls using :math:`k - 2`
dirty ancillary qubits producing a circuit with :math:`2 * k - 1` qubits and at most
:math:`8 * k - 6` CX gates, by Iten et. al. [1].
Expand Down Expand Up @@ -59,7 +67,8 @@ def synth_mcx_n_dirty_i15(
qc.ccx(q_controls[0], q_controls[1], q_target)
return qc
elif not relative_phase and num_ctrl_qubits == 3:
qc._append(C3XGate(), [*q_controls, q_target], [])
circuit = synth_c3x()
qc.append(circuit, [*q_controls, q_target])
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
return qc

num_ancillas = num_ctrl_qubits - 2
Expand Down Expand Up @@ -122,8 +131,8 @@ def synth_mcx_n_dirty_i15(
return qc


def synth_mcx_n_clean_m15(num_ctrl_qubits: int):
"""
def synth_mcx_n_clean_m15(num_ctrl_qubits: int) -> QuantumCircuit:
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved
r"""
Synthesize a multi-controlled X gate with :math:`k` controls using :math:`k - 2`
clean ancillary qubits with producing a circuit with :math:`2 * k - 1` qubits
and at most :math:`6 * k - 6` CX gates, by Maslov [1].
Expand Down Expand Up @@ -165,8 +174,8 @@ def synth_mcx_n_clean_m15(num_ctrl_qubits: int):
return qc


def synth_mcx_1_clean_b95(num_ctrl_qubits: int):
"""
def synth_mcx_1_clean_b95(num_ctrl_qubits: int) -> QuantumCircuit:
r"""
Synthesize a multi-controlled X gate with :math:`k` controls using a single
clean ancillary qubit producing a circuit with :math:`k + 2` qubits and at most
:math:`16 * k - 8` CX gates, by Barenco et al. [1].
Expand All @@ -183,16 +192,10 @@ def synth_mcx_1_clean_b95(num_ctrl_qubits: int):
"""

if num_ctrl_qubits == 3:
q = QuantumRegister(4, name="q")
qc = QuantumCircuit(q, name="mcx")
qc._append(C3XGate(), q[:], [])
return qc
return synth_c3x()

elif num_ctrl_qubits == 4:
q = QuantumRegister(5, name="q")
qc = QuantumCircuit(q, name="mcx")
qc._append(C4XGate(), q[:], [])
return qc
return synth_c4x()

num_qubits = num_ctrl_qubits + 2
q = QuantumRegister(num_qubits, name="q")
Expand Down Expand Up @@ -230,3 +233,113 @@ def synth_mcx_1_clean_b95(num_ctrl_qubits: int):
)

return qc


def synth_mcx_gray_code(num_ctrl_qubits: int) -> QuantumCircuit:
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved
r"""
Synthesize a multi-controlled X gate with :math:`k` controls using the Gray code.

Produces a quantum circuit with :math:`num_ctrl_qubits + 1` qubits.
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved

Args:
num_ctrl_qubits: The number of control qubits.

Returns:
The synthesized quantum circuit.
"""
num_qubits = num_ctrl_qubits + 1
q = QuantumRegister(num_qubits, name="q")
qc = QuantumCircuit(q, name="mcx_gray")
qc._append(HGate(), [q[-1]], [])
qc._append(MCU1Gate(np.pi, num_ctrl_qubits=num_ctrl_qubits), q[:], [])
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
qc._append(HGate(), [q[-1]], [])
return qc


def synth_mcx_mcphase(num_ctrl_qubits: int) -> QuantumCircuit:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any better suggestions for this function name? the mcp synth is based on iteratively using mcrz synth.
I would suggest synth_mcx_basic ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't mcrz use the _mcsu2 work? Maybe we can use that paper as reference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking for a better name for this too, so ideas are welcome. I am not particularly fond of synth_mcx_basic though, as the word "basic" is too generic. By the way, do we have a reference for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is a reference for the mcrz (mcsu2) paper, but this code is a variant that does not appear in the paper.

[1] R. Vale et al. Decomposition of Multi-controlled Special Unitary Single-Qubit Gates
arXiv:2302.06377 (2023) https://arxiv.org/abs/2302.06377

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reference; adding.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think that we should find a better name than " synth_mcx_mcphase"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After an offline discussion with @ShellyGarion and @Cryoris, we have settled on synth_v24. I am not really fond of this or other names, but this is the best we could think of and consistent with the naming of other methods.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we should definitely introduce a human-readable alias for these methods, which users can call in the HLS 🙂

r"""
Synthesize a multi-controlled X gate with :math:`k` controls based on
the implementation for MCPhaseGate.

Produces a quantum circuit with :math:`num_ctrl_qubits + 1` qubits.
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved

Args:
num_ctrl_qubits: The number of control qubits.

Returns:
The synthesized quantum circuit.
"""
if num_ctrl_qubits == 3:
return synth_c3x()

if num_ctrl_qubits == 4:
return synth_c4x()

num_qubits = num_ctrl_qubits + 1
q = QuantumRegister(num_qubits, name="q")
qc = QuantumCircuit(q)
q_controls = list(range(num_ctrl_qubits))
q_target = num_ctrl_qubits
qc.h(q_target)
qc.mcp(np.pi, q_controls, q_target)
qc.h(q_target)
return qc


def synth_c3x() -> QuantumCircuit:
alexanderivrii marked this conversation as resolved.
Show resolved Hide resolved
"""Efficient synthesis of 3-controlled X-gate."""

q = QuantumRegister(4, name="q")
qc = QuantumCircuit(q, name="mcx")
qc.h(3)
qc.p(np.pi / 8, [0, 1, 2, 3])
qc.cx(0, 1)
qc.p(-np.pi / 8, 1)
qc.cx(0, 1)
qc.cx(1, 2)
qc.p(-np.pi / 8, 2)
qc.cx(0, 2)
qc.p(np.pi / 8, 2)
qc.cx(1, 2)
qc.p(-np.pi / 8, 2)
qc.cx(0, 2)
qc.cx(2, 3)
qc.p(-np.pi / 8, 3)
qc.cx(1, 3)
qc.p(np.pi / 8, 3)
qc.cx(2, 3)
qc.p(-np.pi / 8, 3)
qc.cx(0, 3)
qc.p(np.pi / 8, 3)
qc.cx(2, 3)
qc.p(-np.pi / 8, 3)
qc.cx(1, 3)
qc.p(np.pi / 8, 3)
qc.cx(2, 3)
qc.p(-np.pi / 8, 3)
qc.cx(0, 3)
qc.h(3)
return qc


def synth_c4x() -> QuantumCircuit:
"""Efficient synthesis of 4-controlled X-gate."""

q = QuantumRegister(5, name="q")
qc = QuantumCircuit(q, name="mcx")

rules = [
(HGate(), [q[4]], []),
(CU1Gate(np.pi / 2), [q[3], q[4]], []),
Cryoris marked this conversation as resolved.
Show resolved Hide resolved
(HGate(), [q[4]], []),
(RC3XGate(), [q[0], q[1], q[2], q[3]], []),
(HGate(), [q[4]], []),
(CU1Gate(-np.pi / 2), [q[3], q[4]], []),
(HGate(), [q[4]], []),
(RC3XGate().inverse(), [q[0], q[1], q[2], q[3]], []),
(C3SXGate(), [q[0], q[1], q[2], q[4]], []),
]
for instr, qargs, cargs in rules:
qc._append(instr, qargs, cargs)

return qc
Loading
Loading