qiskit 2.0.3__cp39-abi3-macosx_11_0_arm64.whl → 2.1.0__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 (180) 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 +104 -20
  5. qiskit/circuit/_add_control.py +57 -31
  6. qiskit/circuit/_classical_resource_map.py +4 -0
  7. qiskit/circuit/annotation.py +504 -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 +4 -4
  15. qiskit/circuit/library/arithmetic/multipliers/multiplier.py +2 -2
  16. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +8 -4
  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 +172 -99
  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 +182 -6
  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/result/sampled_expval.py +3 -1
  115. qiskit/synthesis/__init__.py +10 -0
  116. qiskit/synthesis/arithmetic/__init__.py +1 -1
  117. qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
  118. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
  119. qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
  120. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
  121. qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
  122. qiskit/synthesis/evolution/lie_trotter.py +10 -7
  123. qiskit/synthesis/evolution/product_formula.py +10 -7
  124. qiskit/synthesis/evolution/qdrift.py +10 -7
  125. qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
  126. qiskit/synthesis/multi_controlled/__init__.py +4 -0
  127. qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
  128. qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
  129. qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
  130. qiskit/synthesis/unitary/qsd.py +80 -9
  131. qiskit/transpiler/__init__.py +10 -3
  132. qiskit/transpiler/instruction_durations.py +2 -20
  133. qiskit/transpiler/passes/__init__.py +5 -2
  134. qiskit/transpiler/passes/layout/dense_layout.py +26 -6
  135. qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
  136. qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
  137. qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
  138. qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
  139. qiskit/transpiler/passes/layout/vf2_utils.py +10 -0
  140. qiskit/transpiler/passes/optimization/__init__.py +1 -1
  141. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
  142. qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
  143. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
  144. qiskit/transpiler/passes/routing/sabre_swap.py +4 -2
  145. qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
  146. qiskit/transpiler/passes/scheduling/__init__.py +1 -1
  147. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  148. qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
  149. qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
  150. qiskit/transpiler/passes/synthesis/__init__.py +1 -0
  151. qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
  152. qiskit/transpiler/passes/synthesis/hls_plugins.py +494 -93
  153. qiskit/transpiler/passes/synthesis/plugin.py +4 -0
  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/transpiler/target.py +15 -2
  161. qiskit/utils/optionals.py +6 -5
  162. qiskit/visualization/circuit/_utils.py +5 -3
  163. qiskit/visualization/circuit/latex.py +9 -2
  164. qiskit/visualization/circuit/matplotlib.py +26 -4
  165. qiskit/visualization/circuit/qcstyle.py +9 -157
  166. qiskit/visualization/dag/__init__.py +13 -0
  167. qiskit/visualization/dag/dagstyle.py +103 -0
  168. qiskit/visualization/dag/styles/__init__.py +13 -0
  169. qiskit/visualization/dag/styles/color.json +10 -0
  170. qiskit/visualization/dag/styles/plain.json +5 -0
  171. qiskit/visualization/dag_visualization.py +169 -98
  172. qiskit/visualization/style.py +223 -0
  173. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/METADATA +7 -6
  174. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/RECORD +178 -169
  175. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/entry_points.txt +6 -0
  176. qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
  177. qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
  178. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/WHEEL +0 -0
  179. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/licenses/LICENSE.txt +0 -0
  180. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/top_level.txt +0 -0
