qiskit 1.0.2__cp38-abi3-win32.whl → 1.1.0__cp38-abi3-win32.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 +27 -16
- qiskit/_accelerate.pyd +0 -0
- qiskit/_numpy_compat.py +73 -0
- qiskit/assembler/__init__.py +5 -10
- qiskit/assembler/disassemble.py +5 -6
- qiskit/circuit/__init__.py +1061 -232
- qiskit/circuit/_classical_resource_map.py +10 -6
- qiskit/circuit/_utils.py +18 -8
- qiskit/circuit/annotated_operation.py +21 -0
- qiskit/circuit/barrier.py +10 -13
- qiskit/circuit/bit.py +0 -1
- qiskit/circuit/classical/__init__.py +2 -2
- qiskit/circuit/classical/expr/__init__.py +39 -5
- qiskit/circuit/classical/expr/constructors.py +84 -1
- qiskit/circuit/classical/expr/expr.py +83 -13
- qiskit/circuit/classical/expr/visitors.py +83 -0
- qiskit/circuit/classical/types/__init__.py +5 -4
- qiskit/circuit/classicalfunction/__init__.py +1 -0
- qiskit/circuit/commutation_checker.py +86 -51
- qiskit/circuit/controlflow/_builder_utils.py +9 -1
- qiskit/circuit/controlflow/break_loop.py +8 -22
- qiskit/circuit/controlflow/builder.py +116 -1
- qiskit/circuit/controlflow/continue_loop.py +8 -22
- qiskit/circuit/controlflow/control_flow.py +47 -8
- qiskit/circuit/controlflow/for_loop.py +8 -23
- qiskit/circuit/controlflow/if_else.py +13 -27
- qiskit/circuit/controlflow/switch_case.py +14 -21
- qiskit/circuit/controlflow/while_loop.py +9 -23
- qiskit/circuit/controlledgate.py +2 -2
- qiskit/circuit/delay.py +7 -5
- qiskit/circuit/gate.py +20 -7
- qiskit/circuit/instruction.py +31 -30
- qiskit/circuit/instructionset.py +9 -22
- qiskit/circuit/library/__init__.py +3 -13
- qiskit/circuit/library/arithmetic/integer_comparator.py +2 -2
- qiskit/circuit/library/arithmetic/quadratic_form.py +3 -2
- qiskit/circuit/library/blueprintcircuit.py +29 -7
- qiskit/circuit/library/data_preparation/state_preparation.py +6 -5
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -4
- qiskit/circuit/library/generalized_gates/isometry.py +51 -254
- qiskit/circuit/library/generalized_gates/pauli.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +4 -1
- qiskit/circuit/library/generalized_gates/rv.py +15 -11
- qiskit/circuit/library/generalized_gates/uc.py +2 -98
- qiskit/circuit/library/generalized_gates/unitary.py +9 -4
- qiskit/circuit/library/hamiltonian_gate.py +11 -5
- qiskit/circuit/library/n_local/efficient_su2.py +5 -5
- qiskit/circuit/library/n_local/n_local.py +100 -49
- qiskit/circuit/library/n_local/two_local.py +3 -59
- qiskit/circuit/library/overlap.py +3 -3
- qiskit/circuit/library/phase_oracle.py +1 -1
- qiskit/circuit/library/quantum_volume.py +39 -38
- qiskit/circuit/library/standard_gates/equivalence_library.py +50 -0
- qiskit/circuit/library/standard_gates/global_phase.py +4 -2
- qiskit/circuit/library/standard_gates/i.py +1 -2
- qiskit/circuit/library/standard_gates/iswap.py +1 -2
- qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +11 -5
- qiskit/circuit/library/standard_gates/p.py +31 -15
- qiskit/circuit/library/standard_gates/r.py +4 -3
- qiskit/circuit/library/standard_gates/rx.py +7 -4
- qiskit/circuit/library/standard_gates/rxx.py +4 -3
- qiskit/circuit/library/standard_gates/ry.py +7 -4
- qiskit/circuit/library/standard_gates/ryy.py +4 -3
- qiskit/circuit/library/standard_gates/rz.py +7 -4
- qiskit/circuit/library/standard_gates/rzx.py +4 -3
- qiskit/circuit/library/standard_gates/rzz.py +4 -3
- qiskit/circuit/library/standard_gates/s.py +4 -8
- qiskit/circuit/library/standard_gates/t.py +2 -4
- qiskit/circuit/library/standard_gates/u.py +16 -11
- qiskit/circuit/library/standard_gates/u1.py +6 -2
- qiskit/circuit/library/standard_gates/u2.py +4 -2
- qiskit/circuit/library/standard_gates/u3.py +9 -5
- qiskit/circuit/library/standard_gates/x.py +22 -11
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +4 -3
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +7 -5
- qiskit/circuit/library/standard_gates/z.py +1 -2
- qiskit/circuit/measure.py +4 -1
- qiskit/circuit/operation.py +13 -8
- qiskit/circuit/parameter.py +11 -6
- qiskit/circuit/quantumcircuit.py +1910 -260
- qiskit/circuit/quantumcircuitdata.py +2 -2
- qiskit/circuit/reset.py +5 -2
- qiskit/circuit/store.py +95 -0
- qiskit/compiler/assembler.py +22 -22
- qiskit/compiler/transpiler.py +63 -112
- qiskit/converters/__init__.py +17 -2
- qiskit/converters/circuit_to_dag.py +7 -0
- qiskit/converters/circuit_to_dagdependency_v2.py +47 -0
- qiskit/converters/circuit_to_gate.py +2 -0
- qiskit/converters/circuit_to_instruction.py +22 -0
- qiskit/converters/dag_to_circuit.py +4 -0
- qiskit/converters/dag_to_dagdependency_v2.py +44 -0
- qiskit/dagcircuit/collect_blocks.py +15 -10
- qiskit/dagcircuit/dagcircuit.py +434 -124
- qiskit/dagcircuit/dagdependency.py +19 -12
- qiskit/dagcircuit/dagdependency_v2.py +641 -0
- qiskit/dagcircuit/dagdepnode.py +19 -16
- qiskit/dagcircuit/dagnode.py +14 -4
- qiskit/passmanager/passmanager.py +11 -11
- qiskit/primitives/__init__.py +22 -12
- qiskit/primitives/backend_estimator.py +3 -5
- qiskit/primitives/backend_estimator_v2.py +410 -0
- qiskit/primitives/backend_sampler_v2.py +287 -0
- qiskit/primitives/base/base_estimator.py +4 -9
- qiskit/primitives/base/base_sampler.py +2 -2
- qiskit/primitives/containers/__init__.py +6 -4
- qiskit/primitives/containers/bit_array.py +293 -2
- qiskit/primitives/containers/data_bin.py +123 -50
- qiskit/primitives/containers/estimator_pub.py +10 -3
- qiskit/primitives/containers/observables_array.py +2 -2
- qiskit/primitives/containers/pub_result.py +1 -1
- qiskit/primitives/containers/sampler_pub.py +19 -3
- qiskit/primitives/containers/sampler_pub_result.py +74 -0
- qiskit/primitives/containers/shape.py +4 -4
- qiskit/primitives/statevector_estimator.py +4 -4
- qiskit/primitives/statevector_sampler.py +7 -12
- qiskit/providers/__init__.py +65 -34
- qiskit/providers/backend.py +2 -2
- qiskit/providers/backend_compat.py +8 -10
- qiskit/providers/basic_provider/__init__.py +2 -23
- qiskit/providers/basic_provider/basic_provider_tools.py +67 -31
- qiskit/providers/basic_provider/basic_simulator.py +81 -21
- qiskit/providers/fake_provider/__init__.py +1 -1
- qiskit/providers/fake_provider/fake_1q.py +1 -1
- qiskit/providers/fake_provider/fake_backend.py +3 -408
- qiskit/providers/fake_provider/generic_backend_v2.py +26 -14
- qiskit/providers/models/__init__.py +2 -2
- qiskit/providers/provider.py +16 -0
- qiskit/pulse/builder.py +4 -1
- qiskit/pulse/parameter_manager.py +60 -4
- qiskit/pulse/schedule.py +29 -13
- qiskit/pulse/utils.py +61 -20
- qiskit/qasm2/__init__.py +1 -5
- qiskit/qasm2/parse.py +1 -4
- qiskit/qasm3/__init__.py +42 -5
- qiskit/qasm3/ast.py +19 -0
- qiskit/qasm3/exporter.py +178 -106
- qiskit/qasm3/printer.py +27 -5
- qiskit/qobj/converters/pulse_instruction.py +6 -6
- qiskit/qpy/__init__.py +299 -67
- qiskit/qpy/binary_io/circuits.py +216 -47
- qiskit/qpy/binary_io/schedules.py +42 -36
- qiskit/qpy/binary_io/value.py +201 -22
- qiskit/qpy/common.py +1 -1
- qiskit/qpy/exceptions.py +20 -0
- qiskit/qpy/formats.py +29 -0
- qiskit/qpy/type_keys.py +21 -0
- qiskit/quantum_info/analysis/distance.py +3 -3
- qiskit/quantum_info/analysis/make_observable.py +2 -1
- qiskit/quantum_info/analysis/z2_symmetries.py +2 -1
- qiskit/quantum_info/operators/channel/chi.py +9 -8
- qiskit/quantum_info/operators/channel/choi.py +10 -9
- qiskit/quantum_info/operators/channel/kraus.py +2 -1
- qiskit/quantum_info/operators/channel/ptm.py +10 -9
- qiskit/quantum_info/operators/channel/quantum_channel.py +2 -1
- qiskit/quantum_info/operators/channel/stinespring.py +2 -1
- qiskit/quantum_info/operators/channel/superop.py +12 -11
- qiskit/quantum_info/operators/channel/transformations.py +12 -11
- qiskit/quantum_info/operators/dihedral/dihedral.py +5 -4
- qiskit/quantum_info/operators/operator.py +43 -30
- qiskit/quantum_info/operators/scalar_op.py +10 -9
- qiskit/quantum_info/operators/symplectic/base_pauli.py +70 -59
- qiskit/quantum_info/operators/symplectic/clifford.py +36 -9
- qiskit/quantum_info/operators/symplectic/pauli.py +53 -6
- qiskit/quantum_info/operators/symplectic/pauli_list.py +36 -14
- qiskit/quantum_info/operators/symplectic/random.py +3 -2
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +61 -36
- qiskit/quantum_info/states/densitymatrix.py +13 -13
- qiskit/quantum_info/states/stabilizerstate.py +3 -3
- qiskit/quantum_info/states/statevector.py +14 -13
- qiskit/quantum_info/states/utils.py +5 -3
- qiskit/result/__init__.py +6 -0
- qiskit/result/mitigation/correlated_readout_mitigator.py +3 -2
- qiskit/result/mitigation/local_readout_mitigator.py +2 -1
- qiskit/result/mitigation/utils.py +3 -2
- qiskit/scheduler/__init__.py +10 -1
- qiskit/scheduler/methods/__init__.py +1 -8
- qiskit/synthesis/__init__.py +3 -6
- qiskit/synthesis/discrete_basis/commutator_decompose.py +2 -2
- qiskit/synthesis/evolution/lie_trotter.py +7 -14
- qiskit/synthesis/evolution/qdrift.py +3 -4
- qiskit/synthesis/linear/cnot_synth.py +1 -3
- qiskit/synthesis/linear/linear_circuits_utils.py +1 -1
- qiskit/synthesis/linear_phase/cz_depth_lnn.py +4 -18
- qiskit/synthesis/permutation/__init__.py +1 -0
- qiskit/synthesis/permutation/permutation_reverse_lnn.py +90 -0
- qiskit/synthesis/qft/qft_decompose_lnn.py +2 -6
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +165 -954
- qiskit/synthesis/two_qubit/xx_decompose/circuits.py +13 -12
- qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +7 -1
- qiskit/synthesis/unitary/aqc/__init__.py +1 -1
- qiskit/synthesis/unitary/aqc/cnot_structures.py +2 -1
- qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +2 -1
- qiskit/synthesis/unitary/qsd.py +3 -2
- qiskit/transpiler/__init__.py +7 -3
- qiskit/transpiler/layout.py +140 -61
- qiskit/transpiler/passes/__init__.py +10 -2
- qiskit/transpiler/passes/basis/basis_translator.py +9 -4
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
- qiskit/transpiler/passes/calibration/rzx_builder.py +2 -1
- qiskit/transpiler/passes/layout/apply_layout.py +8 -3
- qiskit/transpiler/passes/layout/sabre_layout.py +15 -3
- qiskit/transpiler/passes/layout/set_layout.py +1 -1
- qiskit/transpiler/passes/optimization/__init__.py +2 -0
- qiskit/transpiler/passes/optimization/commutation_analysis.py +2 -2
- qiskit/transpiler/passes/optimization/commutative_cancellation.py +1 -1
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +1 -1
- qiskit/transpiler/passes/optimization/cx_cancellation.py +10 -0
- qiskit/transpiler/passes/optimization/elide_permutations.py +114 -0
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +9 -3
- qiskit/transpiler/passes/optimization/optimize_annotated.py +248 -12
- qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +1 -3
- qiskit/transpiler/passes/routing/__init__.py +1 -0
- qiskit/transpiler/passes/routing/basic_swap.py +13 -2
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +8 -1
- qiskit/transpiler/passes/routing/lookahead_swap.py +7 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +10 -6
- qiskit/transpiler/passes/routing/star_prerouting.py +417 -0
- qiskit/transpiler/passes/routing/stochastic_swap.py +24 -8
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alap.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/align_measures.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +9 -6
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +8 -0
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +13 -4
- qiskit/transpiler/passes/scheduling/asap.py +1 -2
- qiskit/transpiler/passes/scheduling/base_scheduler.py +21 -2
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +26 -4
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +24 -2
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +28 -4
- qiskit/transpiler/passes/synthesis/aqc_plugin.py +2 -2
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +120 -13
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +162 -55
- qiskit/transpiler/passes/utils/gates_basis.py +3 -3
- qiskit/transpiler/passmanager.py +44 -1
- qiskit/transpiler/preset_passmanagers/__init__.py +3 -3
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +34 -16
- qiskit/transpiler/preset_passmanagers/common.py +4 -6
- qiskit/transpiler/preset_passmanagers/plugin.py +9 -1
- qiskit/utils/__init__.py +3 -2
- qiskit/utils/optionals.py +6 -2
- qiskit/utils/parallel.py +24 -15
- qiskit/visualization/array.py +1 -1
- qiskit/visualization/bloch.py +2 -3
- qiskit/visualization/circuit/matplotlib.py +44 -14
- qiskit/visualization/circuit/text.py +38 -18
- qiskit/visualization/counts_visualization.py +3 -6
- qiskit/visualization/dag_visualization.py +6 -7
- qiskit/visualization/gate_map.py +9 -1
- qiskit/visualization/pulse_v2/interface.py +8 -3
- qiskit/visualization/state_visualization.py +3 -2
- qiskit/visualization/timeline/interface.py +18 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/METADATA +12 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/RECORD +261 -251
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/WHEEL +1 -1
- qiskit/_qasm2.pyd +0 -0
- qiskit/_qasm3.pyd +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/entry_points.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/top_level.txt +0 -0
@@ -24,7 +24,6 @@ Unitary Synthesis Plugin (in :mod:`qiskit.transpiler.passes.synthesis.unitary_sy
|
|
24
24
|
from __future__ import annotations
|
25
25
|
from math import pi, inf, isclose
|
26
26
|
from typing import Any
|
27
|
-
from copy import deepcopy
|
28
27
|
from itertools import product
|
29
28
|
from functools import partial
|
30
29
|
import numpy as np
|
@@ -35,10 +34,12 @@ from qiskit.transpiler.basepasses import TransformationPass
|
|
35
34
|
from qiskit.transpiler.exceptions import TranspilerError
|
36
35
|
from qiskit.dagcircuit.dagcircuit import DAGCircuit
|
37
36
|
from qiskit.synthesis.one_qubit import one_qubit_decompose
|
37
|
+
from qiskit.transpiler.passes.optimization.optimize_1q_decomposition import _possible_decomposers
|
38
38
|
from qiskit.synthesis.two_qubit.xx_decompose import XXDecomposer, XXEmbodiments
|
39
39
|
from qiskit.synthesis.two_qubit.two_qubit_decompose import (
|
40
40
|
TwoQubitBasisDecomposer,
|
41
41
|
TwoQubitWeylDecomposition,
|
42
|
+
GATE_NAME_MAP,
|
42
43
|
)
|
43
44
|
from qiskit.quantum_info import Operator
|
44
45
|
from qiskit.circuit import ControlFlowOp, Gate, Parameter
|
@@ -84,23 +85,16 @@ def _choose_kak_gate(basis_gates):
|
|
84
85
|
def _choose_euler_basis(basis_gates):
|
85
86
|
"""Choose the first available 1q basis to use in the Euler decomposition."""
|
86
87
|
basis_set = set(basis_gates or [])
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
if set(gates).issubset(basis_set):
|
91
|
-
return basis
|
92
|
-
|
88
|
+
decomposers = _possible_decomposers(basis_set)
|
89
|
+
if decomposers:
|
90
|
+
return decomposers[0]
|
93
91
|
return "U"
|
94
92
|
|
95
93
|
|
96
94
|
def _find_matching_euler_bases(target, qubit):
|
97
95
|
"""Find matching available 1q basis to use in the Euler decomposition."""
|
98
|
-
euler_basis_gates = []
|
99
96
|
basis_set = target.operation_names_for_qargs((qubit,))
|
100
|
-
|
101
|
-
if set(gates).issubset(basis_set):
|
102
|
-
euler_basis_gates.append(basis)
|
103
|
-
return euler_basis_gates
|
97
|
+
return _possible_decomposers(basis_set)
|
104
98
|
|
105
99
|
|
106
100
|
def _choose_bases(basis_gates, basis_dict=None):
|
@@ -153,20 +147,26 @@ def _error(circuit, target=None, qubits=None):
|
|
153
147
|
of circuit as a weak proxy for error.
|
154
148
|
"""
|
155
149
|
if target is None:
|
156
|
-
|
150
|
+
if isinstance(circuit, DAGCircuit):
|
151
|
+
return len(circuit.op_nodes())
|
152
|
+
else:
|
153
|
+
return len(circuit)
|
157
154
|
gate_fidelities = []
|
158
155
|
gate_durations = []
|
159
|
-
|
160
|
-
|
156
|
+
|
157
|
+
def score_instruction(inst, inst_qubits):
|
161
158
|
try:
|
162
159
|
keys = target.operation_names_for_qargs(inst_qubits)
|
163
160
|
for key in keys:
|
164
161
|
target_op = target.operation_from_name(key)
|
165
|
-
if isinstance(
|
162
|
+
if isinstance(circuit, DAGCircuit):
|
163
|
+
op = inst.op
|
164
|
+
else:
|
165
|
+
op = inst.operation
|
166
|
+
if isinstance(target_op, op.base_class) and (
|
166
167
|
target_op.is_parameterized()
|
167
168
|
or all(
|
168
|
-
isclose(float(p1), float(p2))
|
169
|
-
for p1, p2 in zip(target_op.params, inst.operation.params)
|
169
|
+
isclose(float(p1), float(p2)) for p1, p2 in zip(target_op.params, op.params)
|
170
170
|
)
|
171
171
|
):
|
172
172
|
inst_props = target[key].get(inst_qubits, None)
|
@@ -183,10 +183,22 @@ def _error(circuit, target=None, qubits=None):
|
|
183
183
|
else:
|
184
184
|
raise KeyError
|
185
185
|
except KeyError as error:
|
186
|
+
if isinstance(circuit, DAGCircuit):
|
187
|
+
op = inst.op
|
188
|
+
else:
|
189
|
+
op = inst.operation
|
186
190
|
raise TranspilerError(
|
187
|
-
f"Encountered a bad synthesis. "
|
188
|
-
f"Target has no {inst.operation} on qubits {qubits}."
|
191
|
+
f"Encountered a bad synthesis. " f"Target has no {op} on qubits {qubits}."
|
189
192
|
) from error
|
193
|
+
|
194
|
+
if isinstance(circuit, DAGCircuit):
|
195
|
+
for inst in circuit.topological_op_nodes():
|
196
|
+
inst_qubits = tuple(qubits[circuit.find_bit(q).index] for q in inst.qargs)
|
197
|
+
score_instruction(inst, inst_qubits)
|
198
|
+
else:
|
199
|
+
for inst in circuit:
|
200
|
+
inst_qubits = tuple(qubits[circuit.find_bit(q).index] for q in inst.qubits)
|
201
|
+
score_instruction(inst, inst_qubits)
|
190
202
|
# TODO:return np.sum(gate_durations)
|
191
203
|
return 1 - np.prod(gate_fidelities)
|
192
204
|
|
@@ -282,7 +294,7 @@ class UnitarySynthesis(TransformationPass):
|
|
282
294
|
natural_direction: bool | None = None,
|
283
295
|
synth_gates: list[str] | None = None,
|
284
296
|
method: str = "default",
|
285
|
-
min_qubits: int =
|
297
|
+
min_qubits: int = 0,
|
286
298
|
plugin_config: dict = None,
|
287
299
|
target: Target = None,
|
288
300
|
):
|
@@ -488,27 +500,55 @@ class UnitarySynthesis(TransformationPass):
|
|
488
500
|
]
|
489
501
|
)
|
490
502
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
503
|
+
out_dag = dag.copy_empty_like()
|
504
|
+
for node in dag.topological_op_nodes():
|
505
|
+
if node.op.name == "unitary" and len(node.qargs) >= self._min_qubits:
|
506
|
+
synth_dag = None
|
507
|
+
unitary = node.op.to_matrix()
|
508
|
+
n_qubits = len(node.qargs)
|
509
|
+
if (
|
510
|
+
plugin_method.max_qubits is not None and n_qubits > plugin_method.max_qubits
|
511
|
+
) or (plugin_method.min_qubits is not None and n_qubits < plugin_method.min_qubits):
|
512
|
+
method, kwargs = default_method, default_kwargs
|
513
|
+
else:
|
514
|
+
method, kwargs = plugin_method, plugin_kwargs
|
515
|
+
if method.supports_coupling_map:
|
516
|
+
kwargs["coupling_map"] = (
|
517
|
+
self._coupling_map,
|
518
|
+
[qubit_indices[x] for x in node.qargs],
|
519
|
+
)
|
520
|
+
synth_dag = method.run(unitary, **kwargs)
|
521
|
+
if synth_dag is None:
|
522
|
+
out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
523
|
+
continue
|
524
|
+
if isinstance(synth_dag, DAGCircuit):
|
525
|
+
qubit_map = dict(zip(synth_dag.qubits, node.qargs))
|
526
|
+
for node in synth_dag.topological_op_nodes():
|
527
|
+
out_dag.apply_operation_back(
|
528
|
+
node.op, (qubit_map[x] for x in node.qargs), check=False
|
529
|
+
)
|
530
|
+
out_dag.global_phase += synth_dag.global_phase
|
531
|
+
else:
|
532
|
+
node_list, global_phase, gate = synth_dag
|
533
|
+
qubits = node.qargs
|
534
|
+
for (
|
535
|
+
op_name,
|
536
|
+
params,
|
537
|
+
qargs,
|
538
|
+
) in node_list:
|
539
|
+
if op_name == "USER_GATE":
|
540
|
+
op = gate
|
541
|
+
else:
|
542
|
+
op = GATE_NAME_MAP[op_name](*params)
|
543
|
+
out_dag.apply_operation_back(
|
544
|
+
op,
|
545
|
+
(qubits[x] for x in qargs),
|
546
|
+
check=False,
|
547
|
+
)
|
548
|
+
out_dag.global_phase += global_phase
|
501
549
|
else:
|
502
|
-
|
503
|
-
|
504
|
-
kwargs["coupling_map"] = (
|
505
|
-
self._coupling_map,
|
506
|
-
[qubit_indices[x] for x in node.qargs],
|
507
|
-
)
|
508
|
-
synth_dag = method.run(unitary, **kwargs)
|
509
|
-
if synth_dag is not None:
|
510
|
-
dag.substitute_node_with_dag(node, synth_dag)
|
511
|
-
return dag
|
550
|
+
out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
551
|
+
return out_dag
|
512
552
|
|
513
553
|
|
514
554
|
def _build_gate_lengths(props=None, target=None):
|
@@ -777,6 +817,13 @@ class DefaultUnitarySynthesis(plugin.UnitarySynthesisPlugin):
|
|
777
817
|
)
|
778
818
|
decomposers.append(decomposer)
|
779
819
|
|
820
|
+
# If our 2q basis gates are a subset of cx, ecr, or cz then we know TwoQubitBasisDecomposer
|
821
|
+
# is an ideal decomposition and there is no need to bother calculating the XX embodiments
|
822
|
+
# or try the XX decomposer
|
823
|
+
if {"cx", "cz", "ecr"}.issuperset(available_2q_basis):
|
824
|
+
self._decomposer_cache[qubits_tuple] = decomposers
|
825
|
+
return decomposers
|
826
|
+
|
780
827
|
# possible controlled decomposers (i.e. XXDecomposer)
|
781
828
|
controlled_basis = {k: v for k, v in available_2q_basis.items() if is_controlled(v)}
|
782
829
|
basis_2q_fidelity = {}
|
@@ -808,10 +855,23 @@ class DefaultUnitarySynthesis(plugin.UnitarySynthesisPlugin):
|
|
808
855
|
if basis_2q_fidelity:
|
809
856
|
for basis_1q in available_1q_basis:
|
810
857
|
if isinstance(pi2_basis, CXGate) and basis_1q == "ZSX":
|
858
|
+
# If we're going to use the pulse optimal decomposition
|
859
|
+
# in TwoQubitBasisDecomposer we need to compute the basis
|
860
|
+
# fidelity to use for the decomposition. Either use the
|
861
|
+
# cx error rate if approximation degree is None, or
|
862
|
+
# the approximation degree value if it's a float
|
863
|
+
if approximation_degree is None:
|
864
|
+
props = target["cx"].get(qubits_tuple)
|
865
|
+
if props is not None:
|
866
|
+
fidelity = 1.0 - getattr(props, "error", 0.0)
|
867
|
+
else:
|
868
|
+
fidelity = 1.0
|
869
|
+
else:
|
870
|
+
fidelity = approximation_degree
|
811
871
|
pi2_decomposer = TwoQubitBasisDecomposer(
|
812
872
|
pi2_basis,
|
813
873
|
euler_basis=basis_1q,
|
814
|
-
basis_fidelity=
|
874
|
+
basis_fidelity=fidelity,
|
815
875
|
pulse_optimize=True,
|
816
876
|
)
|
817
877
|
embodiments.update({pi / 2: XXEmbodiments[pi2_decomposer.gate.base_class]})
|
@@ -862,6 +922,20 @@ class DefaultUnitarySynthesis(plugin.UnitarySynthesisPlugin):
|
|
862
922
|
decomposers2q = [decomposer2q] if decomposer2q is not None else []
|
863
923
|
# choose the cheapest output among synthesized circuits
|
864
924
|
synth_circuits = []
|
925
|
+
# If we have a single TwoQubitBasisDecomposer skip dag creation as we don't need to
|
926
|
+
# store and can instead manually create the synthesized gates directly in the output dag
|
927
|
+
if len(decomposers2q) == 1 and isinstance(decomposers2q[0], TwoQubitBasisDecomposer):
|
928
|
+
preferred_direction = _preferred_direction(
|
929
|
+
decomposers2q[0],
|
930
|
+
qubits,
|
931
|
+
natural_direction,
|
932
|
+
coupling_map,
|
933
|
+
gate_lengths,
|
934
|
+
gate_errors,
|
935
|
+
)
|
936
|
+
return self._synth_su4_no_dag(
|
937
|
+
unitary, decomposers2q[0], preferred_direction, approximation_degree
|
938
|
+
)
|
865
939
|
for decomposer2q in decomposers2q:
|
866
940
|
preferred_direction = _preferred_direction(
|
867
941
|
decomposer2q, qubits, natural_direction, coupling_map, gate_lengths, gate_errors
|
@@ -882,24 +956,57 @@ class DefaultUnitarySynthesis(plugin.UnitarySynthesisPlugin):
|
|
882
956
|
|
883
957
|
# only decompose if needed. TODO: handle basis better
|
884
958
|
synth_circuit = qs_decomposition(unitary) if (basis_gates or target) else None
|
959
|
+
if synth_circuit is None:
|
960
|
+
return None
|
961
|
+
if isinstance(synth_circuit, DAGCircuit):
|
962
|
+
return synth_circuit
|
963
|
+
return circuit_to_dag(synth_circuit)
|
885
964
|
|
886
|
-
|
887
|
-
return synth_dag
|
888
|
-
|
889
|
-
def _synth_su4(self, su4_mat, decomposer2q, preferred_direction, approximation_degree):
|
965
|
+
def _synth_su4_no_dag(self, unitary, decomposer2q, preferred_direction, approximation_degree):
|
890
966
|
approximate = not approximation_degree == 1.0
|
891
|
-
synth_circ = decomposer2q(
|
967
|
+
synth_circ = decomposer2q._inner_decomposer(unitary, approximate=approximate)
|
968
|
+
if not preferred_direction:
|
969
|
+
return (synth_circ, synth_circ.global_phase, decomposer2q.gate)
|
892
970
|
|
971
|
+
synth_direction = None
|
893
972
|
# if the gates in synthesis are in the opposite direction of the preferred direction
|
894
973
|
# resynthesize a new operator which is the original conjugated by swaps.
|
895
974
|
# this new operator is doubly mirrored from the original and is locally equivalent.
|
975
|
+
for op_name, _params, qubits in synth_circ:
|
976
|
+
if op_name in {"USER_GATE", "cx"}:
|
977
|
+
synth_direction = qubits
|
978
|
+
if synth_direction is not None and synth_direction != preferred_direction:
|
979
|
+
# TODO: Avoid using a dag to correct the synthesis direction
|
980
|
+
return self._reversed_synth_su4(unitary, decomposer2q, approximation_degree)
|
981
|
+
return (synth_circ, synth_circ.global_phase, decomposer2q.gate)
|
982
|
+
|
983
|
+
def _synth_su4(self, su4_mat, decomposer2q, preferred_direction, approximation_degree):
|
984
|
+
approximate = not approximation_degree == 1.0
|
985
|
+
synth_circ = decomposer2q(su4_mat, approximate=approximate, use_dag=True)
|
986
|
+
if not preferred_direction:
|
987
|
+
return synth_circ
|
896
988
|
synth_direction = None
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
989
|
+
# if the gates in synthesis are in the opposite direction of the preferred direction
|
990
|
+
# resynthesize a new operator which is the original conjugated by swaps.
|
991
|
+
# this new operator is doubly mirrored from the original and is locally equivalent.
|
992
|
+
for inst in synth_circ.topological_op_nodes():
|
993
|
+
if inst.op.num_qubits == 2:
|
994
|
+
synth_direction = [synth_circ.find_bit(q).index for q in inst.qargs]
|
995
|
+
if synth_direction is not None and synth_direction != preferred_direction:
|
996
|
+
return self._reversed_synth_su4(su4_mat, decomposer2q, approximation_degree)
|
905
997
|
return synth_circ
|
998
|
+
|
999
|
+
def _reversed_synth_su4(self, su4_mat, decomposer2q, approximation_degree):
|
1000
|
+
approximate = not approximation_degree == 1.0
|
1001
|
+
su4_mat_mm = su4_mat.copy()
|
1002
|
+
su4_mat_mm[[1, 2]] = su4_mat_mm[[2, 1]]
|
1003
|
+
su4_mat_mm[:, [1, 2]] = su4_mat_mm[:, [2, 1]]
|
1004
|
+
synth_circ = decomposer2q(su4_mat_mm, approximate=approximate, use_dag=True)
|
1005
|
+
out_dag = DAGCircuit()
|
1006
|
+
out_dag.global_phase = synth_circ.global_phase
|
1007
|
+
out_dag.add_qubits(list(reversed(synth_circ.qubits)))
|
1008
|
+
flip_bits = out_dag.qubits[::-1]
|
1009
|
+
for node in synth_circ.topological_op_nodes():
|
1010
|
+
qubits = tuple(flip_bits[synth_circ.find_bit(x).index] for x in node.qargs)
|
1011
|
+
out_dag.apply_operation_back(node.op, qubits, check=False)
|
1012
|
+
return out_dag
|
@@ -32,7 +32,7 @@ class GatesInBasis(AnalysisPass):
|
|
32
32
|
self._basis_gates = None
|
33
33
|
if basis_gates is not None:
|
34
34
|
self._basis_gates = set(basis_gates).union(
|
35
|
-
{"measure", "reset", "barrier", "snapshot", "delay"}
|
35
|
+
{"measure", "reset", "barrier", "snapshot", "delay", "store"}
|
36
36
|
)
|
37
37
|
self._target = target
|
38
38
|
|
@@ -46,8 +46,8 @@ class GatesInBasis(AnalysisPass):
|
|
46
46
|
|
47
47
|
def _visit_target(dag, wire_map):
|
48
48
|
for gate in dag.op_nodes():
|
49
|
-
# Barrier
|
50
|
-
if gate.name
|
49
|
+
# Barrier and store are assumed universal and supported by all backends
|
50
|
+
if gate.name in ("barrier", "store"):
|
51
51
|
continue
|
52
52
|
if not self._target.instruction_supported(
|
53
53
|
gate.name, tuple(wire_map[bit] for bit in gate.qargs)
|
qiskit/transpiler/passmanager.py
CHANGED
@@ -29,7 +29,7 @@ from qiskit.passmanager.flow_controllers import FlowControllerLinear
|
|
29
29
|
from qiskit.passmanager.exceptions import PassManagerError
|
30
30
|
from .basepasses import BasePass
|
31
31
|
from .exceptions import TranspilerError
|
32
|
-
from .layout import TranspileLayout
|
32
|
+
from .layout import TranspileLayout, Layout
|
33
33
|
|
34
34
|
_CircuitsT = Union[List[QuantumCircuit], QuantumCircuit]
|
35
35
|
|
@@ -69,6 +69,7 @@ class PassManager(BasePassManager):
|
|
69
69
|
) -> QuantumCircuit:
|
70
70
|
out_program = dag_to_circuit(passmanager_ir, copy_operations=False)
|
71
71
|
|
72
|
+
self._finalize_layouts(passmanager_ir)
|
72
73
|
out_name = kwargs.get("output_name", None)
|
73
74
|
if out_name is not None:
|
74
75
|
out_program.name = out_name
|
@@ -96,6 +97,48 @@ class PassManager(BasePassManager):
|
|
96
97
|
|
97
98
|
return out_program
|
98
99
|
|
100
|
+
def _finalize_layouts(self, dag):
|
101
|
+
if (virtual_permutation_layout := self.property_set["virtual_permutation_layout"]) is None:
|
102
|
+
return
|
103
|
+
|
104
|
+
self.property_set.pop("virtual_permutation_layout")
|
105
|
+
|
106
|
+
# virtual_permutation_layout is usually created before extending the layout with ancillas,
|
107
|
+
# so we extend the permutation to be identity on ancilla qubits
|
108
|
+
original_qubit_indices = self.property_set.get("original_qubit_indices", None)
|
109
|
+
for oq in original_qubit_indices:
|
110
|
+
if oq not in virtual_permutation_layout:
|
111
|
+
virtual_permutation_layout[oq] = original_qubit_indices[oq]
|
112
|
+
|
113
|
+
t_qubits = dag.qubits
|
114
|
+
|
115
|
+
if (t_initial_layout := self.property_set.get("layout", None)) is None:
|
116
|
+
t_initial_layout = Layout(dict(enumerate(t_qubits)))
|
117
|
+
|
118
|
+
if (t_final_layout := self.property_set.get("final_layout", None)) is None:
|
119
|
+
t_final_layout = Layout(dict(enumerate(t_qubits)))
|
120
|
+
|
121
|
+
# Ordered list of original qubits
|
122
|
+
original_qubits_reverse = {v: k for k, v in original_qubit_indices.items()}
|
123
|
+
original_qubits = []
|
124
|
+
for i in range(len(original_qubits_reverse)):
|
125
|
+
original_qubits.append(original_qubits_reverse[i])
|
126
|
+
|
127
|
+
virtual_permutation_layout_inv = virtual_permutation_layout.inverse(
|
128
|
+
original_qubits, original_qubits
|
129
|
+
)
|
130
|
+
|
131
|
+
t_initial_layout_inv = t_initial_layout.inverse(original_qubits, t_qubits)
|
132
|
+
|
133
|
+
# ToDo: this can possibly be made simpler
|
134
|
+
new_final_layout = t_initial_layout_inv
|
135
|
+
new_final_layout = new_final_layout.compose(virtual_permutation_layout_inv, original_qubits)
|
136
|
+
new_final_layout = new_final_layout.compose(t_initial_layout, original_qubits)
|
137
|
+
new_final_layout = new_final_layout.compose(t_final_layout, t_qubits)
|
138
|
+
|
139
|
+
self.property_set["layout"] = t_initial_layout
|
140
|
+
self.property_set["final_layout"] = new_final_layout
|
141
|
+
|
99
142
|
def append(
|
100
143
|
self,
|
101
144
|
passes: Task | list[Task],
|
@@ -115,7 +115,7 @@ def generate_preset_pass_manager(
|
|
115
115
|
|
116
116
|
backend (Backend): An optional backend object which can be used as the
|
117
117
|
source of the default values for the ``basis_gates``, ``inst_map``,
|
118
|
-
``
|
118
|
+
``coupling_map``, ``backend_properties``, ``instruction_durations``,
|
119
119
|
``timing_constraints``, and ``target``. If any of those other arguments
|
120
120
|
are specified in addition to ``backend`` they will take precedence
|
121
121
|
over the value contained in the backend.
|
@@ -136,11 +136,11 @@ def generate_preset_pass_manager(
|
|
136
136
|
instruction_durations (InstructionDurations): Dictionary of duration
|
137
137
|
(in dt) for each instruction.
|
138
138
|
timing_constraints (TimingConstraints): Hardware time alignment restrictions.
|
139
|
-
initial_layout (Layout): Initial position of virtual qubits on
|
139
|
+
initial_layout (Layout | List[int]): Initial position of virtual qubits on
|
140
140
|
physical qubits.
|
141
141
|
layout_method (str): The :class:`~.Pass` to use for choosing initial qubit
|
142
142
|
placement. Valid choices are ``'trivial'``, ``'dense'``,
|
143
|
-
and ``'sabre'``, representing :class:`~.TrivialLayout`, :class
|
143
|
+
and ``'sabre'``, representing :class:`~.TrivialLayout`, :class:`~.DenseLayout` and
|
144
144
|
:class:`~.SabreLayout` respectively. This can also
|
145
145
|
be the external plugin name to use for the ``layout`` stage of the output
|
146
146
|
:class:`~.StagedPassManager`. You can see a list of installed plugins by using
|
@@ -26,7 +26,7 @@ from qiskit.transpiler.passes import DenseLayout
|
|
26
26
|
from qiskit.transpiler.passes import TrivialLayout
|
27
27
|
from qiskit.transpiler.passes import CheckMap
|
28
28
|
from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements
|
29
|
-
from qiskit.transpiler.passes import
|
29
|
+
from qiskit.transpiler.passes import ElidePermutations
|
30
30
|
from qiskit.transpiler.passes import RemoveDiagonalGatesBeforeMeasure
|
31
31
|
from qiskit.transpiler.preset_passmanagers import common
|
32
32
|
from qiskit.transpiler.preset_passmanagers.plugin import (
|
@@ -87,7 +87,7 @@ class DefaultInitPassManager(PassManagerStagePlugin):
|
|
87
87
|
pass_manager_config.unitary_synthesis_plugin_config,
|
88
88
|
pass_manager_config.hls_config,
|
89
89
|
)
|
90
|
-
elif optimization_level
|
90
|
+
elif optimization_level == 1:
|
91
91
|
init = PassManager()
|
92
92
|
if (
|
93
93
|
pass_manager_config.initial_layout
|
@@ -124,7 +124,7 @@ class DefaultInitPassManager(PassManagerStagePlugin):
|
|
124
124
|
)
|
125
125
|
)
|
126
126
|
|
127
|
-
elif optimization_level
|
127
|
+
elif optimization_level in {2, 3}:
|
128
128
|
init = common.generate_unroll_3q(
|
129
129
|
pass_manager_config.target,
|
130
130
|
pass_manager_config.basis_gates,
|
@@ -133,7 +133,7 @@ class DefaultInitPassManager(PassManagerStagePlugin):
|
|
133
133
|
pass_manager_config.unitary_synthesis_plugin_config,
|
134
134
|
pass_manager_config.hls_config,
|
135
135
|
)
|
136
|
-
init.append(
|
136
|
+
init.append(ElidePermutations())
|
137
137
|
init.append(RemoveDiagonalGatesBeforeMeasure())
|
138
138
|
init.append(
|
139
139
|
InverseCancellation(
|
@@ -153,9 +153,9 @@ class DefaultInitPassManager(PassManagerStagePlugin):
|
|
153
153
|
]
|
154
154
|
)
|
155
155
|
)
|
156
|
-
|
156
|
+
init.append(CommutativeCancellation())
|
157
157
|
else:
|
158
|
-
|
158
|
+
raise TranspilerError(f"Invalid optimization level {optimization_level}")
|
159
159
|
return init
|
160
160
|
|
161
161
|
|
@@ -540,16 +540,13 @@ class OptimizationPassManager(PassManagerStagePlugin):
|
|
540
540
|
]
|
541
541
|
),
|
542
542
|
]
|
543
|
+
|
543
544
|
elif optimization_level == 2:
|
544
|
-
# Steps for optimization level 2
|
545
545
|
_opt = [
|
546
546
|
Optimize1qGatesDecomposition(
|
547
547
|
basis=pass_manager_config.basis_gates, target=pass_manager_config.target
|
548
548
|
),
|
549
|
-
CommutativeCancellation(
|
550
|
-
basis_gates=pass_manager_config.basis_gates,
|
551
|
-
target=pass_manager_config.target,
|
552
|
-
),
|
549
|
+
CommutativeCancellation(target=pass_manager_config.target),
|
553
550
|
]
|
554
551
|
elif optimization_level == 3:
|
555
552
|
# Steps for optimization level 3
|
@@ -595,6 +592,27 @@ class OptimizationPassManager(PassManagerStagePlugin):
|
|
595
592
|
|
596
593
|
if optimization_level == 3:
|
597
594
|
optimization.append(_minimum_point_check)
|
595
|
+
elif optimization_level == 2:
|
596
|
+
optimization.append(
|
597
|
+
[
|
598
|
+
Collect2qBlocks(),
|
599
|
+
ConsolidateBlocks(
|
600
|
+
basis_gates=pass_manager_config.basis_gates,
|
601
|
+
target=pass_manager_config.target,
|
602
|
+
approximation_degree=pass_manager_config.approximation_degree,
|
603
|
+
),
|
604
|
+
UnitarySynthesis(
|
605
|
+
pass_manager_config.basis_gates,
|
606
|
+
approximation_degree=pass_manager_config.approximation_degree,
|
607
|
+
coupling_map=pass_manager_config.coupling_map,
|
608
|
+
backend_props=pass_manager_config.backend_properties,
|
609
|
+
method=pass_manager_config.unitary_synthesis_method,
|
610
|
+
plugin_config=pass_manager_config.unitary_synthesis_plugin_config,
|
611
|
+
target=pass_manager_config.target,
|
612
|
+
),
|
613
|
+
]
|
614
|
+
)
|
615
|
+
optimization.append(_depth_check + _size_check)
|
598
616
|
else:
|
599
617
|
optimization.append(_depth_check + _size_check)
|
600
618
|
opt_loop = (
|
@@ -746,7 +764,7 @@ class DefaultLayoutPassManager(PassManagerStagePlugin):
|
|
746
764
|
call_limit=int(5e6), # Set call limit to ~10s with rustworkx 0.10.2
|
747
765
|
properties=pass_manager_config.backend_properties,
|
748
766
|
target=pass_manager_config.target,
|
749
|
-
max_trials=
|
767
|
+
max_trials=2500, # Limits layout scoring to < 600ms on ~400 qubit devices
|
750
768
|
)
|
751
769
|
layout.append(
|
752
770
|
ConditionalController(choose_layout_0, condition=_choose_layout_condition)
|
@@ -755,8 +773,8 @@ class DefaultLayoutPassManager(PassManagerStagePlugin):
|
|
755
773
|
coupling_map,
|
756
774
|
max_iterations=2,
|
757
775
|
seed=pass_manager_config.seed_transpiler,
|
758
|
-
swap_trials=
|
759
|
-
layout_trials=
|
776
|
+
swap_trials=20,
|
777
|
+
layout_trials=20,
|
760
778
|
skip_routing=pass_manager_config.routing_method is not None
|
761
779
|
and pass_manager_config.routing_method != "sabre",
|
762
780
|
)
|
@@ -908,8 +926,8 @@ class SabreLayoutPassManager(PassManagerStagePlugin):
|
|
908
926
|
coupling_map,
|
909
927
|
max_iterations=2,
|
910
928
|
seed=pass_manager_config.seed_transpiler,
|
911
|
-
swap_trials=
|
912
|
-
layout_trials=
|
929
|
+
swap_trials=20,
|
930
|
+
layout_trials=20,
|
913
931
|
skip_routing=pass_manager_config.routing_method is not None
|
914
932
|
and pass_manager_config.routing_method != "sabre",
|
915
933
|
)
|
@@ -584,6 +584,7 @@ def generate_scheduling(
|
|
584
584
|
InstructionDurationCheck(
|
585
585
|
acquire_alignment=timing_constraints.acquire_alignment,
|
586
586
|
pulse_alignment=timing_constraints.pulse_alignment,
|
587
|
+
target=target,
|
587
588
|
)
|
588
589
|
)
|
589
590
|
scheduling.append(
|
@@ -591,6 +592,7 @@ def generate_scheduling(
|
|
591
592
|
ConstrainedReschedule(
|
592
593
|
acquire_alignment=timing_constraints.acquire_alignment,
|
593
594
|
pulse_alignment=timing_constraints.pulse_alignment,
|
595
|
+
target=target,
|
594
596
|
),
|
595
597
|
condition=_require_alignment,
|
596
598
|
)
|
@@ -599,6 +601,7 @@ def generate_scheduling(
|
|
599
601
|
ValidatePulseGates(
|
600
602
|
granularity=timing_constraints.granularity,
|
601
603
|
min_length=timing_constraints.min_length,
|
604
|
+
target=target,
|
602
605
|
)
|
603
606
|
)
|
604
607
|
if scheduling_method:
|
@@ -624,16 +627,11 @@ def get_vf2_limits(
|
|
624
627
|
"""
|
625
628
|
limits = VF2Limits(None, None)
|
626
629
|
if layout_method is None and initial_layout is None:
|
627
|
-
if optimization_level
|
630
|
+
if optimization_level in {1, 2}:
|
628
631
|
limits = VF2Limits(
|
629
632
|
int(5e4), # Set call limit to ~100ms with rustworkx 0.10.2
|
630
633
|
2500, # Limits layout scoring to < 600ms on ~400 qubit devices
|
631
634
|
)
|
632
|
-
elif optimization_level == 2:
|
633
|
-
limits = VF2Limits(
|
634
|
-
int(5e6), # Set call limit to ~10 sec with rustworkx 0.10.2
|
635
|
-
25000, # Limits layout scoring to < 6 sec on ~400 qubit devices
|
636
|
-
)
|
637
635
|
elif optimization_level == 3:
|
638
636
|
limits = VF2Limits(
|
639
637
|
int(3e7), # Set call limit to ~60 sec with rustworkx 0.10.2
|
@@ -68,7 +68,15 @@ load external plugins via corresponding entry points.
|
|
68
68
|
connectivity constraints of the target backend. This does not necessarily
|
69
69
|
need to match the directionality of the edges in the target as a later
|
70
70
|
stage typically will adjust directional gates to match that constraint
|
71
|
-
(but there is no penalty for doing that in the ``routing`` stage).
|
71
|
+
(but there is no penalty for doing that in the ``routing`` stage). The output
|
72
|
+
of this stage is also expected to have the ``final_layout`` property set field
|
73
|
+
set with a :class:`~.Layout` object that maps the :class:`.Qubit` to the
|
74
|
+
output final position of that qubit in the circuit. If there is an
|
75
|
+
existing ``final_layout`` entry in the property set (such as might be set
|
76
|
+
by an optimization pass that introduces a permutation) it is expected
|
77
|
+
that the final layout will be the composition of the two layouts (this
|
78
|
+
can be computed using :meth:`.DAGCircuit.compose`, for example:
|
79
|
+
``second_final_layout.compose(first_final_layout, dag.qubits)``).
|
72
80
|
* - ``translation``
|
73
81
|
- ``qiskit.transpiler.translation``
|
74
82
|
- ``translator``, ``synthesis``, ``unroller``
|
qiskit/utils/__init__.py
CHANGED
@@ -44,7 +44,7 @@ Multiprocessing
|
|
44
44
|
.. autofunction:: local_hardware_info
|
45
45
|
.. autofunction:: is_main_process
|
46
46
|
|
47
|
-
A helper function for calling a custom function with
|
47
|
+
A helper function for calling a custom function with Python
|
48
48
|
:class:`~concurrent.futures.ProcessPoolExecutor`. Tasks can be executed in parallel using this function.
|
49
49
|
|
50
50
|
.. autofunction:: parallel_map
|
@@ -70,7 +70,7 @@ from .lazy_tester import LazyDependencyManager, LazyImportTester, LazySubprocess
|
|
70
70
|
|
71
71
|
from . import optionals
|
72
72
|
|
73
|
-
from .parallel import parallel_map
|
73
|
+
from .parallel import parallel_map, should_run_in_parallel
|
74
74
|
|
75
75
|
__all__ = [
|
76
76
|
"LazyDependencyManager",
|
@@ -85,4 +85,5 @@ __all__ = [
|
|
85
85
|
"is_main_process",
|
86
86
|
"apply_prefix",
|
87
87
|
"parallel_map",
|
88
|
+
"should_run_in_parallel",
|
88
89
|
]
|
qiskit/utils/optionals.py
CHANGED
@@ -307,8 +307,12 @@ HAS_Z3 = _LazyImportTester("z3", install="pip install z3-solver")
|
|
307
307
|
|
308
308
|
HAS_GRAPHVIZ = _LazySubprocessTester(
|
309
309
|
("dot", "-V"),
|
310
|
-
name="
|
311
|
-
|
310
|
+
name="Graphviz",
|
311
|
+
msg=(
|
312
|
+
"To install, follow the instructions at https://graphviz.org/download/."
|
313
|
+
" Qiskit needs the Graphviz binaries, which the 'graphviz' package on pip does not install."
|
314
|
+
" You must install the actual Graphviz software"
|
315
|
+
),
|
312
316
|
)
|
313
317
|
HAS_PDFLATEX = _LazySubprocessTester(
|
314
318
|
("pdflatex", "-version"),
|