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.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +19 -1
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/circuit/__init__.py +104 -20
- qiskit/circuit/_add_control.py +57 -31
- qiskit/circuit/_classical_resource_map.py +4 -0
- qiskit/circuit/annotation.py +504 -0
- qiskit/circuit/classical/expr/__init__.py +1 -1
- qiskit/circuit/classical/expr/expr.py +104 -446
- qiskit/circuit/classical/expr/visitors.py +6 -0
- qiskit/circuit/classical/types/types.py +7 -130
- qiskit/circuit/controlflow/box.py +32 -7
- qiskit/circuit/delay.py +11 -9
- qiskit/circuit/library/arithmetic/adders/adder.py +4 -4
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +2 -2
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +8 -4
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +23 -15
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +22 -14
- qiskit/circuit/library/arithmetic/quadratic_form.py +6 -0
- qiskit/circuit/library/arithmetic/weighted_adder.py +43 -24
- qiskit/circuit/library/basis_change/qft.py +2 -2
- qiskit/circuit/library/blueprintcircuit.py +6 -0
- qiskit/circuit/library/boolean_logic/inner_product.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_and.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_or.py +3 -3
- qiskit/circuit/library/boolean_logic/quantum_xor.py +2 -2
- qiskit/circuit/library/data_preparation/_z_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/_zz_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +2 -2
- qiskit/circuit/library/fourier_checking.py +2 -2
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -1
- qiskit/circuit/library/generalized_gates/gms.py +5 -1
- qiskit/circuit/library/generalized_gates/linear_function.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +5 -1
- qiskit/circuit/library/generalized_gates/uc.py +1 -1
- qiskit/circuit/library/generalized_gates/unitary.py +21 -2
- qiskit/circuit/library/graph_state.py +2 -2
- qiskit/circuit/library/grover_operator.py +2 -2
- qiskit/circuit/library/hidden_linear_function.py +2 -2
- qiskit/circuit/library/iqp.py +2 -2
- qiskit/circuit/library/n_local/efficient_su2.py +2 -2
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
- qiskit/circuit/library/n_local/excitation_preserving.py +7 -9
- qiskit/circuit/library/n_local/n_local.py +4 -3
- qiskit/circuit/library/n_local/pauli_two_design.py +2 -2
- qiskit/circuit/library/n_local/real_amplitudes.py +2 -2
- qiskit/circuit/library/n_local/two_local.py +2 -2
- qiskit/circuit/library/overlap.py +2 -2
- qiskit/circuit/library/pauli_evolution.py +3 -2
- qiskit/circuit/library/phase_estimation.py +2 -2
- qiskit/circuit/library/standard_gates/dcx.py +11 -12
- qiskit/circuit/library/standard_gates/ecr.py +21 -24
- qiskit/circuit/library/standard_gates/equivalence_library.py +232 -96
- qiskit/circuit/library/standard_gates/global_phase.py +5 -6
- qiskit/circuit/library/standard_gates/h.py +22 -45
- qiskit/circuit/library/standard_gates/i.py +1 -1
- qiskit/circuit/library/standard_gates/iswap.py +13 -31
- qiskit/circuit/library/standard_gates/p.py +19 -26
- qiskit/circuit/library/standard_gates/r.py +11 -17
- qiskit/circuit/library/standard_gates/rx.py +21 -45
- qiskit/circuit/library/standard_gates/rxx.py +7 -22
- qiskit/circuit/library/standard_gates/ry.py +21 -39
- qiskit/circuit/library/standard_gates/ryy.py +13 -28
- qiskit/circuit/library/standard_gates/rz.py +18 -35
- qiskit/circuit/library/standard_gates/rzx.py +7 -22
- qiskit/circuit/library/standard_gates/rzz.py +7 -19
- qiskit/circuit/library/standard_gates/s.py +44 -39
- qiskit/circuit/library/standard_gates/swap.py +25 -38
- qiskit/circuit/library/standard_gates/sx.py +34 -41
- qiskit/circuit/library/standard_gates/t.py +18 -27
- qiskit/circuit/library/standard_gates/u.py +8 -24
- qiskit/circuit/library/standard_gates/u1.py +28 -52
- qiskit/circuit/library/standard_gates/u2.py +9 -9
- qiskit/circuit/library/standard_gates/u3.py +24 -40
- qiskit/circuit/library/standard_gates/x.py +190 -336
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +12 -50
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +13 -52
- qiskit/circuit/library/standard_gates/y.py +19 -23
- qiskit/circuit/library/standard_gates/z.py +31 -38
- qiskit/circuit/parameter.py +14 -5
- qiskit/circuit/parameterexpression.py +109 -75
- qiskit/circuit/quantumcircuit.py +172 -99
- qiskit/circuit/quantumcircuitdata.py +1 -0
- qiskit/circuit/random/__init__.py +37 -2
- qiskit/circuit/random/utils.py +445 -56
- qiskit/circuit/tools/pi_check.py +5 -13
- qiskit/compiler/transpiler.py +1 -1
- qiskit/converters/circuit_to_instruction.py +2 -2
- qiskit/dagcircuit/dagnode.py +8 -3
- qiskit/primitives/__init__.py +2 -2
- qiskit/primitives/base/base_estimator.py +2 -2
- qiskit/primitives/containers/data_bin.py +0 -3
- qiskit/primitives/containers/observables_array.py +192 -108
- qiskit/primitives/primitive_job.py +29 -10
- qiskit/providers/fake_provider/generic_backend_v2.py +2 -0
- qiskit/qasm3/__init__.py +106 -12
- qiskit/qasm3/ast.py +15 -1
- qiskit/qasm3/exporter.py +59 -36
- qiskit/qasm3/printer.py +12 -0
- qiskit/qpy/__init__.py +182 -6
- qiskit/qpy/binary_io/circuits.py +256 -24
- qiskit/qpy/binary_io/parse_sympy_repr.py +5 -0
- qiskit/qpy/binary_io/schedules.py +12 -32
- qiskit/qpy/binary_io/value.py +36 -18
- qiskit/qpy/common.py +11 -3
- qiskit/qpy/formats.py +17 -1
- qiskit/qpy/interface.py +52 -12
- qiskit/qpy/type_keys.py +7 -1
- qiskit/quantum_info/__init__.py +10 -0
- qiskit/quantum_info/operators/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/clifford_circuits.py +26 -0
- qiskit/quantum_info/operators/symplectic/pauli.py +2 -2
- qiskit/result/sampled_expval.py +3 -1
- qiskit/synthesis/__init__.py +10 -0
- qiskit/synthesis/arithmetic/__init__.py +1 -1
- qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
- qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
- qiskit/synthesis/evolution/lie_trotter.py +10 -7
- qiskit/synthesis/evolution/product_formula.py +10 -7
- qiskit/synthesis/evolution/qdrift.py +10 -7
- qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
- qiskit/synthesis/multi_controlled/__init__.py +4 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
- qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
- qiskit/synthesis/unitary/qsd.py +80 -9
- qiskit/transpiler/__init__.py +10 -3
- qiskit/transpiler/instruction_durations.py +2 -20
- qiskit/transpiler/passes/__init__.py +5 -2
- qiskit/transpiler/passes/layout/dense_layout.py +26 -6
- qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
- qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
- qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
- qiskit/transpiler/passes/layout/vf2_utils.py +10 -0
- qiskit/transpiler/passes/optimization/__init__.py +1 -1
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
- qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
- qiskit/transpiler/passes/routing/sabre_swap.py +4 -2
- qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
- qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
- qiskit/transpiler/passes/synthesis/__init__.py +1 -0
- qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
- qiskit/transpiler/passes/synthesis/hls_plugins.py +494 -93
- qiskit/transpiler/passes/synthesis/plugin.py +4 -0
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +27 -22
- qiskit/transpiler/passmanager_config.py +3 -0
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +149 -28
- qiskit/transpiler/preset_passmanagers/common.py +101 -0
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +6 -0
- qiskit/transpiler/preset_passmanagers/level3.py +2 -2
- qiskit/transpiler/target.py +15 -2
- qiskit/utils/optionals.py +6 -5
- qiskit/visualization/circuit/_utils.py +5 -3
- qiskit/visualization/circuit/latex.py +9 -2
- qiskit/visualization/circuit/matplotlib.py +26 -4
- qiskit/visualization/circuit/qcstyle.py +9 -157
- qiskit/visualization/dag/__init__.py +13 -0
- qiskit/visualization/dag/dagstyle.py +103 -0
- qiskit/visualization/dag/styles/__init__.py +13 -0
- qiskit/visualization/dag/styles/color.json +10 -0
- qiskit/visualization/dag/styles/plain.json +5 -0
- qiskit/visualization/dag_visualization.py +169 -98
- qiskit/visualization/style.py +223 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/METADATA +7 -6
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/RECORD +178 -169
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/entry_points.txt +6 -0
- qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
- qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/WHEEL +0 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/licenses/LICENSE.txt +0 -0
- {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 =
|
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
|
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
|
152
|
-
up to
|
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(
|
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
|
-
|
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
|
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
|
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",
|
296
|
-
depth = config.get("depth",
|
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",
|
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(
|
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
|
-
|
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=
|
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
|
-
|
740
|
-
|
741
|
-
|
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
|
-
|
874
|
-
|
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
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
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
|
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
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
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,
|
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
|
qiskit/transpiler/target.py
CHANGED
@@ -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
|
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>`__.
|
177
|
-
|
178
|
-
:class:`~.circuit.Parameter`\\ s
|
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
|
-
|
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
|
-
|
503
|
-
|
504
|
-
|
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)]
|