qiskit 1.0.2__cp38-abi3-win32.whl → 1.1.0rc1__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/disassemble.py +5 -6
- qiskit/circuit/__init__.py +1131 -169
- qiskit/circuit/_classical_resource_map.py +7 -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/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 +8 -2
- 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 +864 -128
- 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/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/primitives/__init__.py +12 -8
- 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 +5 -4
- qiskit/primitives/containers/bit_array.py +292 -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 +1 -1
- qiskit/primitives/statevector_estimator.py +4 -4
- qiskit/primitives/statevector_sampler.py +7 -12
- qiskit/providers/__init__.py +17 -18
- qiskit/providers/backend.py +2 -2
- qiskit/providers/backend_compat.py +8 -10
- qiskit/providers/basic_provider/basic_provider_tools.py +67 -31
- qiskit/providers/basic_provider/basic_simulator.py +81 -21
- 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/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/qpy/__init__.py +247 -13
- 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 +48 -4
- 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 +54 -33
- 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/mitigation/correlated_readout_mitigator.py +3 -2
- qiskit/result/mitigation/local_readout_mitigator.py +2 -1
- qiskit/result/mitigation/utils.py +3 -2
- qiskit/synthesis/__init__.py +2 -0
- 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 +6 -0
- qiskit/transpiler/passes/basis/basis_translator.py +7 -2
- 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/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/optionals.py +6 -2
- 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/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.0rc1.dist-info}/METADATA +12 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/RECORD +245 -235
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/WHEEL +1 -1
- qiskit/_qasm2.pyd +0 -0
- qiskit/_qasm3.pyd +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/entry_points.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2017, 2023.
|
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
|
+
"""Remove reset when it is the final instruction on a qubit."""
|
14
|
+
|
15
|
+
from qiskit.circuit import Reset, Qubit
|
16
|
+
from qiskit.dagcircuit import DAGOpNode
|
17
|
+
from qiskit.transpiler.basepasses import TransformationPass
|
18
|
+
|
19
|
+
|
20
|
+
class RemoveFinalReset(TransformationPass):
|
21
|
+
"""Remove reset when it is the final instruction on a qubit wire."""
|
22
|
+
|
23
|
+
def run(self, dag):
|
24
|
+
"""Run the RemoveFinalReset pass on `dag`.
|
25
|
+
|
26
|
+
Args:
|
27
|
+
dag (DAGCircuit): the DAG to be optimized.
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
DAGCircuit: the optimized DAG.
|
31
|
+
"""
|
32
|
+
for output_node in dag.output_map.values():
|
33
|
+
if isinstance(output_node.wire, Qubit):
|
34
|
+
pred = next(dag.predecessors(output_node))
|
35
|
+
if isinstance(pred, DAGOpNode) and isinstance(pred.op, Reset):
|
36
|
+
dag.remove_op_node(pred)
|
37
|
+
return dag
|
@@ -148,9 +148,7 @@ class ForwardMatch:
|
|
148
148
|
|
149
149
|
if self.template_dag_dep.direct_successors(node_id_t):
|
150
150
|
maximal_index = self.template_dag_dep.direct_successors(node_id_t)[-1]
|
151
|
-
for elem in pred
|
152
|
-
if elem > maximal_index:
|
153
|
-
pred.remove(elem)
|
151
|
+
pred = [elem for elem in pred if elem <= maximal_index]
|
154
152
|
|
155
153
|
block = []
|
156
154
|
for node_id in pred:
|
@@ -19,3 +19,4 @@ from .stochastic_swap import StochasticSwap
|
|
19
19
|
from .sabre_swap import SabreSwap
|
20
20
|
from .commuting_2q_gate_routing.commuting_2q_gate_router import Commuting2qGateRouter
|
21
21
|
from .commuting_2q_gate_routing.swap_strategy import SwapStrategy
|
22
|
+
from .star_prerouting import StarPreRouting
|
@@ -114,7 +114,13 @@ class BasicSwap(TransformationPass):
|
|
114
114
|
order = current_layout.reorder_bits(new_dag.qubits)
|
115
115
|
new_dag.compose(subdag, qubits=order)
|
116
116
|
|
117
|
-
self.property_set["final_layout"]
|
117
|
+
if self.property_set["final_layout"] is None:
|
118
|
+
self.property_set["final_layout"] = current_layout
|
119
|
+
else:
|
120
|
+
self.property_set["final_layout"] = current_layout.compose(
|
121
|
+
self.property_set["final_layout"], dag.qubits
|
122
|
+
)
|
123
|
+
|
118
124
|
return new_dag
|
119
125
|
|
120
126
|
def _fake_run(self, dag):
|
@@ -151,5 +157,10 @@ class BasicSwap(TransformationPass):
|
|
151
157
|
for swap in range(len(path) - 2):
|
152
158
|
current_layout.swap(path[swap], path[swap + 1])
|
153
159
|
|
154
|
-
self.property_set["final_layout"]
|
160
|
+
if self.property_set["final_layout"] is None:
|
161
|
+
self.property_set["final_layout"] = current_layout
|
162
|
+
else:
|
163
|
+
self.property_set["final_layout"] = current_layout.compose(
|
164
|
+
self.property_set["final_layout"], dag.qubits
|
165
|
+
)
|
155
166
|
return dag
|
@@ -169,7 +169,13 @@ class LookaheadSwap(TransformationPass):
|
|
169
169
|
|
170
170
|
mapped_gates.extend(gates_mapped)
|
171
171
|
|
172
|
-
self.property_set["final_layout"]
|
172
|
+
if self.property_set["final_layout"] is None:
|
173
|
+
self.property_set["final_layout"] = current_state.layout
|
174
|
+
else:
|
175
|
+
self.property_set["final_layout"] = current_state.layout.compose(
|
176
|
+
self.property_set["final_layout"], dag.qubits
|
177
|
+
)
|
178
|
+
|
173
179
|
if self.fake_run:
|
174
180
|
return dag
|
175
181
|
|
@@ -31,8 +31,8 @@ from qiskit.transpiler.passes.layout import disjoint_utils
|
|
31
31
|
from qiskit.dagcircuit import DAGCircuit
|
32
32
|
from qiskit.utils.parallel import CPU_COUNT
|
33
33
|
|
34
|
-
from qiskit._accelerate.
|
35
|
-
|
34
|
+
from qiskit._accelerate.sabre import (
|
35
|
+
sabre_routing,
|
36
36
|
Heuristic,
|
37
37
|
NeighborTable,
|
38
38
|
SabreDAG,
|
@@ -239,8 +239,7 @@ class SabreSwap(TransformationPass):
|
|
239
239
|
self._qubit_indices,
|
240
240
|
)
|
241
241
|
sabre_start = time.perf_counter()
|
242
|
-
*sabre_result, final_permutation =
|
243
|
-
len(dag.qubits),
|
242
|
+
*sabre_result, final_permutation = sabre_routing(
|
244
243
|
sabre_dag,
|
245
244
|
self._neighbor_table,
|
246
245
|
self.dist_matrix,
|
@@ -251,8 +250,13 @@ class SabreSwap(TransformationPass):
|
|
251
250
|
)
|
252
251
|
sabre_stop = time.perf_counter()
|
253
252
|
logging.debug("Sabre swap algorithm execution complete in: %s", sabre_stop - sabre_start)
|
254
|
-
|
255
|
-
self.property_set["final_layout"]
|
253
|
+
final_layout = Layout(dict(zip(dag.qubits, final_permutation)))
|
254
|
+
if self.property_set["final_layout"] is None:
|
255
|
+
self.property_set["final_layout"] = final_layout
|
256
|
+
else:
|
257
|
+
self.property_set["final_layout"] = final_layout.compose(
|
258
|
+
self.property_set["final_layout"], dag.qubits
|
259
|
+
)
|
256
260
|
if self.fake_run:
|
257
261
|
return dag
|
258
262
|
return _apply_sabre_result(
|
@@ -0,0 +1,417 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2023.
|
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
|
+
"""Search for star connectivity patterns and replace them with."""
|
14
|
+
from typing import Iterable, Union, Optional, List, Tuple
|
15
|
+
from math import floor, log10
|
16
|
+
|
17
|
+
from qiskit.circuit import Barrier
|
18
|
+
from qiskit.dagcircuit import DAGOpNode, DAGDepNode, DAGDependency, DAGCircuit
|
19
|
+
from qiskit.transpiler import Layout
|
20
|
+
from qiskit.transpiler.basepasses import TransformationPass
|
21
|
+
from qiskit.circuit.library import SwapGate
|
22
|
+
|
23
|
+
|
24
|
+
class StarBlock:
|
25
|
+
"""Defines blocks representing star-shaped pieces of a circuit."""
|
26
|
+
|
27
|
+
def __init__(self, nodes=None, center=None, num2q=0):
|
28
|
+
self.center = center
|
29
|
+
self.num2q = num2q
|
30
|
+
self.nodes = [] if nodes is None else nodes
|
31
|
+
|
32
|
+
def get_nodes(self):
|
33
|
+
"""Returns the list of nodes used in the block."""
|
34
|
+
return self.nodes
|
35
|
+
|
36
|
+
def append_node(self, node):
|
37
|
+
"""
|
38
|
+
If node can be added to block while keeping the block star-shaped, and
|
39
|
+
return True. Otherwise, does not add node to block and returns False.
|
40
|
+
"""
|
41
|
+
|
42
|
+
added = False
|
43
|
+
|
44
|
+
if len(node.qargs) == 1:
|
45
|
+
self.nodes.append(node)
|
46
|
+
added = True
|
47
|
+
elif self.center is None:
|
48
|
+
self.center = set(node.qargs)
|
49
|
+
self.nodes.append(node)
|
50
|
+
self.num2q += 1
|
51
|
+
added = True
|
52
|
+
elif isinstance(self.center, set):
|
53
|
+
if node.qargs[0] in self.center:
|
54
|
+
self.center = node.qargs[0]
|
55
|
+
self.nodes.append(node)
|
56
|
+
self.num2q += 1
|
57
|
+
added = True
|
58
|
+
elif node.qargs[1] in self.center:
|
59
|
+
self.center = node.qargs[1]
|
60
|
+
self.nodes.append(node)
|
61
|
+
self.num2q += 1
|
62
|
+
added = True
|
63
|
+
else:
|
64
|
+
if self.center in node.qargs:
|
65
|
+
self.nodes.append(node)
|
66
|
+
self.num2q += 1
|
67
|
+
added = True
|
68
|
+
|
69
|
+
return added
|
70
|
+
|
71
|
+
def size(self):
|
72
|
+
"""
|
73
|
+
Returns the number of two-qubit quantum gates in this block.
|
74
|
+
"""
|
75
|
+
return self.num2q
|
76
|
+
|
77
|
+
|
78
|
+
class StarPreRouting(TransformationPass):
|
79
|
+
"""Run star to linear pre-routing
|
80
|
+
|
81
|
+
This pass is a logical optimization pass that rewrites any
|
82
|
+
solely 2q gate star connectivity subcircuit as a linear connectivity
|
83
|
+
equivalent with swaps.
|
84
|
+
|
85
|
+
For example:
|
86
|
+
|
87
|
+
.. plot::
|
88
|
+
:include-source:
|
89
|
+
|
90
|
+
from qiskit.circuit import QuantumCircuit
|
91
|
+
from qiskit.transpiler.passes import StarPreRouting
|
92
|
+
|
93
|
+
qc = QuantumCircuit(10)
|
94
|
+
qc.h(0)
|
95
|
+
qc.cx(0, range(1, 5))
|
96
|
+
qc.h(9)
|
97
|
+
qc.cx(9, range(8, 4, -1))
|
98
|
+
qc.measure_all()
|
99
|
+
StarPreRouting()(qc).draw("mpl")
|
100
|
+
|
101
|
+
This pass was inspired by a similar pass described in Section IV of:
|
102
|
+
C. Campbell et al., "Superstaq: Deep Optimization of Quantum Programs,"
|
103
|
+
2023 IEEE International Conference on Quantum Computing and Engineering (QCE),
|
104
|
+
Bellevue, WA, USA, 2023, pp. 1020-1032, doi: 10.1109/QCE57702.2023.00116.
|
105
|
+
"""
|
106
|
+
|
107
|
+
def __init__(self):
|
108
|
+
"""StarPreRouting"""
|
109
|
+
|
110
|
+
self._pending_nodes: Optional[list[Union[DAGOpNode, DAGDepNode]]] = None
|
111
|
+
self._in_degree: Optional[dict[Union[DAGOpNode, DAGDepNode], int]] = None
|
112
|
+
super().__init__()
|
113
|
+
|
114
|
+
def _setup_in_degrees(self, dag):
|
115
|
+
"""For an efficient implementation, for every node we keep the number of its
|
116
|
+
unprocessed immediate predecessors (called ``_in_degree``). This ``_in_degree``
|
117
|
+
is set up at the start and updated throughout the algorithm.
|
118
|
+
A node is leaf (or input) node iff its ``_in_degree`` is 0.
|
119
|
+
When a node is (marked as) collected, the ``_in_degree`` of each of its immediate
|
120
|
+
successor is updated by subtracting 1.
|
121
|
+
Additionally, ``_pending_nodes`` explicitly keeps the list of nodes whose
|
122
|
+
``_in_degree`` is 0.
|
123
|
+
"""
|
124
|
+
self._pending_nodes = []
|
125
|
+
self._in_degree = {}
|
126
|
+
for node in self._op_nodes(dag):
|
127
|
+
deg = len(self._direct_preds(dag, node))
|
128
|
+
self._in_degree[node] = deg
|
129
|
+
if deg == 0:
|
130
|
+
self._pending_nodes.append(node)
|
131
|
+
|
132
|
+
def _op_nodes(self, dag) -> Iterable[Union[DAGOpNode, DAGDepNode]]:
|
133
|
+
"""Returns DAG nodes."""
|
134
|
+
if not isinstance(dag, DAGDependency):
|
135
|
+
return dag.op_nodes()
|
136
|
+
else:
|
137
|
+
return dag.get_nodes()
|
138
|
+
|
139
|
+
def _direct_preds(self, dag, node):
|
140
|
+
"""Returns direct predecessors of a node. This function takes into account the
|
141
|
+
direction of collecting blocks, that is node's predecessors when collecting
|
142
|
+
backwards are the direct successors of a node in the DAG.
|
143
|
+
"""
|
144
|
+
if not isinstance(dag, DAGDependency):
|
145
|
+
return [pred for pred in dag.predecessors(node) if isinstance(pred, DAGOpNode)]
|
146
|
+
else:
|
147
|
+
return [dag.get_node(pred_id) for pred_id in dag.direct_predecessors(node.node_id)]
|
148
|
+
|
149
|
+
def _direct_succs(self, dag, node):
|
150
|
+
"""Returns direct successors of a node. This function takes into account the
|
151
|
+
direction of collecting blocks, that is node's successors when collecting
|
152
|
+
backwards are the direct predecessors of a node in the DAG.
|
153
|
+
"""
|
154
|
+
if not isinstance(dag, DAGDependency):
|
155
|
+
return [succ for succ in dag.successors(node) if isinstance(succ, DAGOpNode)]
|
156
|
+
else:
|
157
|
+
return [dag.get_node(succ_id) for succ_id in dag.direct_successors(node.node_id)]
|
158
|
+
|
159
|
+
def _have_uncollected_nodes(self):
|
160
|
+
"""Returns whether there are uncollected (pending) nodes"""
|
161
|
+
return len(self._pending_nodes) > 0
|
162
|
+
|
163
|
+
def collect_matching_block(self, dag, filter_fn):
|
164
|
+
"""Iteratively collects the largest block of input nodes (that is, nodes with
|
165
|
+
``_in_degree`` equal to 0) that match a given filtering function.
|
166
|
+
Examples of this include collecting blocks of swap gates,
|
167
|
+
blocks of linear gates (CXs and SWAPs), blocks of Clifford gates, blocks of single-qubit gates,
|
168
|
+
blocks of two-qubit gates, etc. Here 'iteratively' means that once a node is collected,
|
169
|
+
the ``_in_degree`` of each of its immediate successor is decreased by 1, allowing more nodes
|
170
|
+
to become input and to be eligible for collecting into the current block.
|
171
|
+
Returns the block of collected nodes.
|
172
|
+
"""
|
173
|
+
unprocessed_pending_nodes = self._pending_nodes
|
174
|
+
self._pending_nodes = []
|
175
|
+
|
176
|
+
current_block = StarBlock()
|
177
|
+
|
178
|
+
# Iteratively process unprocessed_pending_nodes:
|
179
|
+
# - any node that does not match filter_fn is added to pending_nodes
|
180
|
+
# - any node that match filter_fn is added to the current_block,
|
181
|
+
# and some of its successors may be moved to unprocessed_pending_nodes.
|
182
|
+
while unprocessed_pending_nodes:
|
183
|
+
new_pending_nodes = []
|
184
|
+
for node in unprocessed_pending_nodes:
|
185
|
+
added = filter_fn(node) and current_block.append_node(node)
|
186
|
+
if added:
|
187
|
+
# update the _in_degree of node's successors
|
188
|
+
for suc in self._direct_succs(dag, node):
|
189
|
+
self._in_degree[suc] -= 1
|
190
|
+
if self._in_degree[suc] == 0:
|
191
|
+
new_pending_nodes.append(suc)
|
192
|
+
else:
|
193
|
+
self._pending_nodes.append(node)
|
194
|
+
unprocessed_pending_nodes = new_pending_nodes
|
195
|
+
|
196
|
+
return current_block
|
197
|
+
|
198
|
+
def collect_all_matching_blocks(
|
199
|
+
self,
|
200
|
+
dag,
|
201
|
+
min_block_size=2,
|
202
|
+
):
|
203
|
+
"""Collects all blocks that match a given filtering function filter_fn.
|
204
|
+
This iteratively finds the largest block that does not match filter_fn,
|
205
|
+
then the largest block that matches filter_fn, and so on, until no more uncollected
|
206
|
+
nodes remain. Intuitively, finding larger blocks of non-matching nodes helps to
|
207
|
+
find larger blocks of matching nodes later on. The option ``min_block_size``
|
208
|
+
specifies the minimum number of gates in the block for the block to be collected.
|
209
|
+
|
210
|
+
By default, blocks are collected in the direction from the inputs towards the outputs
|
211
|
+
of the circuit. The option ``collect_from_back`` allows to change this direction,
|
212
|
+
that is collect blocks from the outputs towards the inputs of the circuit.
|
213
|
+
|
214
|
+
Returns the list of matching blocks only.
|
215
|
+
"""
|
216
|
+
|
217
|
+
def filter_fn(node):
|
218
|
+
"""Specifies which nodes can be collected into star blocks."""
|
219
|
+
return (
|
220
|
+
len(node.qargs) <= 2
|
221
|
+
and len(node.cargs) == 0
|
222
|
+
and getattr(node.op, "condition", None) is None
|
223
|
+
and not isinstance(node.op, Barrier)
|
224
|
+
)
|
225
|
+
|
226
|
+
def not_filter_fn(node):
|
227
|
+
"""Returns the opposite of filter_fn."""
|
228
|
+
return not filter_fn(node)
|
229
|
+
|
230
|
+
# Note: the collection direction must be specified before setting in-degrees
|
231
|
+
self._setup_in_degrees(dag)
|
232
|
+
|
233
|
+
# Iteratively collect non-matching and matching blocks.
|
234
|
+
matching_blocks: list[StarBlock] = []
|
235
|
+
processing_order = []
|
236
|
+
while self._have_uncollected_nodes():
|
237
|
+
self.collect_matching_block(dag, filter_fn=not_filter_fn)
|
238
|
+
matching_block = self.collect_matching_block(dag, filter_fn=filter_fn)
|
239
|
+
if matching_block.size() >= min_block_size:
|
240
|
+
matching_blocks.append(matching_block)
|
241
|
+
processing_order.append(matching_block)
|
242
|
+
|
243
|
+
processing_order = [n for p in processing_order for n in p.nodes]
|
244
|
+
|
245
|
+
return matching_blocks, processing_order
|
246
|
+
|
247
|
+
def run(self, dag):
|
248
|
+
# Extract StarBlocks from DAGCircuit / DAGDependency / DAGDependencyV2
|
249
|
+
star_blocks, processing_order = self.determine_star_blocks_processing(dag, min_block_size=2)
|
250
|
+
|
251
|
+
if not star_blocks:
|
252
|
+
return dag
|
253
|
+
|
254
|
+
if all(b.size() < 3 for b in star_blocks):
|
255
|
+
# we only process blocks with less than 3 two-qubit gates in this pre-routing pass
|
256
|
+
# if they occur in a collection of larger stars, otherwise we consider them to be 'lines'
|
257
|
+
return dag
|
258
|
+
|
259
|
+
# Create a new DAGCircuit / DAGDependency / DAGDependencyV2, replacing each
|
260
|
+
# star block by a linear sequence of gates
|
261
|
+
new_dag, qubit_mapping = self.star_preroute(dag, star_blocks, processing_order)
|
262
|
+
|
263
|
+
# Fix output permuation -- copied from ElidePermutations
|
264
|
+
input_qubit_mapping = {qubit: index for index, qubit in enumerate(dag.qubits)}
|
265
|
+
self.property_set["original_layout"] = Layout(input_qubit_mapping)
|
266
|
+
if self.property_set["original_qubit_indices"] is None:
|
267
|
+
self.property_set["original_qubit_indices"] = input_qubit_mapping
|
268
|
+
|
269
|
+
new_layout = Layout({dag.qubits[out]: idx for idx, out in enumerate(qubit_mapping)})
|
270
|
+
if current_layout := self.property_set["virtual_permutation_layout"]:
|
271
|
+
self.property_set["virtual_permutation_layout"] = new_layout.compose(
|
272
|
+
current_layout.inverse(dag.qubits, dag.qubits), dag.qubits
|
273
|
+
)
|
274
|
+
else:
|
275
|
+
self.property_set["virtual_permutation_layout"] = new_layout
|
276
|
+
|
277
|
+
return new_dag
|
278
|
+
|
279
|
+
def determine_star_blocks_processing(
|
280
|
+
self, dag: Union[DAGCircuit, DAGDependency], min_block_size: int
|
281
|
+
) -> Tuple[List[StarBlock], Union[List[DAGOpNode], List[DAGDepNode]]]:
|
282
|
+
"""Returns star blocks in dag and the processing order of nodes within these star blocks
|
283
|
+
Args:
|
284
|
+
dag (DAGCircuit or DAGDependency): a dag on which star blocks should be determined.
|
285
|
+
min_block_size (int): minimum number of two-qubit gates in a star block.
|
286
|
+
|
287
|
+
Returns:
|
288
|
+
List[StarBlock]: a list of star blocks in the given dag
|
289
|
+
Union[List[DAGOpNode], List[DAGDepNode]]: a list of operations specifying processing order
|
290
|
+
"""
|
291
|
+
blocks, processing_order = self.collect_all_matching_blocks(
|
292
|
+
dag, min_block_size=min_block_size
|
293
|
+
)
|
294
|
+
return blocks, processing_order
|
295
|
+
|
296
|
+
def star_preroute(self, dag, blocks, processing_order):
|
297
|
+
"""Returns star blocks in dag and the processing order of nodes within these star blocks
|
298
|
+
Args:
|
299
|
+
dag (DAGCircuit or DAGDependency): a dag on which star prerouting should be performed.
|
300
|
+
blocks (List[StarBlock]): a list of star blocks in the given dag.
|
301
|
+
processing_order (Union[List[DAGOpNode], List[DAGDepNode]]): a list of operations specifying
|
302
|
+
processing order
|
303
|
+
|
304
|
+
Returns:
|
305
|
+
new_dag: a dag specifying the pre-routed circuit
|
306
|
+
qubit_mapping: the final qubit mapping after pre-routing
|
307
|
+
"""
|
308
|
+
node_to_block_id = {}
|
309
|
+
for i, block in enumerate(blocks):
|
310
|
+
for node in block.get_nodes():
|
311
|
+
node_to_block_id[node] = i
|
312
|
+
|
313
|
+
new_dag = dag.copy_empty_like()
|
314
|
+
processed_block_ids = set()
|
315
|
+
qubit_mapping = list(range(len(dag.qubits)))
|
316
|
+
|
317
|
+
def _apply_mapping(qargs, qubit_mapping, qubits):
|
318
|
+
return tuple(qubits[qubit_mapping[dag.find_bit(qubit).index]] for qubit in qargs)
|
319
|
+
|
320
|
+
is_first_star = True
|
321
|
+
last_2q_gate = [
|
322
|
+
op
|
323
|
+
for op in reversed(processing_order)
|
324
|
+
if ((len(op.qargs) > 1) and (op.name != "barrier"))
|
325
|
+
]
|
326
|
+
if len(last_2q_gate) > 0:
|
327
|
+
last_2q_gate = last_2q_gate[0]
|
328
|
+
else:
|
329
|
+
last_2q_gate = None
|
330
|
+
|
331
|
+
int_digits = floor(log10(len(processing_order))) + 1
|
332
|
+
processing_order_s = set(processing_order)
|
333
|
+
|
334
|
+
def tie_breaker_key(node):
|
335
|
+
if node in processing_order_s:
|
336
|
+
return "a" + str(processing_order.index(node)).zfill(int(int_digits))
|
337
|
+
else:
|
338
|
+
return node.sort_key
|
339
|
+
|
340
|
+
for node in dag.topological_op_nodes(key=tie_breaker_key):
|
341
|
+
block_id = node_to_block_id.get(node, None)
|
342
|
+
if block_id is not None:
|
343
|
+
if block_id in processed_block_ids:
|
344
|
+
continue
|
345
|
+
|
346
|
+
processed_block_ids.add(block_id)
|
347
|
+
|
348
|
+
# process the whole block
|
349
|
+
block = blocks[block_id]
|
350
|
+
sequence = block.nodes
|
351
|
+
center_node = block.center
|
352
|
+
|
353
|
+
if len(sequence) == 2:
|
354
|
+
for inner_node in sequence:
|
355
|
+
new_dag.apply_operation_back(
|
356
|
+
inner_node.op,
|
357
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
358
|
+
inner_node.cargs,
|
359
|
+
check=False,
|
360
|
+
)
|
361
|
+
continue
|
362
|
+
swap_source = None
|
363
|
+
prev = None
|
364
|
+
for inner_node in sequence:
|
365
|
+
if (len(inner_node.qargs) == 1) or (inner_node.qargs == prev):
|
366
|
+
new_dag.apply_operation_back(
|
367
|
+
inner_node.op,
|
368
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
369
|
+
inner_node.cargs,
|
370
|
+
check=False,
|
371
|
+
)
|
372
|
+
continue
|
373
|
+
if is_first_star and swap_source is None:
|
374
|
+
swap_source = center_node
|
375
|
+
new_dag.apply_operation_back(
|
376
|
+
inner_node.op,
|
377
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
378
|
+
inner_node.cargs,
|
379
|
+
check=False,
|
380
|
+
)
|
381
|
+
|
382
|
+
prev = inner_node.qargs
|
383
|
+
continue
|
384
|
+
# place 2q-gate and subsequent swap gate
|
385
|
+
new_dag.apply_operation_back(
|
386
|
+
inner_node.op,
|
387
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
388
|
+
inner_node.cargs,
|
389
|
+
check=False,
|
390
|
+
)
|
391
|
+
|
392
|
+
if not inner_node is last_2q_gate and not isinstance(inner_node.op, Barrier):
|
393
|
+
new_dag.apply_operation_back(
|
394
|
+
SwapGate(),
|
395
|
+
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
|
396
|
+
inner_node.cargs,
|
397
|
+
check=False,
|
398
|
+
)
|
399
|
+
# Swap mapping
|
400
|
+
index_0 = dag.find_bit(inner_node.qargs[0]).index
|
401
|
+
index_1 = dag.find_bit(inner_node.qargs[1]).index
|
402
|
+
qubit_mapping[index_1], qubit_mapping[index_0] = (
|
403
|
+
qubit_mapping[index_0],
|
404
|
+
qubit_mapping[index_1],
|
405
|
+
)
|
406
|
+
|
407
|
+
prev = inner_node.qargs
|
408
|
+
is_first_star = False
|
409
|
+
else:
|
410
|
+
# the node is not part of a block
|
411
|
+
new_dag.apply_operation_back(
|
412
|
+
node.op,
|
413
|
+
_apply_mapping(node.qargs, qubit_mapping, dag.qubits),
|
414
|
+
node.cargs,
|
415
|
+
check=False,
|
416
|
+
)
|
417
|
+
return new_dag, qubit_mapping
|
@@ -33,7 +33,6 @@ from qiskit.circuit import (
|
|
33
33
|
ForLoopOp,
|
34
34
|
SwitchCaseOp,
|
35
35
|
ControlFlowOp,
|
36
|
-
Instruction,
|
37
36
|
CASE_DEFAULT,
|
38
37
|
)
|
39
38
|
from qiskit._accelerate import stochastic_swap as stochastic_swap_rs
|
@@ -266,11 +265,15 @@ class StochasticSwap(TransformationPass):
|
|
266
265
|
# Output any swaps
|
267
266
|
if best_depth > 0:
|
268
267
|
logger.debug("layer_update: there are swaps in this layer, depth %d", best_depth)
|
269
|
-
dag.compose(
|
268
|
+
dag.compose(
|
269
|
+
best_circuit, qubits={bit: bit for bit in best_circuit.qubits}, inline_captures=True
|
270
|
+
)
|
270
271
|
else:
|
271
272
|
logger.debug("layer_update: there are no swaps in this layer")
|
272
273
|
# Output this layer
|
273
|
-
dag.compose(
|
274
|
+
dag.compose(
|
275
|
+
layer["graph"], qubits=best_layout.reorder_bits(dag.qubits), inline_captures=True
|
276
|
+
)
|
274
277
|
|
275
278
|
def _mapper(self, circuit_graph, coupling_graph, trials=20):
|
276
279
|
"""Map a DAGCircuit onto a CouplingMap using swap gates.
|
@@ -323,7 +326,7 @@ class StochasticSwap(TransformationPass):
|
|
323
326
|
# Update the DAG
|
324
327
|
if not self.fake_run:
|
325
328
|
self._layer_update(
|
326
|
-
dagcircuit_output,
|
329
|
+
dagcircuit_output, layer, best_layout, best_depth, best_circuit
|
327
330
|
)
|
328
331
|
continue
|
329
332
|
|
@@ -375,8 +378,13 @@ class StochasticSwap(TransformationPass):
|
|
375
378
|
# any measurements that needed to be removed earlier.
|
376
379
|
logger.debug("mapper: self.initial_layout = %s", self.initial_layout)
|
377
380
|
logger.debug("mapper: layout = %s", layout)
|
381
|
+
if self.property_set["final_layout"] is None:
|
382
|
+
self.property_set["final_layout"] = layout
|
383
|
+
else:
|
384
|
+
self.property_set["final_layout"] = layout.compose(
|
385
|
+
self.property_set["final_layout"], circuit_graph.qubits
|
386
|
+
)
|
378
387
|
|
379
|
-
self.property_set["final_layout"] = layout
|
380
388
|
if self.fake_run:
|
381
389
|
return circuit_graph
|
382
390
|
return dagcircuit_output
|
@@ -433,7 +441,7 @@ class StochasticSwap(TransformationPass):
|
|
433
441
|
root_dag, self.coupling_map, layout, final_layout, seed=self._new_seed()
|
434
442
|
)
|
435
443
|
if swap_dag.size(recurse=False):
|
436
|
-
updated_dag_block.compose(swap_dag, qubits=swap_qubits)
|
444
|
+
updated_dag_block.compose(swap_dag, qubits=swap_qubits, inline_captures=True)
|
437
445
|
idle_qubits &= set(updated_dag_block.idle_wires())
|
438
446
|
|
439
447
|
# Now for each block, expand it to be full width over all active wires (all blocks of a
|
@@ -499,10 +507,18 @@ def _dag_from_block(block, node, root_dag):
|
|
499
507
|
out.add_qreg(qreg)
|
500
508
|
# For clbits, we need to take more care. Nested control-flow might need registers to exist for
|
501
509
|
# conditions on inner blocks. `DAGCircuit.substitute_node_with_dag` handles this register
|
502
|
-
# mapping when required, so we use that with a dummy block
|
510
|
+
# mapping when required, so we use that with a dummy block that pretends to act on all variables
|
511
|
+
# in the DAG.
|
503
512
|
out.add_clbits(node.cargs)
|
513
|
+
for var in block.iter_input_vars():
|
514
|
+
out.add_input_var(var)
|
515
|
+
for var in block.iter_captured_vars():
|
516
|
+
out.add_captured_var(var)
|
517
|
+
for var in block.iter_declared_vars():
|
518
|
+
out.add_declared_var(var)
|
519
|
+
|
504
520
|
dummy = out.apply_operation_back(
|
505
|
-
|
521
|
+
IfElseOp(expr.lift(True), block.copy_empty_like(vars_mode="captures")),
|
506
522
|
node.qargs,
|
507
523
|
node.cargs,
|
508
524
|
check=False,
|
@@ -20,7 +20,7 @@ from .time_unit_conversion import TimeUnitConversion
|
|
20
20
|
from .padding import PadDelay, PadDynamicalDecoupling
|
21
21
|
from .alignments import InstructionDurationCheck, ValidatePulseGates, ConstrainedReschedule
|
22
22
|
|
23
|
-
# For backward
|
23
|
+
# For backward compatibility
|
24
24
|
from . import alignments as instruction_alignments
|
25
25
|
|
26
26
|
# TODO Deprecated pass. Will be removed after deprecation period.
|
@@ -32,8 +32,7 @@ class ALAPSchedule(BaseSchedulerTransform):
|
|
32
32
|
"Instead, use :class:`~.ALAPScheduleAnalysis`, which is an "
|
33
33
|
"analysis pass that requires a padding pass to later modify the circuit."
|
34
34
|
),
|
35
|
-
since="
|
36
|
-
pending=True,
|
35
|
+
since="1.1.0",
|
37
36
|
)
|
38
37
|
def __init__(self, *args, **kwargs):
|
39
38
|
super().__init__(*args, **kwargs)
|
@@ -95,8 +95,7 @@ class AlignMeasures(TransformationPass):
|
|
95
95
|
"Instead, use :class:`~.ConstrainedReschedule`, which performs the same function "
|
96
96
|
"but also supports aligning to additional timing constraints."
|
97
97
|
),
|
98
|
-
since="
|
99
|
-
pending=True,
|
98
|
+
since="1.1.0",
|
100
99
|
)
|
101
100
|
def __init__(self, alignment: int = 1):
|
102
101
|
"""Create new pass.
|