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
@@ -361,6 +361,10 @@ Unitary Synthesis Plugins
361
361
  :no-inherited-members:
362
362
  :no-special-members:
363
363
 
364
+ .. automodule:: qiskit.transpiler.passes.synthesis.clifford_unitary_synth_plugin
365
+ :no-inherited-members:
366
+ :no-special-members:
367
+
364
368
 
365
369
  High Level Synthesis
366
370
  --------------------
@@ -29,9 +29,6 @@ from qiskit.converters import circuit_to_dag
29
29
  from qiskit.circuit.gate import Gate
30
30
  from qiskit.dagcircuit import DAGCircuit
31
31
  from qiskit.synthesis.discrete_basis.solovay_kitaev import SolovayKitaevDecomposition
32
- from qiskit.synthesis.discrete_basis.generate_basis_approximations import (
33
- generate_basic_approximations,
34
- )
35
32
  from qiskit.transpiler.basepasses import TransformationPass
36
33
  from qiskit.transpiler.passes.utils.control_flow import trivial_recurse
37
34
 
@@ -137,23 +134,35 @@ class SolovayKitaev(TransformationPass):
137
134
 
138
135
  def __init__(
139
136
  self,
140
- recursion_degree: int = 3,
137
+ recursion_degree: int = 5,
141
138
  basic_approximations: str | dict[str, np.ndarray] | None = None,
139
+ *,
140
+ basis_gates: list[str | Gate] | None = None,
141
+ depth: int = 12,
142
142
  ) -> None:
143
- """
143
+ r"""
144
144
  Args:
145
145
  recursion_degree: The recursion depth for the Solovay-Kitaev algorithm.
146
146
  A larger recursion depth increases the accuracy and length of the
147
147
  decomposition.
148
148
  basic_approximations: The basic approximations for the finding the best discrete
149
- decomposition at the root of the recursion. If a string, it specifies the ``.npy``
149
+ decomposition at the root of the recursion. If a string, it specifies the
150
150
  file to load the approximations from. If a dictionary, it contains
151
- ``{label: SO(3)-matrix}`` pairs. If None, a default based on the H, T and Tdg gates
152
- up to combinations of depth 10 is generated.
151
+ ``{label: SO(3)-matrix}`` pairs. If ``None``, a default based on the :math:`H`,
152
+ :math:`T` and :math:`T^\dagger` gates up to depth 16 is generated.
153
+ Note that if ``basic_approximations`` is passed, ``basis_gates`` and
154
+ ``depth`` cannot be set.
155
+ basis_gates: The basis gates used to build the net of basic approximations.
156
+ Defaults to ``["h", "t", "tdg"]``. This argument cannot be set if
157
+ ``basic_approximations`` is provided.
158
+ depth: The maximal gate depth used in basic approximations. This argument cannot be
159
+ set if ``basic_approximations`` is provided.
153
160
  """
154
161
  super().__init__()
155
162
  self.recursion_degree = recursion_degree
156
- self._sk = SolovayKitaevDecomposition(basic_approximations)
163
+ self._sk = SolovayKitaevDecomposition(
164
+ basic_approximations, basis_gates=basis_gates, depth=depth
165
+ )
157
166
 
158
167
  @trivial_recurse
159
168
  def run(self, dag: DAGCircuit) -> DAGCircuit:
@@ -169,7 +178,6 @@ class SolovayKitaev(TransformationPass):
169
178
  TranspilerError: if a gates does not have to_matrix
170
179
  """
171
180
  for node in dag.op_nodes():
172
-
173
181
  # ignore operations on which the algorithm cannot run
