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.
Files changed (179) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +19 -1
  3. qiskit/_accelerate.abi3.so +0 -0
  4. qiskit/circuit/__init__.py +13 -21
  5. qiskit/circuit/_add_control.py +57 -31
  6. qiskit/circuit/_classical_resource_map.py +4 -0
  7. qiskit/circuit/annotation.py +404 -0
  8. qiskit/circuit/classical/expr/__init__.py +1 -1
  9. qiskit/circuit/classical/expr/expr.py +104 -446
  10. qiskit/circuit/classical/expr/visitors.py +6 -0
  11. qiskit/circuit/classical/types/types.py +7 -130
  12. qiskit/circuit/controlflow/box.py +32 -7
  13. qiskit/circuit/delay.py +11 -9
  14. qiskit/circuit/library/arithmetic/adders/adder.py +5 -5
  15. qiskit/circuit/library/arithmetic/multipliers/multiplier.py +3 -3
  16. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +7 -3
  17. qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +23 -15
  18. qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +22 -14
  19. qiskit/circuit/library/arithmetic/quadratic_form.py +6 -0
  20. qiskit/circuit/library/arithmetic/weighted_adder.py +43 -24
  21. qiskit/circuit/library/basis_change/qft.py +2 -2
  22. qiskit/circuit/library/blueprintcircuit.py +6 -0
  23. qiskit/circuit/library/boolean_logic/inner_product.py +2 -2
  24. qiskit/circuit/library/boolean_logic/quantum_and.py +2 -2
  25. qiskit/circuit/library/boolean_logic/quantum_or.py +3 -3
  26. qiskit/circuit/library/boolean_logic/quantum_xor.py +2 -2
  27. qiskit/circuit/library/data_preparation/_z_feature_map.py +2 -2
  28. qiskit/circuit/library/data_preparation/_zz_feature_map.py +2 -2
  29. qiskit/circuit/library/data_preparation/pauli_feature_map.py +2 -2
  30. qiskit/circuit/library/fourier_checking.py +2 -2
  31. qiskit/circuit/library/generalized_gates/diagonal.py +5 -1
  32. qiskit/circuit/library/generalized_gates/gms.py +5 -1
  33. qiskit/circuit/library/generalized_gates/linear_function.py +2 -2
  34. qiskit/circuit/library/generalized_gates/permutation.py +5 -1
  35. qiskit/circuit/library/generalized_gates/uc.py +1 -1
  36. qiskit/circuit/library/generalized_gates/unitary.py +21 -2
  37. qiskit/circuit/library/graph_state.py +2 -2
  38. qiskit/circuit/library/grover_operator.py +2 -2
  39. qiskit/circuit/library/hidden_linear_function.py +2 -2
  40. qiskit/circuit/library/iqp.py +2 -2
  41. qiskit/circuit/library/n_local/efficient_su2.py +2 -2
  42. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
  43. qiskit/circuit/library/n_local/excitation_preserving.py +7 -9
  44. qiskit/circuit/library/n_local/n_local.py +4 -3
  45. qiskit/circuit/library/n_local/pauli_two_design.py +2 -2
  46. qiskit/circuit/library/n_local/real_amplitudes.py +2 -2
  47. qiskit/circuit/library/n_local/two_local.py +2 -2
  48. qiskit/circuit/library/overlap.py +2 -2
  49. qiskit/circuit/library/pauli_evolution.py +3 -2
  50. qiskit/circuit/library/phase_estimation.py +2 -2
  51. qiskit/circuit/library/standard_gates/dcx.py +11 -12
  52. qiskit/circuit/library/standard_gates/ecr.py +21 -24
  53. qiskit/circuit/library/standard_gates/equivalence_library.py +232 -96
  54. qiskit/circuit/library/standard_gates/global_phase.py +5 -6
  55. qiskit/circuit/library/standard_gates/h.py +22 -45
  56. qiskit/circuit/library/standard_gates/i.py +1 -1
  57. qiskit/circuit/library/standard_gates/iswap.py +13 -31
  58. qiskit/circuit/library/standard_gates/p.py +19 -26
  59. qiskit/circuit/library/standard_gates/r.py +11 -17
  60. qiskit/circuit/library/standard_gates/rx.py +21 -45
  61. qiskit/circuit/library/standard_gates/rxx.py +7 -22
  62. qiskit/circuit/library/standard_gates/ry.py +21 -39
  63. qiskit/circuit/library/standard_gates/ryy.py +13 -28
  64. qiskit/circuit/library/standard_gates/rz.py +18 -35
  65. qiskit/circuit/library/standard_gates/rzx.py +7 -22
  66. qiskit/circuit/library/standard_gates/rzz.py +7 -19
  67. qiskit/circuit/library/standard_gates/s.py +44 -39
  68. qiskit/circuit/library/standard_gates/swap.py +25 -38
  69. qiskit/circuit/library/standard_gates/sx.py +34 -41
  70. qiskit/circuit/library/standard_gates/t.py +18 -27
  71. qiskit/circuit/library/standard_gates/u.py +8 -24
  72. qiskit/circuit/library/standard_gates/u1.py +28 -52
  73. qiskit/circuit/library/standard_gates/u2.py +9 -9
  74. qiskit/circuit/library/standard_gates/u3.py +24 -40
  75. qiskit/circuit/library/standard_gates/x.py +190 -336
  76. qiskit/circuit/library/standard_gates/xx_minus_yy.py +12 -50
  77. qiskit/circuit/library/standard_gates/xx_plus_yy.py +13 -52
  78. qiskit/circuit/library/standard_gates/y.py +19 -23
  79. qiskit/circuit/library/standard_gates/z.py +31 -38
  80. qiskit/circuit/parameter.py +14 -5
  81. qiskit/circuit/parameterexpression.py +109 -75
  82. qiskit/circuit/quantumcircuit.py +168 -98
  83. qiskit/circuit/quantumcircuitdata.py +1 -0
  84. qiskit/circuit/random/__init__.py +37 -2
  85. qiskit/circuit/random/utils.py +445 -56
  86. qiskit/circuit/tools/pi_check.py +5 -13
  87. qiskit/compiler/transpiler.py +1 -1
  88. qiskit/converters/circuit_to_instruction.py +2 -2
  89. qiskit/dagcircuit/dagnode.py +8 -3
  90. qiskit/primitives/__init__.py +2 -2
  91. qiskit/primitives/base/base_estimator.py +2 -2
  92. qiskit/primitives/containers/data_bin.py +0 -3
  93. qiskit/primitives/containers/observables_array.py +192 -108
  94. qiskit/primitives/primitive_job.py +29 -10
  95. qiskit/providers/fake_provider/generic_backend_v2.py +2 -0
  96. qiskit/qasm3/__init__.py +106 -12
  97. qiskit/qasm3/ast.py +15 -1
  98. qiskit/qasm3/exporter.py +59 -36
  99. qiskit/qasm3/printer.py +12 -0
  100. qiskit/qpy/__init__.py +183 -7
  101. qiskit/qpy/binary_io/circuits.py +256 -24
  102. qiskit/qpy/binary_io/parse_sympy_repr.py +5 -0
  103. qiskit/qpy/binary_io/schedules.py +12 -32
  104. qiskit/qpy/binary_io/value.py +36 -18
  105. qiskit/qpy/common.py +11 -3
  106. qiskit/qpy/formats.py +17 -1
  107. qiskit/qpy/interface.py +52 -12
  108. qiskit/qpy/type_keys.py +7 -1
  109. qiskit/quantum_info/__init__.py +10 -0
  110. qiskit/quantum_info/operators/__init__.py +1 -0
  111. qiskit/quantum_info/operators/symplectic/__init__.py +1 -0
  112. qiskit/quantum_info/operators/symplectic/clifford_circuits.py +26 -0
  113. qiskit/quantum_info/operators/symplectic/pauli.py +2 -2
  114. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +1 -1
  115. qiskit/result/sampled_expval.py +3 -1
  116. qiskit/synthesis/__init__.py +10 -0
  117. qiskit/synthesis/arithmetic/__init__.py +1 -1
  118. qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
  119. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
  120. qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
  121. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
  122. qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
  123. qiskit/synthesis/evolution/lie_trotter.py +10 -7
  124. qiskit/synthesis/evolution/product_formula.py +10 -7
  125. qiskit/synthesis/evolution/qdrift.py +10 -7
  126. qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
  127. qiskit/synthesis/multi_controlled/__init__.py +4 -0
  128. qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
  129. qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
  130. qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
  131. qiskit/synthesis/unitary/qsd.py +80 -9
  132. qiskit/transpiler/__init__.py +19 -8
  133. qiskit/transpiler/instruction_durations.py +2 -20
  134. qiskit/transpiler/passes/__init__.py +4 -2
  135. qiskit/transpiler/passes/layout/dense_layout.py +26 -6
  136. qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
  137. qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
  138. qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
  139. qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
  140. qiskit/transpiler/passes/layout/vf2_utils.py +13 -1
  141. qiskit/transpiler/passes/optimization/__init__.py +1 -1
  142. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
  143. qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
  144. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
  145. qiskit/transpiler/passes/routing/sabre_swap.py +12 -2
  146. qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
  147. qiskit/transpiler/passes/scheduling/__init__.py +1 -1
  148. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  149. qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
  150. qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
  151. qiskit/transpiler/passes/synthesis/__init__.py +1 -0
  152. qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
  153. qiskit/transpiler/passes/synthesis/hls_plugins.py +472 -92
  154. qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +27 -22
  155. qiskit/transpiler/passmanager_config.py +3 -0
  156. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +149 -28
  157. qiskit/transpiler/preset_passmanagers/common.py +101 -0
  158. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +6 -0
  159. qiskit/transpiler/preset_passmanagers/level3.py +2 -2
  160. qiskit/utils/optionals.py +6 -5
  161. qiskit/visualization/circuit/_utils.py +5 -3
  162. qiskit/visualization/circuit/latex.py +9 -2
  163. qiskit/visualization/circuit/matplotlib.py +26 -4
  164. qiskit/visualization/circuit/qcstyle.py +9 -157
  165. qiskit/visualization/dag/__init__.py +13 -0
  166. qiskit/visualization/dag/dagstyle.py +103 -0
  167. qiskit/visualization/dag/styles/__init__.py +13 -0
  168. qiskit/visualization/dag/styles/color.json +10 -0
  169. qiskit/visualization/dag/styles/plain.json +5 -0
  170. qiskit/visualization/dag_visualization.py +169 -98
  171. qiskit/visualization/style.py +223 -0
  172. {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/METADATA +14 -13
  173. {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/RECORD +177 -168
  174. {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/entry_points.txt +6 -0
  175. qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
  176. qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
  177. {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/WHEEL +0 -0
  178. {qiskit-2.0.2.dist-info → qiskit-2.1.0rc1.dist-info}/licenses/LICENSE.txt +0 -0
  179. {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.circuit import QuantumRegister
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
- RC3XGate,
25
- C3SXGate,
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 using :math:`k - 2`
36
- dirty ancillary qubits producing a circuit with :math:`2 * k - 1` qubits and at most
37
- :math:`8 * k - 6` CX gates, by Iten et. al. [1].
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
- if num_ctrl_qubits == 1:
57
- num_qubits = 2
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 - 8` CX gates, by Barenco et al. [1].
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
- qc_first_half = synth_mcx_n_dirty_i15(num_ctrl_qubits=len(first_half))
215
- qc_second_half = synth_mcx_n_dirty_i15(num_ctrl_qubits=len(second_half))
216
-
217
- qc.append(
218
- qc_first_half,
219
- qargs=[*first_half, q_ancilla, *q[middle : middle + len(first_half) - 2]],
220
- cargs=[],
221
- )
222
- qc.append(
223
- qc_second_half,
224
- qargs=[*second_half, q_target, *q[: len(second_half) - 2]],
225
- cargs=[],
226
- )
227
- qc.append(
228
- qc_first_half,
229
- qargs=[*first_half, q_ancilla, *q[middle : middle + len(first_half) - 2]],
230
- cargs=[],
231
- )
232
- qc.append(
233
- qc_second_half,
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
- qc._append(MCU1Gate(np.pi, num_ctrl_qubits=num_ctrl_qubits), q[:], [])
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
- if num_ctrl_qubits == 3:
287
- return synth_c3x()
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
- num_qubits = num_ctrl_qubits + 1
293
- q = QuantumRegister(num_qubits, name="q")
294
- qc = QuantumCircuit(q)
295
- q_controls = list(range(num_ctrl_qubits))
296
- q_target = num_ctrl_qubits
297
- qc.h(q_target)
298
- qc.mcp(np.pi, q_controls, q_target)
299
- qc.h(q_target)
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 synth_c3x() -> QuantumCircuit:
304
- """Efficient synthesis of 3-controlled X-gate."""
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 synth_c4x() -> QuantumCircuit:
340
- """Efficient synthesis of 4-controlled X-gate."""
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
- q = QuantumRegister(5, name="q")
343
- qc = QuantumCircuit(q, name="mcx")
344
-
345
- rules = [
346
- (HGate(), [q[4]], []),
347
- (CU1Gate(np.pi / 2), [q[3], q[4]], []),
348
- (HGate(), [q[4]], []),
349
- (RC3XGate(), [q[0], q[1], q[2], q[3]], []),
350
- (HGate(), [q[4]], []),
351
- (CU1Gate(-np.pi / 2), [q[3], q[4]], []),
352
- (HGate(), [q[4]], []),
353
- (RC3XGate().inverse(), [q[0], q[1], q[2], q[3]], []),
354
- (C3SXGate(), [q[0], q[1], q[2], q[4]], []),
355
- ]
356
- for instr, qargs, cargs in rules:
357
- qc._append(instr, qargs, cargs)
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())