@@ -171,30 +171,29 @@ def _mcsu2_real_diagonal(
171
171
  k_1 = math.ceil(num_controls / 2.0)
172
172
  k_2 = math.floor(num_controls / 2.0)
173
173
 
174
- circuit = QuantumCircuit(num_controls + 1, name="MCSU2")
175
174
  controls = list(range(num_controls)) # control indices, defined for code legibility
176
175
  target = num_controls # target index, defined for code legibility
177
176
 
177
+ mcx1 = synth_mcx_n_dirty_i15(num_ctrl_qubits=k_1)
178
+ mcx1_num_ancillas = mcx1.num_qubits - k_1 - 1
179
+ mcx1_qubits = controls[:k_1] + [target] + controls[k_1 : k_1 + mcx1_num_ancillas]
180
+
181
+ mcx2 = synth_mcx_n_dirty_i15(num_ctrl_qubits=k_2)
182
+ mcx2_num_ancillas = mcx2.num_qubits - k_2 - 1
183
+ mcx2_qubits = controls[k_1:] + [target] + controls[k_1 - mcx2_num_ancillas : k_1]
184
+
185
+ circuit = QuantumCircuit(num_controls + 1, name="MCSU2")
186
+
178
187
  if not is_secondary_diag_real:
179
188
  circuit.h(target)
180
189
 
181
- mcx_1 = synth_mcx_n_dirty_i15(num_ctrl_qubits=k_1)
182
- circuit.compose(mcx_1, controls[:k_1] + [target] + controls[k_1 : 2 * k_1 - 2], inplace=True)
190
+ circuit.compose(mcx1, mcx1_qubits, inplace=True)
183
191
  circuit.append(s_gate, [target])
184
-
185
- # TODO: improve CX count by using action_only=True (based on #9687)
186
- mcx_2 = synth_mcx_n_dirty_i15(num_ctrl_qubits=k_2).to_gate()
187
- circuit.compose(
188
- mcx_2.inverse(), controls[k_1:] + [target] + controls[k_1 - k_2 + 2 : k_1], inplace=True
189
- )
192
+ circuit.compose(mcx2, mcx2_qubits, inplace=True)
190
193
  circuit.append(s_gate.inverse(), [target])
191
-
192
- mcx_3 = synth_mcx_n_dirty_i15(num_ctrl_qubits=k_1).to_gate()
193
- circuit.compose(mcx_3, controls[:k_1] + [target] + controls[k_1 : 2 * k_1 - 2], inplace=True)
194
+ circuit.compose(mcx1, mcx1_qubits, inplace=True)
194
195
  circuit.append(s_gate, [target])
195
-
196
- mcx_4 = synth_mcx_n_dirty_i15(num_ctrl_qubits=k_2).to_gate()
197
- circuit.compose(mcx_4, controls[k_1:] + [target] + controls[k_1 - k_2 + 2 : k_1], inplace=True)
196
+ circuit.compose(mcx2, mcx2_qubits, inplace=True)
198
197
  circuit.append(s_gate.inverse(), [target])
199
198
 
200
199
  if not is_secondary_diag_real:
@@ -13,9 +13,9 @@
13
13
  Circuit synthesis for a QFT circuit.
14
14
  """
15
15
 
16
- import numpy as np
17
16
  from qiskit.circuit import QuantumCircuit
18
- from qiskit.synthesis.permutation.permutation_reverse_lnn import _append_reverse_permutation_lnn_kms
17
+ from qiskit._accelerate.synthesis.qft import synth_qft_line as _synth_qft_line
18
+
19
19
  from .qft_decompose_full import _warn_if_precision_loss
20
20
 
21
21
 
@@ -53,27 +53,9 @@ def synth_qft_line(
53
53
  `arXiv:quant-ph/0402196 [quant-ph] <https://arxiv.org/abs/quant-ph/0402196>`_
54
54
  """
55
55
  _warn_if_precision_loss(num_qubits - approximation_degree - 1)
56
- qc = QuantumCircuit(num_qubits)
57
-
58
- for i in range(num_qubits):
59
- qc.h(num_qubits - 1)
60
-
61
- for j in range(i, num_qubits - 1):
62
- if j - i + 2 < num_qubits - approximation_degree + 1:
63
- qc.p(np.pi / 2 ** (j - i + 2), num_qubits - j + i - 1)
64
- qc.cx(num_qubits - j + i - 1, num_qubits - j + i - 2)
65
- qc.p(-np.pi / 2 ** (j - i + 2), num_qubits - j + i - 2)
66
- qc.cx(num_qubits - j + i - 2, num_qubits - j + i - 1)
67
- qc.cx(num_qubits - j + i - 1, num_qubits - j + i - 2)
68
- qc.p(np.pi / 2 ** (j - i + 2), num_qubits - j + i - 1)
69
- else:
70
- qc.cx(num_qubits - j + i - 1, num_qubits - j + i - 2)
71
- qc.cx(num_qubits - j + i - 2, num_qubits - j + i - 1)
72
- qc.cx(num_qubits - j + i - 1, num_qubits - j + i - 2)
73
-
74
- if not do_swaps:
75
- # Add a reversal network for LNN connectivity in depth 2*n+2,
76
- # based on Kutin at al., https://arxiv.org/abs/quant-ph/0701194, Section 5.
77
- _append_reverse_permutation_lnn_kms(qc, num_qubits)
78
56
 
79
- return qc
57
+ return QuantumCircuit._from_circuit_data(
58
+ # From rust
59
+ _synth_qft_line(num_qubits, do_swaps, approximation_degree),
60
+ add_regs=True,
61
+ )
@@ -15,7 +15,6 @@ Quantum Shannon Decomposition.
15
15
  Method is described in arXiv:quant-ph/0406176.
16
16
  """
17
17
  from __future__ import annotations
18
- import math
19
18
  from typing import Callable
20
19
  import scipy
21
20
  import numpy as np
@@ -31,6 +30,7 @@ from qiskit.circuit.library.generalized_gates.uc_pauli_rot import UCPauliRotGate
31
30
  from qiskit.circuit.library.generalized_gates.ucry import UCRYGate
32
31
  from qiskit.circuit.library.generalized_gates.ucrz import UCRZGate
33
32
  from qiskit._accelerate.two_qubit_decompose import two_qubit_decompose_up_to_diagonal
33
+ from qiskit._accelerate.cos_sin_decomp import cossin
34
34
 
35
35
 
36
36
  def qs_decomposition(
@@ -96,7 +96,8 @@ def qs_decomposition(
96
96
  """
97
97
  # _depth (int): Internal use parameter to track recursion depth.
98
98
  dim = mat.shape[0]
99
- nqubits = int(math.log2(dim))
99
+ nqubits = dim.bit_length() - 1
100
+
100
101
  if np.allclose(np.identity(dim), mat):
101
102
  return QuantumCircuit(nqubits)
102
103
  if dim == 2:
@@ -121,11 +122,25 @@ def qs_decomposition(
121
122
  decomposer_2q = TwoQubitBasisDecomposer(CXGate())
122
123
  circ = decomposer_2q(mat)
123
124
  else:
125
+ # check whether matrix is equivalent to block diagonal wrt ctrl_index
126
+ if opt_a2 is False:
127
+ for ctrl_index in range(nqubits):
128
+ um00, um11, um01, um10 = _extract_multiplex_blocks(mat, ctrl_index)
129
+ # the ctrl_index is reversed here
130
+ if _off_diagonals_are_zero(um01, um10):
131
+ decirc = _demultiplex(
132
+ um00,
133
+ um11,
134
+ opt_a1=opt_a1,
135
+ opt_a2=opt_a2,
136
+ _depth=_depth,
137
+ _ctrl_index=nqubits - 1 - ctrl_index,
138
+ )
139
+ return decirc
124
140
  qr = QuantumRegister(nqubits)
125
141
  circ = QuantumCircuit(qr)
126
- dim_o2 = dim // 2
127
142
  # perform cosine-sine decomposition
128
- (u1, u2), vtheta, (v1h, v2h) = scipy.linalg.cossin(mat, separate=True, p=dim_o2, q=dim_o2)
143
+ (u1, u2), vtheta, (v1h, v2h) = cossin(np.asarray(mat, dtype=complex))
129
144
  # left circ
130
145
  left_circ = _demultiplex(v1h, v2h, opt_a1=opt_a1, opt_a2=opt_a2, _depth=_depth)
131
146
  circ.append(left_circ.to_instruction(), qr)
@@ -150,7 +165,7 @@ def qs_decomposition(
150
165
  return circ
151
166
 
152
167
 
153
- def _demultiplex(um0, um1, opt_a1=False, opt_a2=False, *, _depth=0):
168
+ def _demultiplex(um0, um1, opt_a1=False, opt_a2=False, *, _depth=0, _ctrl_index=None):
154
169
  """Decompose a generic multiplexer.
155
170
 
156
171
  ────□────
@@ -183,12 +198,17 @@ def _demultiplex(um0, um1, opt_a1=False, opt_a2=False, *, _depth=0):
183
198
  unitaries into a diagonal gate and a two cx unitary and reduces overall cx count by
184
199
  4^(n-2) - 1.
185
200
  _depth (int): This is an internal variable to track the recursion depth.
201
+ _ctrl_index (int): The index wrt which um0 and um1 are controlled.
186
202
 
187
203
  Returns:
188
204
  QuantumCircuit: decomposed circuit
189
205
  """
190
206
  dim = um0.shape[0] + um1.shape[0] # these should be same dimension
191
- nqubits = int(math.log2(dim))
207
+ nqubits = dim.bit_length() - 1
208
+ if _ctrl_index is None:
209
+ _ctrl_index = nqubits - 1
210
+ layout = list(range(0, _ctrl_index)) + list(range(_ctrl_index + 1, nqubits)) + [_ctrl_index]
211
+
192
212
  um0um1 = um0 @ um1.T.conjugate()
193
213
  if is_hermitian_matrix(um0um1):
194
214
  eigvals, vmat = scipy.linalg.eigh(um0um1)
@@ -205,18 +225,18 @@ def _demultiplex(um0, um1, opt_a1=False, opt_a2=False, *, _depth=0):
205
225
  left_gate = qs_decomposition(
206
226
  wmat, opt_a1=opt_a1, opt_a2=opt_a2, _depth=_depth + 1
207
227
  ).to_instruction()
208
- circ.append(left_gate, range(nqubits - 1))
228
+ circ.append(left_gate, layout[: nqubits - 1])
209
229
 
210
230
  # multiplexed Rz
211
231
  angles = 2 * np.angle(np.conj(dvals))
212
232
  ucrz = UCRZGate(angles.tolist())
213
- circ.append(ucrz, [nqubits - 1] + list(range(nqubits - 1)))
233
+ circ.append(ucrz, [layout[-1]] + layout[: nqubits - 1])
214
234
 
215
235
  # right gate
216
236
  right_gate = qs_decomposition(
217
237
  vmat, opt_a1=opt_a1, opt_a2=opt_a2, _depth=_depth + 1
218
238
  ).to_instruction()
219
- circ.append(right_gate, range(nqubits - 1))
239
+ circ.append(right_gate, layout[: nqubits - 1])
220
240
 
221
241
  return circ
222
242
 
@@ -286,3 +306,54 @@ def _apply_a2(circ):
286
306
  qc3 = two_qubit_decompose.two_qubit_cnot_decompose(mat2)
287
307
  ccirc.data[ind2] = ccirc.data[ind2].replace(operation=qc3.to_gate())
288
308
  return ccirc
309
+
310
+
311
+ def _extract_multiplex_blocks(umat, k):
312
+ """
313
+ A block diagonal gate is represented as:
314
+ [ um00 | um01 ]
315
+ [ ---- | ---- ]
316
+ [ um10 | um11 ]
317
+ Args:
318
+ umat (ndarray): unitary matrix
319
+ k (integer): qubit which indicates the ctrl index
320
+ Returns:
321
+ um00 (ndarray): upper left block
322
+ um01 (ndarray): upper right block
323
+ um10 (ndarray): lower left block
324
+ um11 (ndarray): lower right block
325
+ """
326
+ dim = umat.shape[0]
327
+ nqubits = dim.bit_length() - 1
328
+ halfdim = dim // 2
329
+
330
+ utensor = umat.reshape((2,) * (2 * nqubits))
331
+
332
+ # Move qubit k to top
333
+ if k != 0:
334
+ utensor = np.moveaxis(utensor, k, 0)
335
+ utensor = np.moveaxis(utensor, k + nqubits, nqubits)
336
+
337
+ # reshape for extraction
338
+ ud4 = utensor.reshape(2, halfdim, 2, halfdim)
339
+ # block for qubit k = |0>
340
+ um00 = ud4[0, :, 0, :]
341
+ # block for qubit k = |1>
342
+ um11 = ud4[1, :, 1, :]
343
+ # off diagonal blocks
344
+ um01 = ud4[0, :, 1, :]
345
+ um10 = ud4[1, :, 0, :]
346
+ return um00, um11, um01, um10
347
+
348
+
349
+ def _off_diagonals_are_zero(um01, um10, atol=1e-12):
350
+ """
351
+ Checks whether off-diagonal blocks are zero.
352
+ Args:
353
+ um01 (ndarray): upper right block
354
+ um10 (ndarray): lower left block
355
+ atol (float): absolute tolerance
356
+ Returns:
357
+ bool: whether both blocks are zero within tolerance
358
+ """
359
+ return np.allclose(um01, 0, atol=atol) and np.allclose(um10, 0, atol=atol)
@@ -677,6 +677,9 @@ At a high level, this starts from the set of gates requested by the circuit, and
677
677
  given :class:`.EquivalenceLibrary` (typically the :data:`.SessionEquivalenceLibrary`) to move
678
678
  towards the ISA.
679
679
 
680
+ For a Clifford+T basis set, the single-qubit rotation gates are approximated using the
681
+ :class:`.SolovayKitaevDecomposition` algorithm.
682
+
680
683
  This is the default translation method.
681
684
 
682
685
  The optimization level has no effect on this plugin.
@@ -704,7 +707,7 @@ as a fix-up pipeline.
704
707
 
705
708
  Qiskit's built-in optimization plugins are general, and apply well to most real-world ISAs for
706
709
  non-error-corrected devices. The built-in plugins are less well-suited to ISAs that have no
707
- continuously parametrized single-qubit gate, such as a Clifford+T basis set.
710
+ continuously parametrized single-qubit gate.
708
711
 
709
712
  When writing :ref:`stage plugins <transpiler-preset-stage-plugins>`, the entry point for
710
713
  ``optimization`` is ``qiskit.transpiler.optimization``. The built-in plugins are:
@@ -724,10 +727,12 @@ When writing :ref:`stage plugins <transpiler-preset-stage-plugins>`, the entry p
724
727
  Built-in ``default`` plugin
725
728
  ...........................
726
729
 
727
- This varies significantly between optimization levels.
730
+ This varies significantly depending on the optimization level and whether the basis set is of the
731
+ form Clifford+T.
728
732
 
729
733
  The specifics of this pipeline are subject to change between Qiskit versions. The broad principles
730
- are described below.
734
+ are described below. First, consider the more common case that the basis set is not of the form
735
+ Clifford+T.
731
736
 
732
737
  At optimization level 0, the stage is empty.
733
738
 
@@ -744,6 +749,8 @@ The optimization loop condition also tries multiple runs and chooses the minimum
744
749
  of fluctuating output; this is necessary because matrix-based resynthesis is relatively unstable in
745
750
  terms of concrete gates.
746
751
 
752
+ For a Clifford+T basis set, two-qubit matrix based resynthesis is not applied.
753
+
747
754
  Optimization level 3 is typically very expensive for large circuits.
748
755
 
749
756
 
@@ -74,30 +74,12 @@ class InstructionDurations:
74
74
 
75
75
  Raises:
76
76
  TranspilerError: If dt and dtm is different in the backend.
77
+ TypeError: If the backend is the wrong type
77
78
  """
78
79
  # All durations in seconds in gate_length
79
80
  if isinstance(backend, BackendV2):
80
81
  return backend.target.durations()
81
-
82
- instruction_durations = []
83
- backend_properties = backend.properties()
84
- if hasattr(backend_properties, "_gates"):
85
- for gate, insts in backend_properties._gates.items():
86
- for qubits, props in insts.items():
87
- if "gate_length" in props:
88
- gate_length = props["gate_length"][0] # Throw away datetime at index 1
89
- instruction_durations.append((gate, qubits, gate_length, "s"))
90
- for q, props in backend.properties()._qubits.items():
91
- if "readout_length" in props:
92
- readout_length = props["readout_length"][0] # Throw away datetime at index 1
93
- instruction_durations.append(("measure", [q], readout_length, "s"))
94
-
95
- try:
96
- dt = backend.configuration().dt
97
- except AttributeError:
98
- dt = None
99
-
100
- return cls(instruction_durations, dt=dt)
82
+ raise TypeError("Unsupported backend type: {backend}")
101
83
 
102
84
  def update(self, inst_durations: "InstructionDurationsType" | None, dt: float = None):
103
85
  """Update self with inst_durations (inst_durations overwrite self).
@@ -91,7 +91,7 @@ Optimizations
91
91
  Split2QUnitaries
92
92
  RemoveIdentityEquivalent
93
93
  ContractIdleWiresInControlFlow
94
- LightCone
94
+ OptimizeCliffordT
95
95
 
96
96
  Scheduling
97
97
  =============
@@ -102,6 +102,7 @@ Scheduling
102
102
  TimeUnitConversion
103
103
  ALAPScheduleAnalysis
104
104
  ASAPScheduleAnalysis
105
+ ContextAwareDynamicalDecoupling
105
106
  PadDynamicalDecoupling
106
107
  PadDelay
107
108
  ConstrainedReschedule
@@ -226,7 +227,7 @@ from .optimization import OptimizeAnnotated
226
227
  from .optimization import RemoveIdentityEquivalent
227
228
  from .optimization import Split2QUnitaries
228
229
  from .optimization import ContractIdleWiresInControlFlow
229
- from .optimization import LightCone
230
+ from .optimization import OptimizeCliffordT
230
231
 
231
232
  # circuit analysis
232
233
  from .analysis import ResourceEstimation
@@ -246,6 +247,7 @@ from .synthesis import HighLevelSynthesis
246
247
  from .synthesis import HLSConfig
247
248
  from .synthesis import SolovayKitaev
248
249
  from .synthesis import SolovayKitaevSynthesis
250
+ from .synthesis import CliffordUnitarySynthesis
249
251
  from .synthesis import AQCSynthesisPlugin
250
252
 
251
253
  # circuit scheduling
@@ -257,6 +259,7 @@ from .scheduling import PadDelay
257
259
  from .scheduling import ConstrainedReschedule
258
260
  from .scheduling import InstructionDurationCheck
259
261
  from .scheduling import SetIOLatency
262
+ from .scheduling import ContextAwareDynamicalDecoupling
260
263
 
261
264
  # additional utility passes
262
265
  from .utils import CheckMap
@@ -19,7 +19,8 @@ import rustworkx
19
19
  from qiskit.transpiler.layout import Layout
20
20
  from qiskit.transpiler.basepasses import AnalysisPass
21
21
  from qiskit.transpiler.exceptions import TranspilerError
22
- from qiskit.transpiler.passes.layout import disjoint_utils
22
+ from qiskit.transpiler.target import Target
23
+ from qiskit._accelerate import disjoint_utils
23
24
 
24
25
  from qiskit._accelerate.dense_layout import best_subset
25
26
 
@@ -66,11 +67,30 @@ class DenseLayout(AnalysisPass):
66
67
  raise TranspilerError(
67
68
  "A coupling_map or target with constrained qargs is necessary to run the pass."
68
69
  )
69
- layout_components = disjoint_utils.run_pass_over_connected_components(
70
- dag,
71
- self.coupling_map if self.target is None else self.target,
72
- self._inner_run,
73
- )
70
+ if self.target is not None:
71
+ layout_components = disjoint_utils.run_pass_over_connected_components(
72
+ dag,
73
+ self.target,
74
+ self._inner_run,
75
+ )
76
+ if layout_components is None:
77
+ target = Target.from_configuration(
78
+ basis_gates=["u", "cx"], coupling_map=self.coupling_map
79
+ )
80
+ layout_components = disjoint_utils.run_pass_over_connected_components(
81
+ dag,
82
+ target,
83
+ self._inner_run,
84
+ )
85
+ else:
86
+ target = Target.from_configuration(
87
+ basis_gates=["u", "cx"], coupling_map=self.coupling_map
88
+ )
89
+ layout_components = disjoint_utils.run_pass_over_connected_components(
90
+ dag,
91
+ target,
92
+ self._inner_run,
93
+ )
74
94
  layout_mapping = {}
75
95
  for component in layout_components:
76
96
  layout_mapping.update(component)
@@ -12,143 +12,12 @@
12
12
 
13
13
  """This module contains common utils for disjoint coupling maps."""
14
14
  from __future__ import annotations
15
- from collections import defaultdict
16
- from typing import List, Callable, TypeVar, Dict, Union
17
- import uuid
15
+ from typing import Union
18
16
 
19
- import rustworkx as rx
20
- from qiskit.dagcircuit import DAGOpNode
21
-
22
- from qiskit.circuit import Qubit, Barrier, Clbit
23
17
  from qiskit.dagcircuit.dagcircuit import DAGCircuit
24
- from qiskit.dagcircuit.dagnode import DAGOutNode
25
18
  from qiskit.transpiler.coupling import CouplingMap
26
19
  from qiskit.transpiler.target import Target
27
20
  from qiskit.transpiler.exceptions import TranspilerError
28
- from qiskit.transpiler.passes.layout import vf2_utils
29
-
30
- T = TypeVar("T")
31
-
32
-
33
- def run_pass_over_connected_components(
34
- dag: DAGCircuit,
35
- components_source: Union[Target, CouplingMap],
36
- run_func: Callable[[DAGCircuit, CouplingMap], T],
37
- ) -> List[T]:
38
- """Run a transpiler pass inner function over mapped components."""
39
- if isinstance(components_source, Target):
40
- coupling_map = components_source.build_coupling_map(filter_idle_qubits=True)
41
- else:
42
- coupling_map = components_source
43
- cmap_components = coupling_map.connected_components()
44
- # If graph is connected we only need to run the pass once
45
- if len(cmap_components) == 1:
46
- if dag.num_qubits() > cmap_components[0].size():
47
- raise TranspilerError(
48
- "A connected component of the DAGCircuit is too large for any of the connected "
49
- "components in the coupling map."
50
- )
51
- return [run_func(dag, cmap_components[0])]
52
- dag_components = separate_dag(dag)
53
- mapped_components = map_components(dag_components, cmap_components)
54
- out_component_pairs = []
55
- for cmap_index, dags in mapped_components.items():
56
- # Take the first dag from the mapped dag components and then
57
- # compose it with any other dag components that are operating on the
58
- # same coupling map connected component. This results in a subcircuit
59
- # of possibly disjoint circuit components which we will run the layout
60
- # pass on.
61
- out_dag = dag_components[dags.pop()]
62
- for dag_index in dags:
63
- dag = dag_components[dag_index]
64
- out_dag.add_qubits(dag.qubits)
65
- out_dag.add_clbits(dag.clbits)
66
- for qreg in dag.qregs:
67
- out_dag.add_qreg(qreg)
68
- for creg in dag.cregs:
69
- out_dag.add_creg(creg)
70
- out_dag.compose(dag, qubits=dag.qubits, clbits=dag.clbits)
71
- out_component_pairs.append((out_dag, cmap_components[cmap_index]))
72
- res = [run_func(out_dag, cmap) for out_dag, cmap in out_component_pairs]
73
- return res
74
-
75
-
76
- def map_components(
77
- dag_components: List[DAGCircuit], cmap_components: List[CouplingMap]
78
- ) -> Dict[int, List[int]]:
79
- """Returns a map where the key is the index of each connected component in cmap_components and
80
- the value is a list of indices from dag_components which should be placed onto it."""
81
- free_qubits = {index: len(cmap.graph) for index, cmap in enumerate(cmap_components)}
82
- out_mapping = defaultdict(list)
83
-
84
- for dag_index, dag in sorted(
85
- enumerate(dag_components), key=lambda x: x[1].num_qubits(), reverse=True
86
- ):
87
- for cmap_index in sorted(
88
- range(len(cmap_components)), key=lambda index: free_qubits[index], reverse=True
89
- ):
90
- # TODO: Improve heuristic to involve connectivity and estimate
91
- # swap cost
92
- if dag.num_qubits() <= free_qubits[cmap_index]:
93
- out_mapping[cmap_index].append(dag_index)
94
- free_qubits[cmap_index] -= dag.num_qubits()
95
- break
96
- else:
97
- raise TranspilerError(
98
- "A connected component of the DAGCircuit is too large for any of the connected "
99
- "components in the coupling map."
100
- )
101
- return out_mapping
102
-
103
-
104
- def split_barriers(dag: DAGCircuit):
105
- """Mutate an input dag to split barriers into single qubit barriers."""
106
- for node in dag.op_nodes(Barrier):
107
- num_qubits = len(node.qargs)
108
- if num_qubits == 1:
109
- continue
110
- if node.label:
111
- barrier_uuid = f"{node.op.label}_uuid={uuid.uuid4()}"
112
- else:
113
- barrier_uuid = f"_none_uuid={uuid.uuid4()}"
114
- split_dag = DAGCircuit()
115
- split_dag.add_qubits([Qubit() for _ in range(num_qubits)])
116
- for i in range(num_qubits):
117
- split_dag.apply_operation_back(
118
- Barrier(1, label=barrier_uuid),
119
- qargs=(split_dag.qubits[i],),
120
- check=False,
121
- )
122
- dag.substitute_node_with_dag(node, split_dag)
123
-
124
-
125
- def combine_barriers(dag: DAGCircuit, retain_uuid: bool = True):
126
- """Mutate input dag to combine barriers with UUID labels into a single barrier."""
127
- qubit_indices = {bit: index for index, bit in enumerate(dag.qubits)}
128
- uuid_map: dict[str, DAGOpNode] = {}
129
- for node in dag.op_nodes(Barrier):
130
- if node.label:
131
- if "_uuid=" in node.label:
132
- barrier_uuid = node.label
133
- else:
134
- continue
135
- if barrier_uuid in uuid_map:
136
- other_node = uuid_map[barrier_uuid]
137
- num_qubits = len(other_node.qargs) + len(node.qargs)
138
- if not retain_uuid:
139
- if isinstance(node.label, str) and node.label.startswith("_none_uuid="):
140
- label = None
141
- elif isinstance(node.label, str) and "_uuid=" in node.label:
142
- label = "_uuid=".join(node.label.split("_uuid=")[:-1])
143
- else:
144
- label = barrier_uuid
145
- else:
146
- label = barrier_uuid
147
- new_op = Barrier(num_qubits, label=label)
148
- new_node = dag.replace_block_with_op([node, other_node], new_op, qubit_indices)
149
- uuid_map[barrier_uuid] = new_node
150
- else:
151
- uuid_map[barrier_uuid] = node
152
21
 
153
22
 
154
23
  def require_layout_isolated_to_component(
@@ -183,37 +52,3 @@ def require_layout_isolated_to_component(
183
52
  f"{dag.find_bit(inst.qargs[1]).index} needs to interact with the "
184
53
  f"qubit {dag.find_bit(inst.qargs[0]).index} and they belong to different components"
185
54
  )
186
-
187
-
188
- def separate_dag(dag: DAGCircuit) -> List[DAGCircuit]:
189
- """Separate a dag circuit into it's connected components."""
190
- # Split barriers into single qubit barriers before splitting connected components
191
- split_barriers(dag)
192
- im_graph, _, qubit_map, __ = vf2_utils.build_interaction_graph(dag)
193
- connected_components = rx.weakly_connected_components(im_graph)
194
- component_qubits = []
195
- for component in connected_components:
196
- component_qubits.append({qubit_map[x] for x in component})
197
-
198
- qubits = set(dag.qubits)
199
-
200
- decomposed_dags = []
201
- for dag_qubits in component_qubits:
202
- new_dag = dag.copy_empty_like()
203
- new_dag.remove_qubits(*qubits - dag_qubits)
204
- new_dag.global_phase = 0
205
- for node in dag.topological_op_nodes():
206
- if dag_qubits.issuperset(node.qargs):
207
- new_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
208
- idle_clbits = []
209
- for bit, node in new_dag.input_map.items():
210
- succ_node = next(new_dag.successors(node))
211
- if isinstance(succ_node, DAGOutNode) and isinstance(succ_node.wire, Clbit):
212
- idle_clbits.append(bit)
213
- new_dag.remove_clbits(*idle_clbits)
214
- combine_barriers(new_dag)
215
- decomposed_dags.append(new_dag)
216
- # Reverse split barriers on input dag to avoid leaking out internal transformations as
217
- # part of splitting
218
- combine_barriers(dag, retain_uuid=False)
219
- return decomposed_dags
@@ -29,11 +29,11 @@ from qiskit.transpiler.passes.layout.set_layout import SetLayout
29
29
  from qiskit.transpiler.passes.layout.full_ancilla_allocation import FullAncillaAllocation
30
30
  from qiskit.transpiler.passes.layout.enlarge_with_ancilla import EnlargeWithAncilla
31
31
  from qiskit.transpiler.passes.layout.apply_layout import ApplyLayout
32
- from qiskit.transpiler.passes.layout import disjoint_utils
33
32
  from qiskit.transpiler.passmanager import PassManager
34
33
  from qiskit.transpiler.layout import Layout
35
34
  from qiskit.transpiler.basepasses import TransformationPass
36
35
  from qiskit.transpiler.exceptions import TranspilerError
36
+ from qiskit._accelerate import disjoint_utils
37
37
  from qiskit._accelerate.nlayout import NLayout
38
38
  from qiskit._accelerate.sabre import sabre_layout_and_routing, Heuristic, NeighborTable, SetScaling
39
39
  from qiskit.transpiler.passes.routing.sabre_swap import _build_sabre_dag, _apply_sabre_result
@@ -267,7 +267,24 @@ class SabreLayout(TransformationPass):
267
267
  inner_run = functools.partial(
268
268
  self._inner_run, starting_layouts=self.property_set["sabre_starting_layouts"]
269
269
  )
270
- components = disjoint_utils.run_pass_over_connected_components(dag, target, inner_run)
270
+ if self.target is not None:
271
+ components = disjoint_utils.run_pass_over_connected_components(
272
+ dag, self.target, inner_run
273
+ )
274
+ # If components is None we can't build a coupling map from the target so we must have
275
+ # one provided:
276
+ if components is None:
277
+ temp_target = Target.from_configuration(
278
+ basis_gates=["u", "cx"], coupling_map=target
279
+ )
280
+ components = disjoint_utils.run_pass_over_connected_components(
281
+ dag, temp_target, inner_run
282
+ )
283
+ else:
284
+ temp_target = Target.from_configuration(basis_gates=["u", "cx"], coupling_map=target)
285
+ components = disjoint_utils.run_pass_over_connected_components(
286
+ dag, temp_target, inner_run
287
+ )
271
288
  self.property_set["layout"] = Layout(
272
289
  {
273
290
  component.dag.qubits[logic]: component.coupling_map.graph[phys]
@@ -413,9 +430,11 @@ class SabreLayout(TransformationPass):
413
430
  coupling_map.size(),
414
431
  original_qubit_indices,
415
432
  )
433
+ # In our defaults, the basic heuristic shouldn't scale by size; if it does, it's liable to
434
+ # get the algorithm stuck. See https://github.com/Qiskit/qiskit/pull/14458 for more.
416
435
  heuristic = (
417
436
  Heuristic(attempt_limit=10 * coupling_map.size())
418
- .with_basic(1.0, SetScaling.Size)
437
+ .with_basic(1.0, SetScaling.Constant)
419
438
  .with_lookahead(0.5, 20, SetScaling.Size)
420
439
  .with_decay(0.001, 5)
421
440
  )
@@ -116,7 +116,7 @@ class SabrePreLayout(AnalysisPass):
116
116
  augmented_map, augmented_error_map = self._add_extra_edges(cur_distance)
117
117
  pass_ = VF2Layout(
118
118
  augmented_map,
119
- seed=0,
119
+ seed=-1,
120
120
  max_trials=self.max_trials_vf2,
121
121
  call_limit=self.call_limit_vf2,
122
122
  )