174
182
  if (
175
183
  (node.op.num_qubits != 1)
@@ -182,11 +190,9 @@ class SolovayKitaev(TransformationPass):
182
190
  # we know it will generate a valid SU(2) matrix
183
191
  check_input = not isinstance(node.op, Gate)
184
192
 
185
- matrix = node.op.to_matrix()
186
-
187
193
  # call solovay kitaev
188
194
  approximation = self._sk.run(
189
- matrix, self.recursion_degree, return_dag=True, check_input=check_input
195
+ node.op, self.recursion_degree, return_dag=True, check_input=check_input
190
196
  )
191
197
 
192
198
  # convert to a dag and replace the gate by the approximation
@@ -221,12 +227,12 @@ class SolovayKitaevSynthesis(UnitarySynthesisPlugin):
221
227
 
222
228
  depth (int):
223
229
  The gate-depth of the basic approximations. All possible, unique combinations of the
224
- basis gates up to length ``depth`` are considered. If None, defaults to 10.
230
+ basis gates up to length ``depth`` are considered. If None, defaults to 12.
225
231
  If ``basic_approximations`` is not None, ``depth`` is required to correspond to the
226
232
  depth that was used to generate it.
227
233
 
228
234
  recursion_degree (int):
229
- The number of times the decomposition is recursively improved. If None, defaults to 3.
235
+ The number of times the decomposition is recursively improved. If None, defaults to 5.
230
236
  """
231
237
 
232
238
  # Generating basic approximations of single-qubit gates is computationally expensive.
@@ -292,10 +298,10 @@ class SolovayKitaevSynthesis(UnitarySynthesisPlugin):
292
298
  """Run the SolovayKitaevSynthesis synthesis plugin on the given unitary."""
293
299
 
294
300
  config = options.get("config") or {}
295
- basis_gates = options.get("basis_gates", ["h", "t", "tdg"])
296
- depth = config.get("depth", 10)
301
+ basis_gates = options.get("basis_gates", None)
302
+ depth = config.get("depth", 12)
297
303
  basic_approximations = config.get("basic_approximations", None)
298
- recursion_degree = config.get("recursion_degree", 3)
304
+ recursion_degree = config.get("recursion_degree", 5)
299
305
 
300
306
  # Check if we didn't yet construct the Solovay-Kitaev instance (which contains the basic
301
307
  # approximations) or if the basic approximations need need to be recomputed.
@@ -303,11 +309,10 @@ class SolovayKitaevSynthesis(UnitarySynthesisPlugin):
303
309
  (basis_gates != SolovayKitaevSynthesis._basis_gates)
304
310
  or (depth != SolovayKitaevSynthesis._depth)
305
311
  ):
306
- if basic_approximations is None:
307
- basic_approximations = generate_basic_approximations(basis_gates, depth)
308
-
309
312
  SolovayKitaevSynthesis._basis_gates = basis_gates
310
313
  SolovayKitaevSynthesis._depth = depth
311
- SolovayKitaevSynthesis._sk = SolovayKitaevDecomposition(basic_approximations)
314
+ SolovayKitaevSynthesis._sk = SolovayKitaevDecomposition(
315
+ basic_approximations, basis_gates=basis_gates, depth=depth
316
+ )
312
317
  approximate_circuit = SolovayKitaevSynthesis._sk.run(unitary, recursion_degree)
313
318
  return circuit_to_dag(approximate_circuit)
@@ -95,6 +95,9 @@ class PassManagerConfig:
95
95
  self.target = target
96
96
  self.hls_config = hls_config
97
97
  self.qubits_initially_zero = qubits_initially_zero
98
+ # Stores whether the basis gates are Clifford+T,
99
+ # in which case we use stage manager plugins adapted to Clifford+T.
100
+ self._is_clifford_t = False
98
101
 
99
102
  @classmethod
100
103
  def from_backend(cls, backend, _skip_target=False, **pass_manager_options):
@@ -14,6 +14,7 @@
14
14
 
15
15
  import os
16
16
 
17
+ from qiskit.transpiler.passes.layout.vf2_post_layout import VF2PostLayout
17
18
  from qiskit.transpiler.passes.optimization.split_2q_unitaries import Split2QUnitaries
18
19
  from qiskit.transpiler.passmanager import PassManager
19
20
  from qiskit.transpiler.exceptions import TranspilerError
@@ -30,6 +31,8 @@ from qiskit.transpiler.passes import CheckMap
30
31
  from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements
31
32
  from qiskit.transpiler.passes import ElidePermutations
32
33
  from qiskit.transpiler.passes import RemoveDiagonalGatesBeforeMeasure
34
+ from qiskit.transpiler.passes import OptimizeCliffordT
35
+ from qiskit.transpiler.passes import BasisTranslator
33
36
  from qiskit.transpiler.preset_passmanagers import common
34
37
  from qiskit.transpiler.preset_passmanagers.plugin import (
35
38
  PassManagerStagePlugin,
@@ -66,6 +69,7 @@ from qiskit.circuit.library.standard_gates import (
66
69
  SXGate,
67
70
  SXdgGate,
68
71
  )
72
+ from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel
69
73
  from qiskit.utils import default_num_processes
70
74
  from qiskit import user_config
71
75
 
@@ -86,6 +90,7 @@ class DefaultInitPassManager(PassManagerStagePlugin):
86
90
  """Plugin class for default init stage."""
87
91
 
88
92
  def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager:
93
+
89
94
  if optimization_level == 0:
90
95
  init = None
91
96
  if (
@@ -186,7 +191,12 @@ class DefaultInitPassManager(PassManagerStagePlugin):
186
191
  ]
187
192
  )
188
193
  init.append(CommutativeCancellation())
189
- init.append(ConsolidateBlocks())
194
+
195
+ # We do not want to consolidate blocks for a Clifford+T basis set,
196
+ # since this involves resynthesizing 2-qubit unitaries.
197
+ if not pass_manager_config._is_clifford_t:
198
+ init.append(ConsolidateBlocks())
199
+
190
200
  # If approximation degree is None that indicates a request to approximate up to the
191
201
  # error rates in the target. However, in the init stage we don't yet know the target
192
202
  # qubits being used to figure out the fidelity so just use the default fidelity parameter
@@ -215,6 +225,7 @@ class DefaultTranslationPassManager(PassManagerStagePlugin):
215
225
  # future if we want to change the default method to do more context-aware switching, or to
216
226
  # start transitioning the default method without breaking the semantics of the default
217
227
  # string referring to the `BasisTranslator`.
228
+
218
229
  return BasisTranslatorPassManager().pass_manager(pass_manager_config, optimization_level)
219
230
 
220
231
 
@@ -222,10 +233,14 @@ class BasisTranslatorPassManager(PassManagerStagePlugin):
222
233
  """Plugin class for translation stage with :class:`~.BasisTranslator`"""
223
234
 
224
235
  def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager:
236
+ if pass_manager_config._is_clifford_t:
237
+ method = "clifford_t"
238
+ else:
239
+ method = "translator"
225
240
  return common.generate_translation_passmanager(
226
241
  pass_manager_config.target,
227
242
  basis_gates=pass_manager_config.basis_gates,
228
- method="translator",
243
+ method=method,
229
244
  approximation_degree=pass_manager_config.approximation_degree,
230
245
  coupling_map=pass_manager_config.coupling_map,
231
246
  unitary_synthesis_method=pass_manager_config.unitary_synthesis_method,
@@ -496,6 +511,13 @@ class OptimizationPassManager(PassManagerStagePlugin):
496
511
 
497
512
  def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager:
498
513
  """Build pass manager for optimization stage."""
514
+
515
+ # Use the dedicated plugin for the Clifford+T basis when appropriate.
516
+ if pass_manager_config._is_clifford_t:
517
+ return CliffordTOptimizationPassManager().pass_manager(
518
+ pass_manager_config, optimization_level
519
+ )
520
+
499
521
  # Obtain the translation method required for this pass to work
500
522
  translation_method = pass_manager_config.translation_method or "default"
501
523
  optimization = PassManager()
@@ -646,6 +668,23 @@ class OptimizationPassManager(PassManagerStagePlugin):
646
668
  else _opt + _unroll_if_out_of_basis + _depth_check + _size_check
647
669
  )
648
670
  optimization.append(DoWhileController(opt_loop, do_while=_opt_control))
671
+
672
+ if optimization_level == 3 and pass_manager_config.coupling_map:
673
+ vf2_call_limit, vf2_max_trials = common.get_vf2_limits(
674
+ optimization_level,
675
+ pass_manager_config.layout_method,
676
+ pass_manager_config.initial_layout,
677
+ )
678
+ optimization.append(
679
+ VF2PostLayout(
680
+ target=pass_manager_config.target,
681
+ seed=-1,
682
+ call_limit=vf2_call_limit,
683
+ max_trials=vf2_max_trials,
684
+ strict_direction=True,
685
+ )
686
+ )
687
+
649
688
  return optimization
650
689
  else:
651
690
  return None
@@ -736,13 +775,18 @@ class DefaultLayoutPassManager(PassManagerStagePlugin):
736
775
  layout = PassManager()
737
776
  layout.append(_given_layout)
738
777
  if optimization_level == 0:
739
- layout.append(
740
- ConditionalController(
741
- TrivialLayout(coupling_map), condition=_choose_layout_condition
778
+ if coupling_map is not None:
779
+ layout.append(
780
+ ConditionalController(
781
+ TrivialLayout(coupling_map), condition=_choose_layout_condition
782
+ )
742
783
  )
743
- )
744
784
  layout += common.generate_embed_passmanager(coupling_map)
745
785
  return layout
786
+
787
+ if coupling_map is None:
788
+ # There's nothing to lay out onto. We only need to embed the initial layout, if given.
789
+ pass
746
790
  elif optimization_level == 1:
747
791
  layout.append(
748
792
  ConditionalController(
@@ -870,9 +914,12 @@ class TrivialLayoutPassManager(PassManagerStagePlugin):
870
914
 
871
915
  layout = PassManager()
872
916
  layout.append(_given_layout)
873
- layout.append(
874
- ConditionalController(TrivialLayout(coupling_map), condition=_choose_layout_condition)
875
- )
917
+ if coupling_map is not None:
918
+ layout.append(
919
+ ConditionalController(
920
+ TrivialLayout(coupling_map), condition=_choose_layout_condition
921
+ )
922
+ )
876
923
  layout += common.generate_embed_passmanager(coupling_map)
877
924
  return layout
878
925
 
@@ -893,15 +940,16 @@ class DenseLayoutPassManager(PassManagerStagePlugin):
893
940
 
894
941
  layout = PassManager()
895
942
  layout.append(_given_layout)
896
- layout.append(
897
- ConditionalController(
898
- DenseLayout(
899
- coupling_map=pass_manager_config.coupling_map,
900
- target=pass_manager_config.target,
901
- ),
902
- condition=_choose_layout_condition,
943
+ if coupling_map is not None:
944
+ layout.append(
945
+ ConditionalController(
946
+ DenseLayout(
947
+ coupling_map=pass_manager_config.coupling_map,
948
+ target=pass_manager_config.target,
949
+ ),
950
+ condition=_choose_layout_condition,
951
+ )
903
952
  )
904
- )
905
953
  layout += common.generate_embed_passmanager(coupling_map)
906
954
  return layout
907
955
 
@@ -925,7 +973,9 @@ class SabreLayoutPassManager(PassManagerStagePlugin):
925
973
 
926
974
  layout = PassManager()
927
975
  layout.append(_given_layout)
928
- if optimization_level == 0:
976
+ if coupling_map is None:
977
+ layout_pass = None
978
+ elif optimization_level == 0:
929
979
  trial_count = _get_trial_count(5)
930
980
 
931
981
  layout_pass = SabreLayout(
@@ -971,17 +1021,18 @@ class SabreLayoutPassManager(PassManagerStagePlugin):
971
1021
  )
972
1022
  else:
973
1023
  raise TranspilerError(f"Invalid optimization level: {optimization_level}")
974
- layout.append(
975
- ConditionalController(
976
- [
977
- BarrierBeforeFinalMeasurements(
978
- "qiskit.transpiler.internal.routing.protection.barrier"
979
- ),
980
- layout_pass,
981
- ],
982
- condition=_choose_layout_condition,
1024
+ if layout_pass is not None:
1025
+ layout.append(
1026
+ ConditionalController(
1027
+ [
1028
+ BarrierBeforeFinalMeasurements(
1029
+ "qiskit.transpiler.internal.routing.protection.barrier"
1030
+ ),
1031
+ layout_pass,
1032
+ ],
1033
+ condition=_choose_layout_condition,
1034
+ )
983
1035
  )
984
- )
985
1036
  embed = common.generate_embed_passmanager(coupling_map)
986
1037
  layout.append(ConditionalController(embed.to_flow_controller(), condition=_swap_mapped))
987
1038
  return layout
@@ -991,3 +1042,73 @@ def _get_trial_count(default_trials=5):
991
1042
  if CONFIG.get("sabre_all_threads", None) or os.getenv("QISKIT_SABRE_ALL_THREADS"):
992
1043
  return max(default_num_processes(), default_trials)
993
1044
  return default_trials
1045
+
1046
+
1047
+ class CliffordTOptimizationPassManager(PassManagerStagePlugin):
1048
+ """Plugin class for optimization stage"""
1049
+
1050
+ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager:
1051
+ """Build pass manager for optimization stage."""
1052
+
1053
+ # Obtain the translation method required for this pass to work
1054
+ optimization = PassManager()
1055
+ if optimization_level != 0:
1056
+ _depth_check = [Depth(recurse=True), FixedPoint("depth")]
1057
+ _size_check = [Size(recurse=True), FixedPoint("size")]
1058
+
1059
+ def _opt_control(property_set):
1060
+ return (not property_set["depth_fixed_point"]) or (
1061
+ not property_set["size_fixed_point"]
1062
+ )
1063
+
1064
+ if optimization_level == 1:
1065
+ _opt = [
1066
+ InverseCancellation(
1067
+ [
1068
+ CXGate(),
1069
+ ECRGate(),
1070
+ CZGate(),
1071
+ CYGate(),
1072
+ XGate(),
1073
+ YGate(),
1074
+ ZGate(),
1075
+ HGate(),
1076
+ SwapGate(),
1077
+ (TGate(), TdgGate()),
1078
+ (SGate(), SdgGate()),
1079
+ (SXGate(), SXdgGate()),
1080
+ ]
1081
+ ),
1082
+ ContractIdleWiresInControlFlow(),
1083
+ ]
1084
+ elif optimization_level in [2, 3]:
1085
+ # The optimization loop runs OptimizeCliffordT + CommutativeCancellation
1086
+ # until fixpoint.
1087
+ _opt = [
1088
+ RemoveIdentityEquivalent(
1089
+ approximation_degree=pass_manager_config.approximation_degree,
1090
+ target=pass_manager_config.target,
1091
+ ),
1092
+ OptimizeCliffordT(),
1093
+ CommutativeCancellation(target=pass_manager_config.target),
1094
+ ContractIdleWiresInControlFlow(),
1095
+ ]
1096
+
1097
+ else:
1098
+ raise TranspilerError(f"Invalid optimization_level: {optimization_level}")
1099
+
1100
+ # Build nested flow controllers
1101
+ optimization.append(_depth_check + _size_check)
1102
+
1103
+ opt_loop = _opt + _depth_check + _size_check
1104
+ optimization.append(DoWhileController(opt_loop, do_while=_opt_control))
1105
+ # We need to run BasisTranslator because OptimizeCliffordT does not consider the basis set.
1106
+ if optimization_level in [2, 3]:
1107
+ optimization.append(
1108
+ BasisTranslator(
1109
+ sel, pass_manager_config.basis_gates, pass_manager_config.target
1110
+ )
1111
+ )
1112
+ return optimization
1113
+ else:
1114
+ return None
@@ -51,6 +51,7 @@ from qiskit.transpiler.passes.layout.vf2_post_layout import VF2PostLayoutStopRea
51
51
  from qiskit.transpiler.exceptions import TranspilerError
52
52
  from qiskit.transpiler.layout import Layout
53
53
  from qiskit.utils import deprecate_func
54
+ from qiskit.quantum_info.operators.symplectic.clifford_circuits import _CLIFFORD_GATE_NAMES
54
55
 
55
56
 
56
57
  _ControlFlowState = collections.namedtuple("_ControlFlowState", ("working", "not_working"))
@@ -485,6 +486,74 @@ def generate_translation_passmanager(
485
486
  translator,
486
487
  ]
487
488
  fix_1q = [translator]
489
+ elif method == "clifford_t":
490
+ # The list of extended basis gates consists of the specified Clifford+T basis gates and
491
+ # additionally the 1q-gate "u".
492
+ # We set target=None to make sure extended_basis_gates is not overwritten by the target.
493
+ extended_basis_gates = list(basis_gates) + ["u"]
494
+
495
+ unroll = [
496
+ # Use the UnitarySynthesis pass to unroll 1-qubit and 2-qubit gates named "unitary" into
497
+ # extended_basis_gates.
498
+ UnitarySynthesis(
499
+ basis_gates=extended_basis_gates,
500
+ approximation_degree=approximation_degree,
501
+ coupling_map=coupling_map,
502
+ plugin_config=unitary_synthesis_plugin_config,
503
+ method=unitary_synthesis_method,
504
+ target=None,
505
+ ),
506
+ # Use the HighLevelSynthesis pass to unroll all the remaining 1q and 2q custom
507
+ # gates into extended_basis_gates + the gates in the equivalence library.
508
+ # We set target=None to make sure extended_basis_gates is not overwritten by the target.
509
+ HighLevelSynthesis(
510
+ hls_config=hls_config,
511
+ coupling_map=coupling_map,
512
+ target=None,
513
+ use_qubit_indices=True,
514
+ equivalence_library=sel,
515
+ basis_gates=extended_basis_gates,
516
+ qubits_initially_zero=qubits_initially_zero,
517
+ ),
518
+ # Use the BasisTranslator pass to translate all the gates into extended_basis_gates.
519
+ # In other words, this translates the gates in the equivalence library that are not
520
+ # in extended_basis_gates to gates in extended_basis_gates only.
521
+ # Note that we do not want to make any assumptions on which Clifford gates are present
522
+ # in basis_gates. The BasisTranslator will do the conversion if possible (and provide
523
+ # a helpful error message otherwise).
524
+ BasisTranslator(sel, extended_basis_gates, None),
525
+ # The next step is to resynthesize blocks of consecutive 1q-gates into ["h", "t", "tdg"].
526
+ # Use Collect1qRuns and ConsolidateBlocks passes to replace such blocks by 1q "unitary"
527
+ # gates.
528
+ Collect1qRuns(),
529
+ ConsolidateBlocks(
530
+ basis_gates=None,
531
+ target=None,
532
+ approximation_degree=approximation_degree,
533
+ force_consolidate=True,
534
+ ),
535
+ # We use the "clifford" unitary synthesis plugin to replace single-qubit
536
+ # unitary gates that can be represented as Cliffords by Clifford gates.
537
+ UnitarySynthesis(method="clifford", plugin_config={"max_qubits": 1}),
538
+ # We use the Solovay-Kitaev decomposition via the plugin mechanism for "sk"
539
+ # UnitarySynthesisPlugin.
540
+ UnitarySynthesis(
541
+ basis_gates=["h", "t", "tdg"],
542
+ approximation_degree=approximation_degree,
543
+ coupling_map=coupling_map,
544
+ plugin_config=unitary_synthesis_plugin_config,
545
+ method="sk",
546
+ min_qubits=1,
547
+ target=None,
548
+ ),
549
+ # Finally, we use BasisTranslator to translate ["h", "t", "tdg"] to the actually
550
+ # specified set of basis gates.
551
+ BasisTranslator(sel, basis_gates, target),
552
+ ]
553
+ # We use the BasisTranslator pass to translate any 1q-gates added by GateDirection
554
+ # into basis_gates.
555
+ translator = BasisTranslator(sel, basis_gates, target)
556
+ fix_1q = [translator]
488
557
  elif method == "synthesis":
489
558
  unroll = [
490
559
  # # Use unitary synthesis for basis aware decomposition of
@@ -670,3 +739,35 @@ def get_vf2_limits(
670
739
  250000, # Limits layout scoring to < 60 sec on ~400 qubit devices
671
740
  )
672
741
  return limits
742
+
743
+
744
+ # Clifford+T basis, consisting of Clifford+T gate names + additional instruction names
745
+ # that are a part of every basis
746
+ _CLIFFORD_T_BASIS = set(_CLIFFORD_GATE_NAMES).union(
747
+ {"t", "tdg", "delay", "barrier", "reset", "measure"}.union(CONTROL_FLOW_OP_NAMES)
748
+ )
749
+
750
+
751
+ def is_clifford_t_basis(basis_gates=None, target=None) -> bool:
752
+ """
753
+ Checks whether the given basis set can be considered as Clifford+T.
754
+
755
+ For this we require that:
756
+ 1. The set only contains Clifford+T gates,
757
+ 2. The set contains either T or Tdg gate or both.
758
+
759
+ In particular, these conditions guarantee that the empty basis set
760
+ is not considered as Clifford+T.
761
+ """
762
+
763
+ if target is not None:
764
+ basis = set(target.operation_names)
765
+ elif basis_gates is not None:
766
+ basis = set(basis_gates)
767
+ else:
768
+ basis = set()
769
+
770
+ if (basis_gates is None) or (("t" not in basis_gates) and ("tdg" not in basis_gates)):
771
+ return False
772
+
773
+ return basis.issubset(_CLIFFORD_T_BASIS)
@@ -25,6 +25,7 @@ from qiskit.transpiler.exceptions import TranspilerError
25
25
  from qiskit.transpiler.instruction_durations import InstructionDurations
26
26
  from qiskit.transpiler.layout import Layout
27
27
  from qiskit.transpiler.passmanager_config import PassManagerConfig
28
+ from qiskit.transpiler.preset_passmanagers.common import is_clifford_t_basis
28
29
  from qiskit.transpiler.target import Target, _FakeTarget
29
30
  from qiskit.transpiler.timing_constraints import TimingConstraints
30
31
 
@@ -302,6 +303,11 @@ def generate_preset_pass_manager(
302
303
  pm_config = PassManagerConfig.from_backend(backend, **pm_options)
303
304
  else:
304
305
  pm_config = PassManagerConfig(**pm_options)
306
+
307
+ pm_config._is_clifford_t = is_clifford_t_basis(
308
+ basis_gates=pm_config.basis_gates, target=pm_config.target
309
+ )
310
+
305
311
  if optimization_level == 0:
306
312
  pm = level_0_pass_manager(pm_config)
307
313
  elif optimization_level == 1:
@@ -36,7 +36,8 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
36
36
  The pass manager then transforms the circuit to match the coupling constraints.
37
37
  It is then unrolled to the basis, and any flipped cx directions are fixed.
38
38
  Finally, optimizations in the form of commutative gate cancellation, resynthesis
39
- of two-qubit unitary blocks, and redundant reset removal are performed.
39
+ of two-qubit unitary blocks, redundant reset removal and final layout improvements are
40
+ performed.
40
41
 
41
42
  Args:
42
43
  pass_manager_config: configuration of the pass manager.
@@ -55,7 +56,6 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> StagedPassMa
55
56
  layout_method = pass_manager_config.layout_method or "default"
56
57
  routing_method = pass_manager_config.routing_method or "default"
57
58
  translation_method = pass_manager_config.translation_method or "default"
58
- scheduling_method = pass_manager_config.scheduling_method
59
59
  optimization_method = pass_manager_config.optimization_method or "default"
60
60
  scheduling_method = pass_manager_config.scheduling_method or "default"
61
61
  target = pass_manager_config.target
@@ -159,6 +159,13 @@ class Target(BaseTarget):
159
159
  angle :class:`~qiskit.circuit.library.RXGate` while ``rx`` will get the
160
160
  parameterized :class:`~qiskit.circuit.library.RXGate`.
161
161
 
162
+ This class can be queried via the mapping protocol, using the
163
+ instruction's name as a key. You can modify any property for an
164
+ instruction via the :meth:`.update_instruction_properties` method.
165
+ Modification via the mapping protocol or mutating the attributes of
166
+ a :class:`.InstructionProperties` object is **not** supported and
167
+ doing so will invalidate the internal state of the object.
168
+
162
169
  .. note::
163
170
 
164
171
  This class assumes that qubit indices start at 0 and are a contiguous
@@ -167,7 +174,7 @@ class Target(BaseTarget):
167
174
 
168
175
  .. note::
169
176
 
170
- This class only supports additions of gates, qargs, and qubits.
177
+ This class only supports additions of gates, qargs, and properties.
171
178
  If you need to remove one of these the best option is to iterate over
172
179
  an existing object and create a new subset (or use one of the methods
173
180
  to do this). The object internally caches different views and these
@@ -373,7 +380,13 @@ class Target(BaseTarget):
373
380
  self._instruction_schedule_map = None
374
381
 
375
382
  def update_instruction_properties(self, instruction, qargs, properties):
376
- """Update the property object for an instruction qarg pair already in the Target
383
+ """Update the property object for an instruction qarg pair already in the Target.
384
+
385
+ For ease of access, a user is able to obtain the mapping between an instruction's
386
+ applicable qargs and its instruction properties via the mapping protocol (using ``__getitem__``),
387
+ with the instruction's name as the key. This method is the only way to
388
+ modify/update the properties of an instruction in the ``Target``. Usage of the mapping protocol
389
+ for modifications is not supported.
377
390
 
378
391
  Args:
379
392
  instruction (str): The instruction name to update
qiskit/utils/optionals.py CHANGED
@@ -173,16 +173,17 @@ External Python Libraries
173
173
  .. py:data:: HAS_SYMENGINE
174
174
 
175
175
  `Symengine <https://github.com/symengine/symengine>`__ is a fast C++ backend for the
176
- symbolic-manipulation library `Sympy <https://www.sympy.org/en/index.html>`__. Qiskit uses
177
- special methods from Symengine to accelerate its handling of
178
- :class:`~.circuit.Parameter`\\ s if available.
176
+ symbolic-manipulation library `Sympy <https://www.sympy.org/en/index.html>`__. This
177
+ dependency is used to load legacy QPY formats, where this package was used to handle
178
+ :class:`~.circuit.Parameter`\\ s.
179
179
 
180
180
  .. py:data:: HAS_SYMPY
181
181
 
182
182
  `SymPy <https://www.sympy.org/en/index.html>`__ is Python library for symbolic mathematics.
183
- Sympy was historically used for the implementation of the :class:`.ParameterExpression`
183
+ ``SymPy`` was historically used for the implementation of the :class:`.ParameterExpression`
184
184
  class but isn't any longer. However it is needed for some legacy functionality that uses
185
- :meth:`.ParameterExpression.sympify`. It is also used in some visualization functions.
185
+ :meth:`.ParameterExpression.sympify`. It is also used in some visualization functions
186
+ and template matching.
186
187
 
187
188
  .. py:data:: HAS_TESTTOOLS
188
189
 
@@ -19,6 +19,7 @@ from warnings import warn
19
19
  import numpy as np
20
20
 
21
21
  from qiskit.circuit import (
22
+ BoxOp,
22
23
  ClassicalRegister,
23
24
  Clbit,
24
25
  ControlFlowOp,
@@ -499,9 +500,10 @@ def _get_gate_span(qubits, node):
499
500
  if index > max_index:
500
501
  max_index = index
501
502
 
502
- # Because of wrapping boxes for mpl control flow ops, this
503
- # type of op must be the only op in the layer
504
- if isinstance(node.op, ControlFlowOp):
503
+ if isinstance(node.op, ControlFlowOp) and not isinstance(node.op, BoxOp):
504
+ # Because of wrapping boxes for mpl control flow ops, this
505
+ # type of op must be the only op in the layer
506
+ # BoxOps are excepted because they have one block executed unconditionally
505
507
  span = qubits
506
508
  elif node.cargs or getattr(node, "condition", None):
507
509
  span = qubits[min_index : len(qubits)]