qiskit 2.0.2__cp39-abi3-macosx_11_0_arm64.whl → 2.1.0rc1__cp39-abi3-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +19 -1
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/circuit/__init__.py +13 -21
- qiskit/circuit/_add_control.py +57 -31
- qiskit/circuit/_classical_resource_map.py +4 -0
- qiskit/circuit/annotation.py +404 -0
- qiskit/circuit/classical/expr/__init__.py +1 -1
- qiskit/circuit/classical/expr/expr.py +104 -446
- qiskit/circuit/classical/expr/visitors.py +6 -0
- qiskit/circuit/classical/types/types.py +7 -130
- qiskit/circuit/controlflow/box.py +32 -7
- qiskit/circuit/delay.py +11 -9
- qiskit/circuit/library/arithmetic/adders/adder.py +5 -5
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +3 -3
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +7 -3
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +23 -15
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +22 -14
- qiskit/circuit/library/arithmetic/quadratic_form.py +6 -0
- qiskit/circuit/library/arithmetic/weighted_adder.py +43 -24
- qiskit/circuit/library/basis_change/qft.py +2 -2
- qiskit/circuit/library/blueprintcircuit.py +6 -0
- qiskit/circuit/library/boolean_logic/inner_product.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_and.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_or.py +3 -3
- qiskit/circuit/library/boolean_logic/quantum_xor.py +2 -2
- qiskit/circuit/library/data_preparation/_z_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/_zz_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +2 -2
- qiskit/circuit/library/fourier_checking.py +2 -2
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -1
- qiskit/circuit/library/generalized_gates/gms.py +5 -1
- qiskit/circuit/library/generalized_gates/linear_function.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +5 -1
- qiskit/circuit/library/generalized_gates/uc.py +1 -1
- qiskit/circuit/library/generalized_gates/unitary.py +21 -2
- qiskit/circuit/library/graph_state.py +2 -2
- qiskit/circuit/library/grover_operator.py +2 -2
- qiskit/circuit/library/hidden_linear_function.py +2 -2
- qiskit/circuit/library/iqp.py +2 -2
- qiskit/circuit/library/n_local/efficient_su2.py +2 -2
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
- qiskit/circuit/library/n_local/excitation_preserving.py +7 -9
- qiskit/circuit/library/n_local/n_local.py +4 -3
- qiskit/circuit/library/n_local/pauli_two_design.py +2 -2
- qiskit/circuit/library/n_local/real_amplitudes.py +2 -2
- qiskit/circuit/library/n_local/two_local.py +2 -2
- qiskit/circuit/library/overlap.py +2 -2
- qiskit/circuit/library/pauli_evolution.py +3 -2
- qiskit/circuit/library/phase_estimation.py +2 -2
- qiskit/circuit/library/standard_gates/dcx.py +11 -12
- qiskit/circuit/library/standard_gates/ecr.py +21 -24
- qiskit/circuit/library/standard_gates/equivalence_library.py +232 -96
- qiskit/circuit/library/standard_gates/global_phase.py +5 -6
- qiskit/circuit/library/standard_gates/h.py +22 -45
- qiskit/circuit/library/standard_gates/i.py +1 -1
- qiskit/circuit/library/standard_gates/iswap.py +13 -31
- qiskit/circuit/library/standard_gates/p.py +19 -26
- qiskit/circuit/library/standard_gates/r.py +11 -17
- qiskit/circuit/library/standard_gates/rx.py +21 -45
- qiskit/circuit/library/standard_gates/rxx.py +7 -22
- qiskit/circuit/library/standard_gates/ry.py +21 -39
- qiskit/circuit/library/standard_gates/ryy.py +13 -28
- qiskit/circuit/library/standard_gates/rz.py +18 -35
- qiskit/circuit/library/standard_gates/rzx.py +7 -22
- qiskit/circuit/library/standard_gates/rzz.py +7 -19
- qiskit/circuit/library/standard_gates/s.py +44 -39
- qiskit/circuit/library/standard_gates/swap.py +25 -38
- qiskit/circuit/library/standard_gates/sx.py +34 -41
- qiskit/circuit/library/standard_gates/t.py +18 -27
- qiskit/circuit/library/standard_gates/u.py +8 -24
- qiskit/circuit/library/standard_gates/u1.py +28 -52
- qiskit/circuit/library/standard_gates/u2.py +9 -9
- qiskit/circuit/library/standard_gates/u3.py +24 -40
- qiskit/circuit/library/standard_gates/x.py +190 -336
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +12 -50
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +13 -52
- qiskit/circuit/library/standard_gates/y.py +19 -23
- qiskit/circuit/library/standard_gates/z.py +31 -38
- qiskit/circuit/parameter.py +14 -5
- qiskit/circuit/parameterexpression.py +109 -75
- qiskit/circuit/quantumcircuit.py +168 -98
- qiskit/circuit/quantumcircuitdata.py +1 -0
- qiskit/circuit/random/__init__.py +37 -2
- qiskit/circuit/random/utils.py +445 -56
- qiskit/circuit/tools/pi_check.py +5 -13
- qiskit/compiler/transpiler.py +1 -1
- qiskit/converters/circuit_to_instruction.py +2 -2
- qiskit/dagcircuit/dagnode.py +8 -3
- qiskit/primitives/__init__.py +2 -2
- qiskit/primitives/base/base_estimator.py +2 -2
- qiskit/primitives/containers/data_bin.py +0 -3
- qiskit/primitives/containers/observables_array.py +192 -108
- qiskit/primitives/primitive_job.py +29 -10
- qiskit/providers/fake_provider/generic_backend_v2.py +2 -0
- qiskit/qasm3/__init__.py +106 -12
- qiskit/qasm3/ast.py +15 -1
- qiskit/qasm3/exporter.py +59 -36
- qiskit/qasm3/printer.py +12 -0
- qiskit/qpy/__init__.py +183 -7
- qiskit/qpy/binary_io/circuits.py +256 -24
- qiskit/qpy/binary_io/parse_sympy_repr.py +5 -0
- qiskit/qpy/binary_io/schedules.py +12 -32
- qiskit/qpy/binary_io/value.py +36 -18
- qiskit/qpy/common.py +11 -3
- qiskit/qpy/formats.py +17 -1
- qiskit/qpy/interface.py +52 -12
- qiskit/qpy/type_keys.py +7 -1
- qiskit/quantum_info/__init__.py +10 -0
- qiskit/quantum_info/operators/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/clifford_circuits.py +26 -0
- qiskit/quantum_info/operators/symplectic/pauli.py +2 -2
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +1 -1
- qiskit/result/sampled_expval.py +3 -1
- qiskit/synthesis/__init__.py +10 -0
- qiskit/synthesis/arithmetic/__init__.py +1 -1
- qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
- qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
- qiskit/synthesis/evolution/lie_trotter.py +10 -7
- qiskit/synthesis/evolution/product_formula.py +10 -7
- qiskit/synthesis/evolution/qdrift.py +10 -7
- qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
- qiskit/synthesis/multi_controlled/__init__.py +4 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
- qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
- qiskit/synthesis/unitary/qsd.py +80 -9
- qiskit/transpiler/__init__.py +19 -8
- qiskit/transpiler/instruction_durations.py +2 -20
- qiskit/transpiler/passes/__init__.py +4 -2
- qiskit/transpiler/passes/layout/dense_layout.py +26 -6
- qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
- qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
- qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
- qiskit/transpiler/passes/layout/vf2_utils.py +13 -1
- qiskit/transpiler/passes/optimization/__init__.py +1 -1
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
- qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
- qiskit/transpiler/passes/routing/sabre_swap.py +12 -2
- qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
- qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
- qiskit/transpiler/passes/synthesis/__init__.py +1 -0
- qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
- qiskit/transpiler/passes/synthesis/hls_plugins.py +472 -92
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +27 -22
- qiskit/transpiler/passmanager_config.py +3 -0
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +149 -28
- qiskit/transpiler/preset_passmanagers/common.py +101 -0
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +6 -0
- qiskit/transpiler/preset_passmanagers/level3.py +2 -2
- qiskit/utils/optionals.py +6 -5
- qiskit/visualization/circuit/_utils.py +5 -3
- qiskit/visualization/circuit/latex.py +9 -2
- qiskit/visualization/circuit/matplotlib.py +26 -4
- qiskit/visualization/circuit/qcstyle.py +9 -157
- qiskit/visualization/dag/__init__.py +13 -0
- qiskit/visualization/dag/dagstyle.py +103 -0
- qiskit/visualization/dag/styles/__init__.py +13 -0
- qiskit/visualization/dag/styles/color.json +10 -0
- qiskit/visualization/dag/styles/plain.json +5 -0
- qiskit/visualization/dag_visualization.py +169 -98
- qiskit/visualization/style.py +223 -0
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/METADATA +14 -13
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/RECORD +177 -168
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/entry_points.txt +6 -0
- qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
- qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/WHEEL +0 -0
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/licenses/LICENSE.txt +0 -0
- {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -12,17 +12,22 @@
|
|
12
12
|
|
13
13
|
"""Module containing multi-controlled circuits synthesis with and without ancillary qubits."""
|
14
14
|
|
15
|
+
from __future__ import annotations
|
15
16
|
from math import ceil
|
16
17
|
import numpy as np
|
17
18
|
|
18
|
-
from qiskit.
|
19
|
-
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
19
|
+
from qiskit.exceptions import QiskitError
|
20
|
+
from qiskit.circuit.quantumcircuit import QuantumCircuit, QuantumRegister, AncillaRegister
|
20
21
|
from qiskit.circuit.library.standard_gates import (
|
21
22
|
HGate,
|
22
|
-
MCU1Gate,
|
23
23
|
CU1Gate,
|
24
|
-
|
25
|
-
|
24
|
+
)
|
25
|
+
|
26
|
+
from qiskit._accelerate.synthesis.multi_controlled import (
|
27
|
+
c3x as c3x_rs,
|
28
|
+
c4x as c4x_rs,
|
29
|
+
synth_mcx_n_dirty_i15 as synth_mcx_n_dirty_i15_rs,
|
30
|
+
synth_mcx_noaux_v24 as synth_mcx_noaux_v24_rs,
|
26
31
|
)
|
27
32
|
|
28
33
|
|
@@ -32,9 +37,12 @@ def synth_mcx_n_dirty_i15(
|
|
32
37
|
action_only: bool = False,
|
33
38
|
) -> QuantumCircuit:
|
34
39
|
r"""
|
35
|
-
Synthesize a multi-controlled X gate with :math:`k` controls
|
36
|
-
|
37
|
-
|
40
|
+
Synthesize a multi-controlled X gate with :math:`k` controls based on the paper
|
41
|
+
by Iten et al. [1].
|
42
|
+
|
43
|
+
For :math:`k\ge 4` the method uses :math:`k - 2` dirty ancillary qubits, producing a circuit
|
44
|
+
with :math:`2 * k - 1` qubits and at most :math:`8 * k - 6` CX gates. For :math:`k\le 3`
|
45
|
+
explicit efficient circuits are used instead.
|
38
46
|
|
39
47
|
Args:
|
40
48
|
num_ctrl_qubits: The number of control qubits.
|
@@ -52,86 +60,9 @@ def synth_mcx_n_dirty_i15(
|
|
52
60
|
1. Iten et. al., *Quantum Circuits for Isometries*, Phys. Rev. A 93, 032318 (2016),
|
53
61
|
`arXiv:1501.06911 <http://arxiv.org/abs/1501.06911>`_
|
54
62
|
"""
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
else:
|
59
|
-
num_qubits = 2 * num_ctrl_qubits - 1
|
60
|
-
q = QuantumRegister(num_qubits, name="q")
|
61
|
-
qc = QuantumCircuit(q, name="mcx_vchain")
|
62
|
-
q_controls = q[:num_ctrl_qubits]
|
63
|
-
q_target = q[num_ctrl_qubits]
|
64
|
-
q_ancillas = q[num_ctrl_qubits + 1 :]
|
65
|
-
|
66
|
-
if num_ctrl_qubits == 1:
|
67
|
-
qc.cx(q_controls, q_target)
|
68
|
-
return qc
|
69
|
-
elif num_ctrl_qubits == 2:
|
70
|
-
qc.ccx(q_controls[0], q_controls[1], q_target)
|
71
|
-
return qc
|
72
|
-
elif not relative_phase and num_ctrl_qubits == 3:
|
73
|
-
circuit = synth_c3x()
|
74
|
-
qc.compose(circuit, [*q_controls, q_target], inplace=True, copy=False)
|
75
|
-
return qc
|
76
|
-
|
77
|
-
num_ancillas = num_ctrl_qubits - 2
|
78
|
-
targets = [q_target] + q_ancillas[:num_ancillas][::-1]
|
79
|
-
|
80
|
-
for j in range(2):
|
81
|
-
for i in range(num_ctrl_qubits): # action part
|
82
|
-
if i < num_ctrl_qubits - 2:
|
83
|
-
if targets[i] != q_target or relative_phase:
|
84
|
-
# gate cancelling
|
85
|
-
|
86
|
-
# cancel rightmost gates of action part
|
87
|
-
# with leftmost gates of reset part
|
88
|
-
if relative_phase and targets[i] == q_target and j == 1:
|
89
|
-
qc.cx(q_ancillas[num_ancillas - i - 1], targets[i])
|
90
|
-
qc.t(targets[i])
|
91
|
-
qc.cx(q_controls[num_ctrl_qubits - i - 1], targets[i])
|
92
|
-
qc.tdg(targets[i])
|
93
|
-
qc.h(targets[i])
|
94
|
-
else:
|
95
|
-
qc.h(targets[i])
|
96
|
-
qc.t(targets[i])
|
97
|
-
qc.cx(q_controls[num_ctrl_qubits - i - 1], targets[i])
|
98
|
-
qc.tdg(targets[i])
|
99
|
-
qc.cx(q_ancillas[num_ancillas - i - 1], targets[i])
|
100
|
-
else:
|
101
|
-
controls = [
|
102
|
-
q_controls[num_ctrl_qubits - i - 1],
|
103
|
-
q_ancillas[num_ancillas - i - 1],
|
104
|
-
]
|
105
|
-
|
106
|
-
qc.ccx(controls[0], controls[1], targets[i])
|
107
|
-
else:
|
108
|
-
# implements an optimized toffoli operation
|
109
|
-
# up to a diagonal gate, akin to lemma 6 of arXiv:1501.06911
|
110
|
-
qc.h(targets[i])
|
111
|
-
qc.t(targets[i])
|
112
|
-
qc.cx(q_controls[num_ctrl_qubits - i - 2], targets[i])
|
113
|
-
qc.tdg(targets[i])
|
114
|
-
qc.cx(q_controls[num_ctrl_qubits - i - 1], targets[i])
|
115
|
-
qc.t(targets[i])
|
116
|
-
qc.cx(q_controls[num_ctrl_qubits - i - 2], targets[i])
|
117
|
-
qc.tdg(targets[i])
|
118
|
-
qc.h(targets[i])
|
119
|
-
|
120
|
-
break
|
121
|
-
|
122
|
-
for i in range(num_ancillas - 1): # reset part
|
123
|
-
qc.cx(q_ancillas[i], q_ancillas[i + 1])
|
124
|
-
qc.t(q_ancillas[i + 1])
|
125
|
-
qc.cx(q_controls[2 + i], q_ancillas[i + 1])
|
126
|
-
qc.tdg(q_ancillas[i + 1])
|
127
|
-
qc.h(q_ancillas[i + 1])
|
128
|
-
|
129
|
-
if action_only:
|
130
|
-
qc.ccx(q_controls[-1], q_ancillas[-1], q_target)
|
131
|
-
|
132
|
-
break
|
133
|
-
|
134
|
-
return qc
|
63
|
+
return QuantumCircuit._from_circuit_data(
|
64
|
+
synth_mcx_n_dirty_i15_rs(num_ctrl_qubits, relative_phase, action_only)
|
65
|
+
)
|
135
66
|
|
136
67
|
|
137
68
|
def synth_mcx_n_clean_m15(num_ctrl_qubits: int) -> QuantumCircuit:
|
@@ -181,7 +112,7 @@ def synth_mcx_1_clean_b95(num_ctrl_qubits: int) -> QuantumCircuit:
|
|
181
112
|
r"""
|
182
113
|
Synthesize a multi-controlled X gate with :math:`k` controls using a single
|
183
114
|
clean ancillary qubit producing a circuit with :math:`k + 2` qubits and at most
|
184
|
-
:math:`16 * k -
|
115
|
+
:math:`16 * k - 24` CX gates, by [1], [2].
|
185
116
|
|
186
117
|
Args:
|
187
118
|
num_ctrl_qubits: The number of control qubits.
|
@@ -190,8 +121,10 @@ def synth_mcx_1_clean_b95(num_ctrl_qubits: int) -> QuantumCircuit:
|
|
190
121
|
The synthesized quantum circuit.
|
191
122
|
|
192
123
|
References:
|
193
|
-
1. Barenco et. al., Phys.Rev. A52 3457 (1995),
|
124
|
+
1. Barenco et. al., *Elementary gates for quantum computation*, Phys.Rev. A52 3457 (1995),
|
194
125
|
`arXiv:quant-ph/9503016 <https://arxiv.org/abs/quant-ph/9503016>`_
|
126
|
+
2. Iten et. al., *Quantum Circuits for Isometries*, Phys. Rev. A 93, 032318 (2016),
|
127
|
+
`arXiv:1501.06911 <http://arxiv.org/abs/1501.06911>`_
|
195
128
|
"""
|
196
129
|
|
197
130
|
if num_ctrl_qubits == 3:
|
@@ -208,32 +141,27 @@ def synth_mcx_1_clean_b95(num_ctrl_qubits: int) -> QuantumCircuit:
|
|
208
141
|
q_ancilla = q[-1]
|
209
142
|
q_target = q[-2]
|
210
143
|
middle = ceil(num_ctrl_qubits / 2)
|
211
|
-
first_half = [*q[:middle]]
|
212
|
-
second_half = [*q[middle : num_ctrl_qubits - 1], q_ancilla]
|
213
144
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
)
|
232
|
-
qc.
|
233
|
-
|
234
|
-
qargs=[*second_half, q_target, *q[: len(second_half) - 2]],
|
235
|
-
cargs=[],
|
236
|
-
)
|
145
|
+
# The contruction involving 4 MCX gates is described in Lemma 7.3 of [1], and also
|
146
|
+
# appears as Lemma 9 in [2]. The optimization that the first and third MCX gates
|
147
|
+
# can be synthesized up to relative phase follows from Lemma 7 in [2], as a diagonal
|
148
|
+
# gate following the first MCX gate commutes with the second MCX gate, and
|
149
|
+
# thus cancels with the inverse diagonal gate preceding the third MCX gate. The
|
150
|
+
# same optimization cannot be applied to the second MCX gate, since a diagonal
|
151
|
+
# gate following the second MCX gate would not satisfy the preconditions of Lemma 7,
|
152
|
+
# and would not necessarily commute with the third MCX gate.
|
153
|
+
controls1 = [*q[:middle]]
|
154
|
+
mcx1 = synth_mcx_n_dirty_i15(num_ctrl_qubits=len(controls1), relative_phase=True)
|
155
|
+
qubits1 = [*controls1, q_ancilla, *q[middle : middle + mcx1.num_qubits - len(controls1) - 1]]
|
156
|
+
|
157
|
+
controls2 = [*q[middle : num_ctrl_qubits - 1], q_ancilla]
|
158
|
+
mcx2 = synth_mcx_n_dirty_i15(num_ctrl_qubits=len(controls2))
|
159
|
+
qc2_qubits = [*controls2, q_target, *q[0 : mcx2.num_qubits - len(controls2) - 1]]
|
160
|
+
|
161
|
+
qc.compose(mcx1, qubits1, inplace=True)
|
162
|
+
qc.compose(mcx2, qc2_qubits, inplace=True)
|
163
|
+
qc.compose(mcx1.inverse(), qubits1, inplace=True)
|
164
|
+
qc.compose(mcx2, qc2_qubits, inplace=True)
|
237
165
|
|
238
166
|
return qc
|
239
167
|
|
@@ -252,11 +180,17 @@ def synth_mcx_gray_code(num_ctrl_qubits: int) -> QuantumCircuit:
|
|
252
180
|
Returns:
|
253
181
|
The synthesized quantum circuit.
|
254
182
|
"""
|
183
|
+
from qiskit.circuit.library.standard_gates.u3 import _gray_code_chain
|
184
|
+
|
255
185
|
num_qubits = num_ctrl_qubits + 1
|
256
186
|
q = QuantumRegister(num_qubits, name="q")
|
257
187
|
qc = QuantumCircuit(q, name="mcx_gray")
|
258
188
|
qc._append(HGate(), [q[-1]], [])
|
259
|
-
|
189
|
+
scaled_lam = np.pi / (2 ** (num_ctrl_qubits - 1))
|
190
|
+
bottom_gate = CU1Gate(scaled_lam)
|
191
|
+
definition = _gray_code_chain(q, num_ctrl_qubits, bottom_gate)
|
192
|
+
for instr, qargs, cargs in definition:
|
193
|
+
qc._append(instr, qargs, cargs)
|
260
194
|
qc._append(HGate(), [q[-1]], [])
|
261
195
|
return qc
|
262
196
|
|
@@ -283,77 +217,367 @@ def synth_mcx_noaux_v24(num_ctrl_qubits: int) -> QuantumCircuit:
|
|
283
217
|
Single-Qubit Gates*, IEEE TCAD 43(3) (2024),
|
284
218
|
`arXiv:2302.06377 <https://arxiv.org/abs/2302.06377>`_
|
285
219
|
"""
|
286
|
-
|
287
|
-
|
220
|
+
circ = QuantumCircuit._from_circuit_data(synth_mcx_noaux_v24_rs(num_ctrl_qubits))
|
221
|
+
return circ
|
288
222
|
|
289
|
-
if num_ctrl_qubits == 4:
|
290
|
-
return synth_c4x()
|
291
223
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
224
|
+
def _n_parallel_ccx_x(n: int, apply_x: bool = True) -> QuantumCircuit:
|
225
|
+
r"""
|
226
|
+
Construct a quantum circuit for creating n-condionally clean ancillae using 3n qubits. This
|
227
|
+
implements Fig. 4a of [1]. The circuit applies n relative CCX (RCCX) gates . If apply_x is True,
|
228
|
+
each RCCX gate is preceded by an X gate on the target qubit. The order of returned qubits is
|
229
|
+
qr_a, qr_b, qr_target.
|
230
|
+
|
231
|
+
Args:
|
232
|
+
n: Number of conditionally clean ancillae to create.
|
233
|
+
apply_x: If True, apply X gate to the target qubit.
|
234
|
+
|
235
|
+
Returns:
|
236
|
+
QuantumCircuit: The quantum circuit for creating n-conditionally clean ancillae.
|
237
|
+
|
238
|
+
References:
|
239
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
240
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
241
|
+
"""
|
242
|
+
|
243
|
+
n_qubits = 3 * n
|
244
|
+
q = QuantumRegister(n_qubits, name="q")
|
245
|
+
qc = QuantumCircuit(q, name=f"ccxn_{n}")
|
246
|
+
qr_a, qr_b, qr_target = q[:n], q[n : 2 * n], q[2 * n :]
|
247
|
+
|
248
|
+
if apply_x:
|
249
|
+
qc.x(qr_target)
|
250
|
+
|
251
|
+
qc.rccx(qr_a, qr_b, qr_target)
|
252
|
+
|
300
253
|
return qc
|
301
254
|
|
302
255
|
|
303
|
-
def
|
304
|
-
"""
|
256
|
+
def _linear_depth_ladder_ops(num_ladder_qubits: int) -> tuple[QuantumCircuit, list[int]]:
|
257
|
+
r"""
|
258
|
+
Helper function to create linear-depth ladder operations used in Khattar and Gidney's MCX synthesis.
|
259
|
+
In particular, this implements Step-1 and Step-2 on Fig. 3 of [1] except for the first and last
|
260
|
+
CCX gates.
|
261
|
+
|
262
|
+
Args:
|
263
|
+
num_ladder_qubits: No. of qubits involved in the ladder operation.
|
264
|
+
|
265
|
+
Returns:
|
266
|
+
A tuple consisting of the linear-depth ladder circuit and the index of control qubit to
|
267
|
+
apply the final CCX gate.
|
268
|
+
|
269
|
+
Raises:
|
270
|
+
QiskitError: If num_ladder_qubits <= 2.
|
271
|
+
|
272
|
+
References:
|
273
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
274
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
275
|
+
"""
|
276
|
+
|
277
|
+
if num_ladder_qubits <= 2:
|
278
|
+
raise QiskitError("n_ctrls >= 3 to use MCX ladder. Otherwise, use CCX")
|
279
|
+
|
280
|
+
n = num_ladder_qubits + 1
|
281
|
+
qc = QuantumCircuit(n)
|
282
|
+
qreg = list(range(n))
|
283
|
+
|
284
|
+
# up-ladder
|
285
|
+
for i in range(2, n - 2, 2):
|
286
|
+
qc.rccx(qreg[i + 1], qreg[i + 2], qreg[i])
|
287
|
+
qc.x(qreg[i])
|
288
|
+
|
289
|
+
# down-ladder
|
290
|
+
if n % 2 != 0:
|
291
|
+
a, b, target = n - 3, n - 5, n - 6
|
292
|
+
else:
|
293
|
+
a, b, target = n - 1, n - 4, n - 5
|
294
|
+
|
295
|
+
if target > 0:
|
296
|
+
qc.rccx(qreg[a], qreg[b], qreg[target])
|
297
|
+
qc.x(qreg[target])
|
298
|
+
|
299
|
+
for i in range(target, 2, -2):
|
300
|
+
qc.rccx(qreg[i], qreg[i - 1], qreg[i - 2])
|
301
|
+
qc.x(qreg[i - 2])
|
302
|
+
|
303
|
+
mid_second_ctrl = 1 + max(0, 6 - n)
|
304
|
+
final_ctrl = qreg[mid_second_ctrl] - 1
|
305
|
+
return qc, final_ctrl
|
306
|
+
|
307
|
+
|
308
|
+
def synth_mcx_1_kg24(num_ctrl_qubits: int, clean: bool = True) -> QuantumCircuit:
|
309
|
+
r"""
|
310
|
+
Synthesize a multi-controlled X gate with :math:`k` controls using :math:`1` ancillary qubit as
|
311
|
+
described in Sec. 5 of [1].
|
312
|
+
|
313
|
+
Args:
|
314
|
+
num_ctrl_qubits: The number of control qubits.
|
315
|
+
clean: If True, the ancilla is clean, otherwise it is dirty.
|
316
|
+
|
317
|
+
Returns:
|
318
|
+
The synthesized quantum circuit.
|
319
|
+
|
320
|
+
Raises:
|
321
|
+
QiskitError: If num_ctrl_qubits <= 2.
|
322
|
+
|
323
|
+
References:
|
324
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
325
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
326
|
+
"""
|
327
|
+
|
328
|
+
if num_ctrl_qubits <= 2:
|
329
|
+
raise QiskitError("kg24 synthesis requires at least 3 control qubits. Use CCX directly.")
|
330
|
+
|
331
|
+
q_controls = QuantumRegister(num_ctrl_qubits, name="ctrl")
|
332
|
+
q_target = QuantumRegister(1, name="targ")
|
333
|
+
q_ancilla = AncillaRegister(1, name="anc")
|
334
|
+
qc = QuantumCircuit(q_controls, q_target, q_ancilla, name="mcx_linear_depth")
|
335
|
+
|
336
|
+
ladder_ops, final_ctrl = _linear_depth_ladder_ops(num_ctrl_qubits)
|
337
|
+
|
338
|
+
qc.rccx(q_controls[0], q_controls[1], q_ancilla[0]) # # create cond. clean ancilla
|
339
|
+
qc.compose(ladder_ops, q_ancilla[:] + q_controls[:], inplace=True) # up-ladder
|
340
|
+
qc.ccx(q_ancilla, q_controls[final_ctrl], q_target) # # target
|
341
|
+
qc.compose( # # down-ladder
|
342
|
+
ladder_ops.inverse(),
|
343
|
+
q_ancilla[:] + q_controls[:],
|
344
|
+
inplace=True,
|
345
|
+
)
|
346
|
+
qc.rccx(q_controls[0], q_controls[1], q_ancilla[0]) # # undo cond. clean ancilla
|
347
|
+
|
348
|
+
if not clean:
|
349
|
+
# perform toggle-detection if ancilla is dirty
|
350
|
+
qc.compose(ladder_ops, q_ancilla[:] + q_controls[:], inplace=True)
|
351
|
+
qc.ccx(q_ancilla, q_controls[final_ctrl], q_target)
|
352
|
+
qc.compose(ladder_ops.inverse(), q_ancilla[:] + q_controls[:], inplace=True)
|
305
353
|
|
306
|
-
q = QuantumRegister(4, name="q")
|
307
|
-
qc = QuantumCircuit(q, name="mcx")
|
308
|
-
qc.h(3)
|
309
|
-
qc.p(np.pi / 8, [0, 1, 2, 3])
|
310
|
-
qc.cx(0, 1)
|
311
|
-
qc.p(-np.pi / 8, 1)
|
312
|
-
qc.cx(0, 1)
|
313
|
-
qc.cx(1, 2)
|
314
|
-
qc.p(-np.pi / 8, 2)
|
315
|
-
qc.cx(0, 2)
|
316
|
-
qc.p(np.pi / 8, 2)
|
317
|
-
qc.cx(1, 2)
|
318
|
-
qc.p(-np.pi / 8, 2)
|
319
|
-
qc.cx(0, 2)
|
320
|
-
qc.cx(2, 3)
|
321
|
-
qc.p(-np.pi / 8, 3)
|
322
|
-
qc.cx(1, 3)
|
323
|
-
qc.p(np.pi / 8, 3)
|
324
|
-
qc.cx(2, 3)
|
325
|
-
qc.p(-np.pi / 8, 3)
|
326
|
-
qc.cx(0, 3)
|
327
|
-
qc.p(np.pi / 8, 3)
|
328
|
-
qc.cx(2, 3)
|
329
|
-
qc.p(-np.pi / 8, 3)
|
330
|
-
qc.cx(1, 3)
|
331
|
-
qc.p(np.pi / 8, 3)
|
332
|
-
qc.cx(2, 3)
|
333
|
-
qc.p(-np.pi / 8, 3)
|
334
|
-
qc.cx(0, 3)
|
335
|
-
qc.h(3)
|
336
354
|
return qc
|
337
355
|
|
338
356
|
|
339
|
-
def
|
340
|
-
"""
|
357
|
+
def synth_mcx_1_clean_kg24(num_ctrl_qubits: int) -> QuantumCircuit:
|
358
|
+
r"""
|
359
|
+
Synthesize a multi-controlled X gate with :math:`k` controls using :math:`1` clean ancillary qubit
|
360
|
+
producing a circuit with :math:`2k-3` Toffoli gates and depth :math:`O(k)` as described in
|
361
|
+
Sec. 5.1 of [1].
|
341
362
|
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
363
|
+
Args:
|
364
|
+
num_ctrl_qubits: The number of control qubits.
|
365
|
+
|
366
|
+
Returns:
|
367
|
+
The synthesized quantum circuit.
|
368
|
+
|
369
|
+
Raises:
|
370
|
+
QiskitError: If num_ctrl_qubits <= 2.
|
371
|
+
|
372
|
+
References:
|
373
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
374
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
375
|
+
"""
|
376
|
+
|
377
|
+
return synth_mcx_1_kg24(num_ctrl_qubits, clean=True)
|
378
|
+
|
379
|
+
|
380
|
+
def synth_mcx_1_dirty_kg24(num_ctrl_qubits: int) -> QuantumCircuit:
|
381
|
+
r"""
|
382
|
+
Synthesize a multi-controlled X gate with :math:`k` controls using :math:`1` dirty ancillary qubit
|
383
|
+
producing a circuit with :math:`4k-8` Toffoli gates and depth :math:`O(k)` as described in
|
384
|
+
Sec. 5.3 of [1].
|
385
|
+
|
386
|
+
Args:
|
387
|
+
num_ctrl_qubits: The number of control qubits.
|
388
|
+
|
389
|
+
Returns:
|
390
|
+
The synthesized quantum circuit.
|
391
|
+
|
392
|
+
Raises:
|
393
|
+
QiskitError: If num_ctrl_qubits <= 2.
|
394
|
+
|
395
|
+
References:
|
396
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
397
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
398
|
+
"""
|
399
|
+
|
400
|
+
return synth_mcx_1_kg24(num_ctrl_qubits, clean=False)
|
401
|
+
|
402
|
+
|
403
|
+
def _build_logn_depth_ccx_ladder(
|
404
|
+
ancilla_idx: int, ctrls: list[int], skip_cond_clean: bool = False
|
405
|
+
) -> tuple[QuantumCircuit, list[int]]:
|
406
|
+
r"""
|
407
|
+
Helper function to build a log-depth ladder compose of CCX and X gates as shown in Fig. 4b of [1].
|
408
|
+
|
409
|
+
Args:
|
410
|
+
ancilla_idx: Index of the ancillary qubit.
|
411
|
+
ctrls: List of control qubits.
|
412
|
+
skip_cond_clean: If True, do not include the conditionally clean ancilla (step 1 and 5 in
|
413
|
+
Fig. 4b of [1]).
|
414
|
+
|
415
|
+
Returns:
|
416
|
+
A tuple consisting of the log-depth ladder circuit of conditionally clean ancillae and the
|
417
|
+
list of indices of control qubit to apply the linear-depth MCX gate.
|
418
|
+
|
419
|
+
Raises:
|
420
|
+
QiskitError: If no. of qubits in parallel CCX + X gates are not the same.
|
421
|
+
|
422
|
+
References:
|
423
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
424
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
425
|
+
"""
|
426
|
+
|
427
|
+
qc = QuantumCircuit(len(ctrls) + 1)
|
428
|
+
anc = [ancilla_idx]
|
429
|
+
final_ctrls = []
|
430
|
+
|
431
|
+
while len(ctrls) > 1:
|
432
|
+
next_batch_len = min(len(anc) + 1, len(ctrls))
|
433
|
+
ctrls, nxt_batch = ctrls[next_batch_len:], ctrls[:next_batch_len]
|
434
|
+
new_anc = []
|
435
|
+
while len(nxt_batch) > 1:
|
436
|
+
ccx_n = len(nxt_batch) // 2
|
437
|
+
st = int(len(nxt_batch) % 2)
|
438
|
+
ccx_x, ccx_y, ccx_t = (
|
439
|
+
nxt_batch[st : st + ccx_n],
|
440
|
+
nxt_batch[st + ccx_n :],
|
441
|
+
anc[-ccx_n:],
|
442
|
+
)
|
443
|
+
if not len(ccx_x) == len(ccx_y) == ccx_n >= 1:
|
444
|
+
raise QiskitError(
|
445
|
+
f"Invalid CCX gate parameters: {len(ccx_x)=} != {len(ccx_y)=} != {len(ccx_n)=}"
|
446
|
+
)
|
447
|
+
if ccx_t != [ancilla_idx]:
|
448
|
+
qc.compose(_n_parallel_ccx_x(ccx_n), ccx_x + ccx_y + ccx_t, inplace=True)
|
449
|
+
else:
|
450
|
+
if not skip_cond_clean:
|
451
|
+
qc.rccx(ccx_x[0], ccx_y[0], ccx_t[0]) # # create conditionally clean ancilla
|
452
|
+
|
453
|
+
new_anc += nxt_batch[st:] # # newly created cond. clean ancilla
|
454
|
+
nxt_batch = ccx_t + nxt_batch[:st]
|
455
|
+
anc = anc[:-ccx_n]
|
456
|
+
|
457
|
+
anc = sorted(anc + new_anc)
|
458
|
+
final_ctrls += nxt_batch
|
459
|
+
|
460
|
+
final_ctrls += ctrls
|
461
|
+
final_ctrls = sorted(final_ctrls)
|
462
|
+
return qc, final_ctrls[:-1] # exclude ancilla
|
463
|
+
|
464
|
+
|
465
|
+
def synth_mcx_2_kg24(num_ctrl_qubits: int, clean: bool = True) -> QuantumCircuit:
|
466
|
+
r"""
|
467
|
+
Synthesize a multi-controlled X gate with :math:`k` controls using :math:`2` ancillary qubits.
|
468
|
+
as described in Sec. 5 of [1].
|
469
|
+
|
470
|
+
Args:
|
471
|
+
num_ctrl_qubits: The number of control qubits.
|
472
|
+
clean: If True, the ancilla is clean, otherwise it is dirty.
|
473
|
+
|
474
|
+
Returns:
|
475
|
+
The synthesized quantum circuit.
|
476
|
+
|
477
|
+
Raises:
|
478
|
+
QiskitError: If num_ctrl_qubits <= 2.
|
479
|
+
|
480
|
+
References:
|
481
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
482
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
483
|
+
"""
|
484
|
+
|
485
|
+
if num_ctrl_qubits <= 2:
|
486
|
+
raise QiskitError("kg24 synthesis requires at least 3 control qubits. Use CCX directly.")
|
487
|
+
|
488
|
+
q_control = QuantumRegister(num_ctrl_qubits, name="ctrl")
|
489
|
+
q_target = QuantumRegister(1, name="targ")
|
490
|
+
q_ancilla = AncillaRegister(2, name="anc")
|
491
|
+
qc = QuantumCircuit(q_control, q_target, q_ancilla, name="mcx_logn_depth")
|
492
|
+
|
493
|
+
ladder_ops, final_ctrls = _build_logn_depth_ccx_ladder(
|
494
|
+
num_ctrl_qubits, list(range(num_ctrl_qubits))
|
495
|
+
)
|
496
|
+
qc.compose(ladder_ops, q_control[:] + [q_ancilla[0]], inplace=True)
|
497
|
+
if len(final_ctrls) == 1: # Already a toffoli
|
498
|
+
qc.ccx(q_ancilla[0], q_control[final_ctrls[0]], q_target)
|
499
|
+
else:
|
500
|
+
mid_mcx = synth_mcx_1_clean_kg24(len(final_ctrls) + 1)
|
501
|
+
qc.compose(
|
502
|
+
mid_mcx,
|
503
|
+
[q_ancilla[0]]
|
504
|
+
+ q_control[final_ctrls]
|
505
|
+
+ q_target[:]
|
506
|
+
+ [q_ancilla[1]], # ctrls, targ, anc
|
507
|
+
inplace=True,
|
508
|
+
)
|
509
|
+
qc.compose(ladder_ops.inverse(), q_control[:] + [q_ancilla[0]], inplace=True)
|
510
|
+
|
511
|
+
if not clean:
|
512
|
+
# perform toggle-detection if ancilla is dirty
|
513
|
+
ladder_ops_new, final_ctrls = _build_logn_depth_ccx_ladder(
|
514
|
+
num_ctrl_qubits, list(range(num_ctrl_qubits)), skip_cond_clean=True
|
515
|
+
)
|
516
|
+
qc.compose(ladder_ops_new, q_control[:] + [q_ancilla[0]], inplace=True)
|
517
|
+
if len(final_ctrls) == 1:
|
518
|
+
qc.ccx(q_ancilla[0], q_control[final_ctrls[0]], q_target)
|
519
|
+
else:
|
520
|
+
qc.compose(
|
521
|
+
mid_mcx,
|
522
|
+
[q_ancilla[0]] + q_control[final_ctrls] + q_target[:] + [q_ancilla[1]],
|
523
|
+
inplace=True,
|
524
|
+
)
|
525
|
+
qc.compose(ladder_ops_new.inverse(), q_control[:] + [q_ancilla[0]], inplace=True)
|
358
526
|
|
359
527
|
return qc
|
528
|
+
|
529
|
+
|
530
|
+
def synth_mcx_2_clean_kg24(num_ctrl_qubits: int) -> QuantumCircuit:
|
531
|
+
r"""
|
532
|
+
Synthesize a multi-controlled X gate with :math:`k` controls using :math:`2` clean ancillary qubits
|
533
|
+
producing a circuit with :math:`2k-3` Toffoli gates and depth :math:`O(\log(k))` as described in
|
534
|
+
Sec. 5.2 of [1].
|
535
|
+
|
536
|
+
Args:
|
537
|
+
num_ctrl_qubits: The number of control qubits.
|
538
|
+
|
539
|
+
Returns:
|
540
|
+
The synthesized quantum circuit.
|
541
|
+
|
542
|
+
Raises:
|
543
|
+
QiskitError: If num_ctrl_qubits <= 2.
|
544
|
+
|
545
|
+
References:
|
546
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
547
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
548
|
+
"""
|
549
|
+
|
550
|
+
return synth_mcx_2_kg24(num_ctrl_qubits, clean=True)
|
551
|
+
|
552
|
+
|
553
|
+
def synth_mcx_2_dirty_kg24(num_ctrl_qubits: int) -> QuantumCircuit:
|
554
|
+
r"""
|
555
|
+
Synthesize a multi-controlled X gate with :math:`k` controls using :math:`2` dirty ancillary qubits
|
556
|
+
producing a circuit with :math:`4k-8` Toffoli gates and depth :math:`O(\log(k))` as described in
|
557
|
+
Sec. 5.4 of [1].
|
558
|
+
|
559
|
+
Args:
|
560
|
+
num_ctrl_qubits: The number of control qubits.
|
561
|
+
|
562
|
+
Returns:
|
563
|
+
The synthesized quantum circuit.
|
564
|
+
|
565
|
+
Raises:
|
566
|
+
QiskitError: If num_ctrl_qubits <= 2.
|
567
|
+
|
568
|
+
References:
|
569
|
+
1. Khattar and Gidney, Rise of conditionally clean ancillae for optimizing quantum circuits
|
570
|
+
`arXiv:2407.17966 <https://arxiv.org/abs/2407.17966>`__
|
571
|
+
"""
|
572
|
+
|
573
|
+
return synth_mcx_2_kg24(num_ctrl_qubits, clean=False)
|
574
|
+
|
575
|
+
|
576
|
+
def synth_c3x() -> QuantumCircuit:
|
577
|
+
"""Efficient synthesis of 3-controlled X-gate."""
|
578
|
+
return QuantumCircuit._from_circuit_data(c3x_rs())
|
579
|
+
|
580
|
+
|
581
|
+
def synth_c4x() -> QuantumCircuit:
|
582
|
+
"""Efficient synthesis of 4-controlled X-gate."""
|
583
|
+
return QuantumCircuit._from_circuit_data(c4x_rs())
|