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
@@ -23,6 +23,7 @@ from qiskit.transpiler.layout import Layout
|
|
23
23
|
from qiskit.transpiler.basepasses import AnalysisPass
|
24
24
|
from qiskit.transpiler.exceptions import TranspilerError
|
25
25
|
from qiskit.transpiler.passes.layout import vf2_utils
|
26
|
+
from qiskit._accelerate.vf2_layout import vf2_layout_pass, MultiQEncountered
|
26
27
|
|
27
28
|
|
28
29
|
logger = logging.getLogger(__name__)
|
@@ -110,13 +111,7 @@ class VF2Layout(AnalysisPass):
|
|
110
111
|
"""
|
111
112
|
super().__init__()
|
112
113
|
self.target = target
|
113
|
-
|
114
|
-
target is not None
|
115
|
-
and (target_coupling_map := self.target.build_coupling_map()) is not None
|
116
|
-
):
|
117
|
-
self.coupling_map = target_coupling_map
|
118
|
-
else:
|
119
|
-
self.coupling_map = coupling_map
|
114
|
+
self.coupling_map = coupling_map
|
120
115
|
self.strict_direction = strict_direction
|
121
116
|
self.seed = seed
|
122
117
|
self.call_limit = call_limit
|
@@ -126,11 +121,52 @@ class VF2Layout(AnalysisPass):
|
|
126
121
|
|
127
122
|
def run(self, dag):
|
128
123
|
"""run the layout method"""
|
129
|
-
if self.coupling_map is None:
|
124
|
+
if self.target is None and self.coupling_map is None:
|
130
125
|
raise TranspilerError("coupling_map or target must be specified.")
|
126
|
+
if self.coupling_map is None:
|
127
|
+
target, coupling_map = self.target, self.target.build_coupling_map()
|
128
|
+
elif self.target is None:
|
129
|
+
coupling_map = self.coupling_map
|
130
|
+
target = vf2_utils.build_dummy_target(coupling_map)
|
131
|
+
else:
|
132
|
+
# We have both, but may need to override the target if it has no connectivity.
|
133
|
+
coupling_map = self.target.build_coupling_map()
|
134
|
+
if coupling_map is None:
|
135
|
+
target = vf2_utils.build_dummy_target(self.coupling_map)
|
136
|
+
coupling_map = self.coupling_map
|
137
|
+
else:
|
138
|
+
target = self.target
|
131
139
|
self.avg_error_map = self.property_set["vf2_avg_error_map"]
|
140
|
+
# Run rust fast path if we have no randomization
|
141
|
+
if self.seed == -1:
|
142
|
+
try:
|
143
|
+
layout = vf2_layout_pass(
|
144
|
+
dag,
|
145
|
+
target,
|
146
|
+
self.strict_direction,
|
147
|
+
self.call_limit,
|
148
|
+
self.time_limit,
|
149
|
+
self.max_trials,
|
150
|
+
self.avg_error_map,
|
151
|
+
)
|
152
|
+
except MultiQEncountered:
|
153
|
+
self.property_set["VF2Layout_stop_reason"] = VF2LayoutStopReason.MORE_THAN_2Q
|
154
|
+
return
|
155
|
+
if layout is None:
|
156
|
+
self.property_set["VF2Layout_stop_reason"] = VF2LayoutStopReason.NO_SOLUTION_FOUND
|
157
|
+
return
|
158
|
+
|
159
|
+
self.property_set["VF2Layout_stop_reason"] = VF2LayoutStopReason.SOLUTION_FOUND
|
160
|
+
mapping = {dag.qubits[virt]: phys for virt, phys in layout.items()}
|
161
|
+
chosen_layout = Layout(mapping)
|
162
|
+
self.property_set["layout"] = chosen_layout
|
163
|
+
for reg in dag.qregs.values():
|
164
|
+
self.property_set["layout"].add_register(reg)
|
165
|
+
return
|
166
|
+
# We can't use the rust fast path because we have a seed set, or no target so continue with
|
167
|
+
# the python path
|
132
168
|
if self.avg_error_map is None:
|
133
|
-
self.avg_error_map = vf2_utils.build_average_error_map(
|
169
|
+
self.avg_error_map = vf2_utils.build_average_error_map(target, coupling_map)
|
134
170
|
|
135
171
|
result = vf2_utils.build_interaction_graph(dag, self.strict_direction)
|
136
172
|
if result is None:
|
@@ -140,12 +176,12 @@ class VF2Layout(AnalysisPass):
|
|
140
176
|
scoring_edge_list = vf2_utils.build_edge_list(im_graph)
|
141
177
|
scoring_bit_list = vf2_utils.build_bit_list(im_graph, im_graph_node_map)
|
142
178
|
cm_graph, cm_nodes = vf2_utils.shuffle_coupling_graph(
|
143
|
-
|
179
|
+
coupling_map, self.seed, self.strict_direction
|
144
180
|
)
|
145
181
|
# Filter qubits without any supported operations. If they don't support any operations
|
146
182
|
# They're not valid for layout selection
|
147
|
-
if
|
148
|
-
has_operations = set(itertools.chain.from_iterable(
|
183
|
+
if target is not None and target.qargs is not None:
|
184
|
+
has_operations = set(itertools.chain.from_iterable(target.qargs))
|
149
185
|
to_remove = set(range(len(cm_nodes))).difference(has_operations)
|
150
186
|
if to_remove:
|
151
187
|
cm_graph.remove_nodes_from([cm_nodes[i] for i in to_remove])
|
@@ -156,7 +192,7 @@ class VF2Layout(AnalysisPass):
|
|
156
192
|
# mapping in the search space if no other limits are set
|
157
193
|
if self.max_trials is None and self.call_limit is None and self.time_limit is None:
|
158
194
|
im_graph_edge_count = len(im_graph.edge_list())
|
159
|
-
cm_graph_edge_count = len(
|
195
|
+
cm_graph_edge_count = len(coupling_map.graph.edge_list())
|
160
196
|
self.max_trials = max(im_graph_edge_count, cm_graph_edge_count) + 15
|
161
197
|
|
162
198
|
logger.debug("Running VF2 to find mappings")
|
@@ -20,6 +20,7 @@ from rustworkx import PyDiGraph, PyGraph, connected_components
|
|
20
20
|
|
21
21
|
from qiskit.circuit import ForLoopOp
|
22
22
|
from qiskit.converters import circuit_to_dag
|
23
|
+
from qiskit.transpiler.target import Target
|
23
24
|
from qiskit._accelerate import vf2_layout
|
24
25
|
from qiskit._accelerate.nlayout import NLayout
|
25
26
|
from qiskit._accelerate.error_map import ErrorMap
|
@@ -141,6 +142,15 @@ def score_layout(
|
|
141
142
|
)
|
142
143
|
|
143
144
|
|
145
|
+
def build_dummy_target(coupling_map) -> Target:
|
146
|
+
"""Build a dummy target with no error rates that represents the coupling in ``coupling_map``."""
|
147
|
+
# The choice of basis gates is completely arbitrary, and we have no source of error rates.
|
148
|
+
# We just want _something_ to represent the coupling constraints.
|
149
|
+
return Target.from_configuration(
|
150
|
+
basis_gates=["u", "cx"], num_qubits=coupling_map.size(), coupling_map=coupling_map
|
151
|
+
)
|
152
|
+
|
153
|
+
|
144
154
|
def build_average_error_map(target, coupling_map):
|
145
155
|
"""Build an average error map used for scoring layouts pre-basis translation."""
|
146
156
|
num_qubits = 0
|
@@ -39,4 +39,4 @@ from .remove_identity_equiv import RemoveIdentityEquivalent
|
|
39
39
|
from .split_2q_unitaries import Split2QUnitaries
|
40
40
|
from .collect_and_collapse import CollectAndCollapse
|
41
41
|
from .contract_idle_wires_in_control_flow import ContractIdleWiresInControlFlow
|
42
|
-
from .
|
42
|
+
from .optimize_clifford_t import OptimizeCliffordT
|
@@ -19,6 +19,7 @@ from qiskit.transpiler.basepasses import TransformationPass
|
|
19
19
|
from qiskit.transpiler.passes.utils import control_flow
|
20
20
|
from qiskit.synthesis.one_qubit import one_qubit_decompose
|
21
21
|
from qiskit._accelerate import euler_one_qubit_decomposer
|
22
|
+
from qiskit._accelerate import optimize_1q_gates_decomposition
|
22
23
|
from qiskit.circuit.library.standard_gates import (
|
23
24
|
UGate,
|
24
25
|
PhaseGate,
|
@@ -207,7 +208,7 @@ class Optimize1qGatesDecomposition(TransformationPass):
|
|
207
208
|
Returns:
|
208
209
|
DAGCircuit: the optimized DAG.
|
209
210
|
"""
|
210
|
-
|
211
|
+
optimize_1q_gates_decomposition.optimize_1q_gates_decomposition(
|
211
212
|
dag,
|
212
213
|
target=self._target,
|
213
214
|
global_decomposers=self._global_decomposers,
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2025.
|
4
|
+
#
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
8
|
+
#
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
11
|
+
# that they have been altered from the originals.
|
12
|
+
|
13
|
+
"""Combine consecutive T/Tdg gates in a Clifford+T circuit."""
|
14
|
+
|
15
|
+
from qiskit.dagcircuit import DAGCircuit
|
16
|
+
from qiskit.transpiler.basepasses import TransformationPass
|
17
|
+
from qiskit.circuit.library import SGate, SdgGate
|
18
|
+
|
19
|
+
|
20
|
+
class OptimizeCliffordT(TransformationPass):
|
21
|
+
"""An optimization pass for Clifford+T circuits.
|
22
|
+
|
23
|
+
Currently all the pass does is merging pairs of consecutive T-gates into
|
24
|
+
S-gates, and pair of consecutive Tdg-gates into Sdg-gates.
|
25
|
+
"""
|
26
|
+
|
27
|
+
def run(self, dag: DAGCircuit):
|
28
|
+
"""
|
29
|
+
Run the OptimizeCliffordT pass on `dag`.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
dag: The directed acyclic graph to run on.
|
33
|
+
|
34
|
+
Returns:
|
35
|
+
DAGCircuit: Transformed DAG.
|
36
|
+
"""
|
37
|
+
|
38
|
+
new_dag = dag.copy_empty_like()
|
39
|
+
|
40
|
+
nodes = list(dag.topological_op_nodes())
|
41
|
+
num_nodes = len(nodes)
|
42
|
+
idx = 0
|
43
|
+
|
44
|
+
while idx < num_nodes - 1:
|
45
|
+
cur_node = nodes[idx]
|
46
|
+
next_node = nodes[idx + 1]
|
47
|
+
if cur_node.name == "t" and next_node.name == "t" and cur_node.qargs == next_node.qargs:
|
48
|
+
# Combine two consecutive T-gates into an S-gate
|
49
|
+
new_dag.apply_operation_back(SGate(), cur_node.qargs, cur_node.cargs)
|
50
|
+
idx += 2
|
51
|
+
elif (
|
52
|
+
nodes[idx].name == "tdg"
|
53
|
+
and nodes[idx + 1].name == "tdg"
|
54
|
+
and nodes[idx].qargs == nodes[idx + 1].qargs
|
55
|
+
):
|
56
|
+
# Combine two consecutive Tdg-gates into an Sdg-gate
|
57
|
+
new_dag.apply_operation_back(SdgGate(), cur_node.qargs, cur_node.cargs)
|
58
|
+
idx += 2
|
59
|
+
else:
|
60
|
+
new_dag.apply_operation_back(cur_node.op, cur_node.qargs, cur_node.cargs)
|
61
|
+
idx += 1
|
62
|
+
|
63
|
+
# Handle the last element (if any)
|
64
|
+
if idx == num_nodes - 1:
|
65
|
+
cur_node = nodes[idx]
|
66
|
+
new_dag.apply_operation_back(cur_node.op, cur_node.qargs, cur_node.cargs)
|
67
|
+
|
68
|
+
return new_dag
|
@@ -497,14 +497,8 @@ class TemplateSubstitution:
|
|
497
497
|
"""
|
498
498
|
import sympy as sym
|
499
499
|
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
# Converts Sympy expressions to Symengine ones.
|
504
|
-
to_native_symbolic = symengine.sympify
|
505
|
-
else:
|
506
|
-
# Our native form is sympy, so we don't need to do anything.
|
507
|
-
to_native_symbolic = lambda x: x
|
500
|
+
# Our native form is sympy, so we don't need to do anything.
|
501
|
+
to_native_symbolic = lambda x: x
|
508
502
|
|
509
503
|
circuit_params, template_params = [], []
|
510
504
|
# Set of all parameter names that are present in the circuits to be optimized.
|
@@ -596,7 +590,7 @@ class TemplateSubstitution:
|
|
596
590
|
return None
|
597
591
|
# If there's multiple solutions, arbitrarily pick the first one.
|
598
592
|
sol = {
|
599
|
-
param.name: ParameterExpression(circ_dict, to_native_symbolic(expr))
|
593
|
+
param.name: ParameterExpression(circ_dict, str(to_native_symbolic(expr)))
|
600
594
|
for param, expr in sym_sol[0].items()
|
601
595
|
}
|
602
596
|
fake_bind = {key: sol[key.name] for key in temp_symbols}
|
@@ -210,6 +210,8 @@ class SabreSwap(TransformationPass):
|
|
210
210
|
" This circuit cannot be routed to this device."
|
211
211
|
)
|
212
212
|
|
213
|
+
# In our defaults, the basic heuristic shouldn't scale by size; if it does, it's liable to
|
214
|
+
# get the algorithm stuck. See https://github.com/Qiskit/qiskit/pull/14458 for more.
|
213
215
|
if isinstance(self.heuristic, Heuristic):
|
214
216
|
heuristic = self.heuristic
|
215
217
|
elif self.heuristic == "basic":
|
@@ -219,13 +221,13 @@ class SabreSwap(TransformationPass):
|
|
219
221
|
elif self.heuristic == "lookahead":
|
220
222
|
heuristic = (
|
221
223
|
Heuristic(attempt_limit=10 * num_dag_qubits)
|
222
|
-
.with_basic(1.0, SetScaling.
|
224
|
+
.with_basic(1.0, SetScaling.Constant)
|
223
225
|
.with_lookahead(0.5, 20, SetScaling.Size)
|
224
226
|
)
|
225
227
|
elif self.heuristic == "decay":
|
226
228
|
heuristic = (
|
227
229
|
Heuristic(attempt_limit=10 * num_dag_qubits)
|
228
|
-
.with_basic(1.0, SetScaling.
|
230
|
+
.with_basic(1.0, SetScaling.Constant)
|
229
231
|
.with_lookahead(0.5, 20, SetScaling.Size)
|
230
232
|
.with_decay(0.001, 5)
|
231
233
|
)
|
@@ -15,22 +15,18 @@ import itertools
|
|
15
15
|
from typing import Iterable, Union, Optional, List, Tuple
|
16
16
|
from math import floor, log10
|
17
17
|
|
18
|
-
from qiskit.circuit import
|
19
|
-
from qiskit.circuit.
|
18
|
+
from qiskit.circuit import Barrier
|
19
|
+
from qiskit.circuit.library import SwapGate
|
20
20
|
from qiskit.dagcircuit import (
|
21
21
|
DAGOpNode,
|
22
|
+
DAGOutNode,
|
23
|
+
DAGInNode,
|
22
24
|
DAGDepNode,
|
23
25
|
DAGDependency,
|
24
26
|
DAGCircuit,
|
25
|
-
DAGOutNode,
|
26
|
-
DAGInNode,
|
27
27
|
)
|
28
28
|
from qiskit.transpiler.basepasses import TransformationPass
|
29
29
|
from qiskit.transpiler.layout import Layout
|
30
|
-
from qiskit.transpiler.passes.routing.sabre_swap import _build_sabre_dag, _apply_sabre_result
|
31
|
-
|
32
|
-
from qiskit._accelerate import star_prerouting
|
33
|
-
from qiskit._accelerate.nlayout import NLayout
|
34
30
|
|
35
31
|
|
36
32
|
class StarBlock:
|
@@ -232,7 +228,7 @@ class StarPreRouting(TransformationPass):
|
|
232
228
|
return (
|
233
229
|
len(node.qargs) <= 2
|
234
230
|
and len(node.cargs) == 0
|
235
|
-
and getattr(node, "condition", None) is None
|
231
|
+
and getattr(node.op, "condition", None) is None
|
236
232
|
and not isinstance(node.op, Barrier)
|
237
233
|
)
|
238
234
|
|
@@ -318,24 +314,33 @@ class StarPreRouting(TransformationPass):
|
|
318
314
|
new_dag: a dag specifying the pre-routed circuit
|
319
315
|
qubit_mapping: the final qubit mapping after pre-routing
|
320
316
|
"""
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
317
|
+
node_to_block_id = {}
|
318
|
+
for i, block in enumerate(blocks):
|
319
|
+
for node in block.get_nodes():
|
320
|
+
node_to_block_id[node] = i
|
321
|
+
|
322
|
+
new_dag = dag.copy_empty_like()
|
323
|
+
processed_block_ids = set()
|
324
|
+
qubit_mapping = list(range(len(dag.qubits)))
|
325
|
+
|
326
|
+
def _apply_mapping(qargs, qubit_mapping, qubits):
|
327
|
+
return tuple(qubits[qubit_mapping[dag.find_bit(qubit).index]] for qubit in qargs)
|
328
|
+
|
329
|
+
is_first_star = True
|
330
|
+
last_2q_gate = [
|
331
|
+
op
|
332
|
+
for op in reversed(processing_order)
|
333
|
+
if ((len(op.qargs) > 1) and (op.name != "barrier"))
|
333
334
|
]
|
335
|
+
if len(last_2q_gate) > 0:
|
336
|
+
last_2q_gate = last_2q_gate[0]
|
337
|
+
else:
|
338
|
+
last_2q_gate = None
|
334
339
|
|
335
|
-
# Determine the processing order of the nodes in the DAG for the Rust representation
|
336
340
|
int_digits = floor(log10(len(processing_order))) + 1
|
337
341
|
processing_order_index_map = {
|
338
|
-
node: f"a{index
|
342
|
+
node: f"a{str(index).zfill(int(int_digits))}"
|
343
|
+
for index, node in enumerate(processing_order)
|
339
344
|
}
|
340
345
|
|
341
346
|
def tie_breaker_key(node):
|
@@ -348,61 +353,81 @@ class StarPreRouting(TransformationPass):
|
|
348
353
|
f"{dag.find_bit(q).index:04d}" for q in itertools.chain(node.qargs, node.cargs)
|
349
354
|
)
|
350
355
|
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
356
|
+
for node in dag.topological_op_nodes(key=tie_breaker_key):
|
357
|
+
block_id = node_to_block_id.get(node, None)
|
358
|
+
if block_id is not None:
|
359
|
+
if block_id in processed_block_ids:
|
360
|
+
continue
|
361
|
+
|
362
|
+
processed_block_ids.add(block_id)
|
363
|
+
|
364
|
+
# process the whole block
|
365
|
+
block = blocks[block_id]
|
366
|
+
sequence = block.nodes
|
367
|
+
center_node = block.center
|
368
|
+
|
369
|
+
if len(sequence) == 2:
|
370
|
+
for inner_node in sequence:
|
371
|
+
new_dag.apply_operation_back(
|
372
|
+
inner_node.op,
|
373
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
374
|
+
inner_node.cargs,
|
375
|
+
check=False,
|
376
|
+
)
|
377
|
+
continue
|
378
|
+
swap_source = None
|
379
|
+
prev = None
|
380
|
+
for inner_node in sequence:
|
381
|
+
if (len(inner_node.qargs) == 1) or (inner_node.qargs == prev):
|
382
|
+
new_dag.apply_operation_back(
|
383
|
+
inner_node.op,
|
384
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
385
|
+
inner_node.cargs,
|
386
|
+
check=False,
|
387
|
+
)
|
388
|
+
continue
|
389
|
+
if is_first_star and swap_source is None:
|
390
|
+
swap_source = center_node
|
391
|
+
new_dag.apply_operation_back(
|
392
|
+
inner_node.op,
|
393
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
394
|
+
inner_node.cargs,
|
395
|
+
check=False,
|
396
|
+
)
|
397
|
+
|
398
|
+
prev = inner_node.qargs
|
399
|
+
continue
|
400
|
+
# place 2q-gate and subsequent swap gate
|
401
|
+
new_dag.apply_operation_back(
|
402
|
+
inner_node.op,
|
403
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
404
|
+
inner_node.cargs,
|
405
|
+
check=False,
|
406
|
+
)
|
407
|
+
|
408
|
+
if not inner_node is last_2q_gate and not isinstance(inner_node.op, Barrier):
|
409
|
+
new_dag.apply_operation_back(
|
410
|
+
SwapGate(),
|
411
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
412
|
+
inner_node.cargs,
|
413
|
+
check=False,
|
414
|
+
)
|
415
|
+
# Swap mapping
|
416
|
+
index_0 = dag.find_bit(inner_node.qargs[0]).index
|
417
|
+
index_1 = dag.find_bit(inner_node.qargs[1]).index
|
418
|
+
qubit_mapping[index_1], qubit_mapping[index_0] = (
|
419
|
+
qubit_mapping[index_0],
|
420
|
+
qubit_mapping[index_1],
|
421
|
+
)
|
422
|
+
|
423
|
+
prev = inner_node.qargs
|
424
|
+
is_first_star = False
|
425
|
+
else:
|
426
|
+
# the node is not part of a block
|
427
|
+
new_dag.apply_operation_back(
|
428
|
+
node.op,
|
429
|
+
_apply_mapping(node.qargs, qubit_mapping, dag.qubits),
|
430
|
+
node.cargs,
|
431
|
+
check=False,
|
432
|
+
)
|
433
|
+
return new_dag, qubit_mapping
|
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
from .scheduling import ALAPScheduleAnalysis, ASAPScheduleAnalysis, SetIOLatency
|
16
16
|
from .time_unit_conversion import TimeUnitConversion
|
17
|
-
from .padding import PadDelay, PadDynamicalDecoupling
|
17
|
+
from .padding import PadDelay, PadDynamicalDecoupling, ContextAwareDynamicalDecoupling
|
18
18
|
from .alignments import InstructionDurationCheck, ConstrainedReschedule
|
19
19
|
|
20
20
|
# For backward compatibility
|
@@ -59,7 +59,7 @@ class InstructionDurationCheck(AnalysisPass):
|
|
59
59
|
self.property_set["reschedule_required"] = False
|
60
60
|
|
61
61
|
# Rescheduling is not necessary
|
62
|
-
if (self.acquire_align == 1 and self.pulse_align == 1) or dag.
|
62
|
+
if (self.acquire_align == 1 and self.pulse_align == 1) or dag.num_stretches != 0:
|
63
63
|
return
|
64
64
|
|
65
65
|
# Check delay durations
|