qiskit 2.0.0rc2__cp39-abi3-win_amd64.whl → 2.0.2__cp39-abi3-win_amd64.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 +1 -4
- qiskit/_accelerate.pyd +0 -0
- qiskit/circuit/__init__.py +11 -5
- qiskit/circuit/classical/expr/constructors.py +0 -12
- qiskit/circuit/library/__init__.py +449 -163
- qiskit/circuit/library/boolean_logic/quantum_or.py +2 -2
- qiskit/circuit/library/graph_state.py +1 -0
- qiskit/circuit/library/n_local/efficient_su2.py +1 -1
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +3 -1
- qiskit/circuit/library/n_local/excitation_preserving.py +1 -1
- qiskit/circuit/library/quantum_volume.py +9 -0
- qiskit/circuit/library/standard_gates/r.py +4 -3
- qiskit/circuit/library/standard_gates/x.py +1 -2
- qiskit/circuit/quantumcircuit.py +405 -80
- qiskit/converters/circuit_to_dag.py +2 -2
- qiskit/converters/dag_to_circuit.py +2 -3
- qiskit/dagcircuit/dagdependency_v2.py +3 -2
- qiskit/primitives/statevector_estimator.py +1 -1
- qiskit/qpy/__init__.py +21 -0
- qiskit/qpy/binary_io/circuits.py +5 -0
- qiskit/result/models.py +1 -2
- qiskit/result/result.py +10 -8
- qiskit/synthesis/discrete_basis/commutator_decompose.py +30 -6
- qiskit/synthesis/discrete_basis/gate_sequence.py +10 -4
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +1 -1
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +36 -13
- qiskit/transpiler/passes/__init__.py +2 -0
- qiskit/transpiler/passes/basis/basis_translator.py +1 -1
- qiskit/transpiler/passes/layout/full_ancilla_allocation.py +2 -3
- qiskit/transpiler/passes/layout/sabre_layout.py +3 -1
- qiskit/transpiler/passes/layout/vf2_utils.py +2 -5
- qiskit/transpiler/passes/optimization/__init__.py +1 -0
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +6 -1
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +2 -2
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +5 -5
- qiskit/transpiler/passes/scheduling/padding/pad_delay.py +1 -1
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +10 -6
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +29 -19
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +2 -1
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +13 -7
- qiskit/transpiler/target.py +11 -0
- qiskit/visualization/circuit/text.py +1 -1
- qiskit/visualization/counts_visualization.py +4 -0
- qiskit/visualization/library.py +4 -1
- qiskit/visualization/state_visualization.py +13 -2
- qiskit/visualization/timeline/core.py +1 -1
- qiskit/visualization/timeline/plotters/matplotlib.py +4 -1
- {qiskit-2.0.0rc2.dist-info → qiskit-2.0.2.dist-info}/METADATA +4 -3
- {qiskit-2.0.0rc2.dist-info → qiskit-2.0.2.dist-info}/RECORD +55 -55
- {qiskit-2.0.0rc2.dist-info → qiskit-2.0.2.dist-info}/WHEEL +1 -1
- {qiskit-2.0.0rc2.dist-info → qiskit-2.0.2.dist-info}/entry_points.txt +0 -0
- {qiskit-2.0.0rc2.dist-info → qiskit-2.0.2.dist-info/licenses}/LICENSE.txt +0 -0
- {qiskit-2.0.0rc2.dist-info → qiskit-2.0.2.dist-info}/top_level.txt +0 -0
@@ -75,6 +75,6 @@ def circuit_to_dag(circuit, copy_operations=True, *, qubit_order=None, clbit_ord
|
|
75
75
|
|
76
76
|
dagcircuit = core_circuit_to_dag(circuit, copy_operations, qubit_order, clbit_order)
|
77
77
|
|
78
|
-
dagcircuit.
|
79
|
-
dagcircuit.
|
78
|
+
dagcircuit._duration = circuit._duration
|
79
|
+
dagcircuit._unit = circuit._unit
|
80
80
|
return dagcircuit
|
@@ -74,7 +74,6 @@ def dag_to_circuit(dag, copy_operations=True):
|
|
74
74
|
circuit.add_stretch(stretch)
|
75
75
|
circuit.metadata = dag.metadata or {}
|
76
76
|
circuit._data = circuit_data
|
77
|
-
|
78
|
-
circuit.
|
79
|
-
circuit._unit = dag.unit
|
77
|
+
circuit._duration = dag._duration
|
78
|
+
circuit._unit = dag._unit
|
80
79
|
return circuit
|
@@ -447,8 +447,6 @@ class _DAGDependencyV2:
|
|
447
447
|
target_dag = _DAGDependencyV2()
|
448
448
|
target_dag.name = self.name
|
449
449
|
target_dag._global_phase = self._global_phase
|
450
|
-
target_dag.duration = self.duration
|
451
|
-
target_dag.unit = self.unit
|
452
450
|
target_dag.metadata = self.metadata
|
453
451
|
target_dag._key_cache = self._key_cache
|
454
452
|
target_dag.comm_checker = self.comm_checker
|
@@ -456,6 +454,9 @@ class _DAGDependencyV2:
|
|
456
454
|
target_dag.add_qubits(self.qubits)
|
457
455
|
target_dag.add_clbits(self.clbits)
|
458
456
|
|
457
|
+
target_dag.duration = self.duration
|
458
|
+
target_dag.unit = self.unit
|
459
|
+
|
459
460
|
for qreg in self.qregs.values():
|
460
461
|
target_dag.add_qreg(qreg)
|
461
462
|
for creg in self.cregs.values():
|
@@ -33,7 +33,7 @@ class StatevectorEstimator(BaseEstimatorV2):
|
|
33
33
|
Simple implementation of :class:`BaseEstimatorV2` with full state vector simulation.
|
34
34
|
|
35
35
|
This class is implemented via :class:`~.Statevector` which turns provided circuits into
|
36
|
-
pure state vectors. These states are subsequently acted on by :class
|
36
|
+
pure state vectors. These states are subsequently acted on by :class:`~.SparsePauliOp`,
|
37
37
|
which implies that, at present, this implementation is only compatible with Pauli-based
|
38
38
|
observables.
|
39
39
|
|
qiskit/qpy/__init__.py
CHANGED
@@ -194,6 +194,27 @@ of QPY in qiskit-terra 0.18.0.
|
|
194
194
|
* - Qiskit (qiskit-terra for < 1.0.0) version
|
195
195
|
- :func:`.dump` format(s) output versions
|
196
196
|
- :func:`.load` maximum supported version (older format versions can always be read)
|
197
|
+
* - 2.0.0
|
198
|
+
- 13, 14
|
199
|
+
- 14
|
200
|
+
* - 1.4.2
|
201
|
+
- 10, 11, 12, 13
|
202
|
+
- 13
|
203
|
+
* - 1.4.1
|
204
|
+
- 10, 11, 12, 13
|
205
|
+
- 13
|
206
|
+
* - 1.4.0
|
207
|
+
- 10, 11, 12, 13
|
208
|
+
- 13
|
209
|
+
* - 1.3.3
|
210
|
+
- 10, 11, 12, 13
|
211
|
+
- 13
|
212
|
+
* - 1.3.2
|
213
|
+
- 10, 11, 12, 13
|
214
|
+
- 13
|
215
|
+
* - 1.3.1
|
216
|
+
- 10, 11, 12, 13
|
217
|
+
- 13
|
197
218
|
* - 1.3.0
|
198
219
|
- 10, 11, 12, 13
|
199
220
|
- 13
|
qiskit/qpy/binary_io/circuits.py
CHANGED
@@ -783,6 +783,11 @@ def _write_instruction(
|
|
783
783
|
custom_operations[gate_class_name] = instruction.operation
|
784
784
|
custom_operations_list.append(gate_class_name)
|
785
785
|
|
786
|
+
elif isinstance(instruction.operation, library.MCMTGate):
|
787
|
+
gate_class_name = instruction.operation.name + "_" + str(uuid.uuid4())
|
788
|
+
custom_operations[gate_class_name] = instruction.operation
|
789
|
+
custom_operations_list.append(gate_class_name)
|
790
|
+
|
786
791
|
condition_type = type_keys.Condition.NONE
|
787
792
|
condition_register = b""
|
788
793
|
condition_value = 0
|
qiskit/result/models.py
CHANGED
@@ -145,8 +145,7 @@ class ExperimentResult:
|
|
145
145
|
status (str): The status of the experiment
|
146
146
|
seed (int): The seed used for simulation (if run on a simulator)
|
147
147
|
meas_return (str): The type of measurement returned
|
148
|
-
header (dict): A free form dictionary
|
149
|
-
header for the experiment
|
148
|
+
header (dict): A free form dictionary header for the experiment
|
150
149
|
kwargs: Arbitrary extra fields
|
151
150
|
|
152
151
|
Raises:
|
qiskit/result/result.py
CHANGED
@@ -34,6 +34,9 @@ class Result:
|
|
34
34
|
each experiment success)
|
35
35
|
results (list[ExperimentResult]): corresponding results for array of
|
36
36
|
experiments of the input
|
37
|
+
date (str): optional date field
|
38
|
+
status (str): optional status field
|
39
|
+
header (dict): an optional free form dictionary header
|
37
40
|
"""
|
38
41
|
|
39
42
|
_metadata = {}
|
@@ -88,7 +91,7 @@ class Result:
|
|
88
91
|
"backend_name": self.backend_name,
|
89
92
|
"backend_version": self.backend_version,
|
90
93
|
"date": self.date,
|
91
|
-
"header":
|
94
|
+
"header": self.header,
|
92
95
|
"job_id": self.job_id,
|
93
96
|
"status": self.status,
|
94
97
|
"success": self.success,
|
@@ -128,11 +131,10 @@ class Result:
|
|
128
131
|
the get_xxx method, and the data will be post-processed for the data type.
|
129
132
|
|
130
133
|
Args:
|
131
|
-
experiment (str or QuantumCircuit or
|
134
|
+
experiment (str or QuantumCircuit or int or None): the index of the
|
132
135
|
experiment. Several types are accepted for convenience::
|
133
136
|
* str: the name of the experiment.
|
134
137
|
* QuantumCircuit: the name of the circuit instance will be used.
|
135
|
-
* Schedule: the name of the schedule instance will be used.
|
136
138
|
* int: the position of the experiment.
|
137
139
|
* None: if there is only one experiment, returns it.
|
138
140
|
|
@@ -179,7 +181,7 @@ class Result:
|
|
179
181
|
['00000', '01000', '10100', '10100', '11101', '11100', '00101', ..., '01010']
|
180
182
|
|
181
183
|
Args:
|
182
|
-
experiment (str or QuantumCircuit or
|
184
|
+
experiment (str or QuantumCircuit or int or None): the index of the
|
183
185
|
experiment, as specified by ``data()``.
|
184
186
|
|
185
187
|
Returns:
|
@@ -231,7 +233,7 @@ class Result:
|
|
231
233
|
"""Get the histogram data of an experiment.
|
232
234
|
|
233
235
|
Args:
|
234
|
-
experiment (str or QuantumCircuit or
|
236
|
+
experiment (str or QuantumCircuit or int or None): the index of the
|
235
237
|
experiment, as specified by ``data([experiment])``.
|
236
238
|
|
237
239
|
Returns:
|
@@ -283,7 +285,7 @@ class Result:
|
|
283
285
|
"""Get the final statevector of an experiment.
|
284
286
|
|
285
287
|
Args:
|
286
|
-
experiment (str or QuantumCircuit or
|
288
|
+
experiment (str or QuantumCircuit or int or None): the index of the
|
287
289
|
experiment, as specified by ``data()``.
|
288
290
|
decimals (int): the number of decimals in the statevector.
|
289
291
|
If None, does not round.
|
@@ -305,7 +307,7 @@ class Result:
|
|
305
307
|
"""Get the final unitary of an experiment.
|
306
308
|
|
307
309
|
Args:
|
308
|
-
experiment (str or QuantumCircuit or
|
310
|
+
experiment (str or QuantumCircuit or int or None): the index of the
|
309
311
|
experiment, as specified by ``data()``.
|
310
312
|
decimals (int): the number of decimals in the unitary.
|
311
313
|
If None, does not round.
|
@@ -326,7 +328,7 @@ class Result:
|
|
326
328
|
"""Return a single experiment result from a given key.
|
327
329
|
|
328
330
|
Args:
|
329
|
-
key (str or QuantumCircuit or
|
331
|
+
key (str or QuantumCircuit or int or None): the index of the
|
330
332
|
experiment, as specified by ``data()``.
|
331
333
|
|
332
334
|
Returns:
|
@@ -53,16 +53,40 @@ def _compute_rotation_axis(matrix: np.ndarray) -> np.ndarray:
|
|
53
53
|
"""
|
54
54
|
_check_is_so3(matrix)
|
55
55
|
|
56
|
+
# If theta represents the rotation angle, then trace = 1 + 2cos(theta).
|
56
57
|
trace = _compute_trace_so3(matrix)
|
57
|
-
|
58
|
-
if
|
59
|
-
|
60
|
-
y = 1 / (2 * math.sin(theta)) * (matrix[0][2] - matrix[2][0])
|
61
|
-
z = 1 / (2 * math.sin(theta)) * (matrix[1][0] - matrix[0][1])
|
62
|
-
else:
|
58
|
+
|
59
|
+
if trace >= 3 - 1e-10:
|
60
|
+
# The matrix is the identity (rotation by 0)
|
63
61
|
x = 1.0
|
64
62
|
y = 0.0
|
65
63
|
z = 0.0
|
64
|
+
|
65
|
+
elif trace <= -1 + 1e-10:
|
66
|
+
# The matrix is the 180-degree rotation
|
67
|
+
squares = (1 + np.diagonal(matrix)) / 2
|
68
|
+
index_of_max = np.argmax(squares)
|
69
|
+
|
70
|
+
if index_of_max == 0:
|
71
|
+
x = math.sqrt(squares[0])
|
72
|
+
y = matrix[0][1] / (2 * x)
|
73
|
+
z = matrix[0][2] / (2 * x)
|
74
|
+
elif index_of_max == 1:
|
75
|
+
y = math.sqrt(squares[1])
|
76
|
+
x = matrix[0][1] / (2 * y)
|
77
|
+
z = matrix[1][2] / (2 * y)
|
78
|
+
else:
|
79
|
+
z = math.sqrt(squares[2])
|
80
|
+
x = matrix[0][2] / (2 * z)
|
81
|
+
y = matrix[1][2] / (2 * z)
|
82
|
+
|
83
|
+
else:
|
84
|
+
# The matrix is the rotation by theta with sin(theta)!=0
|
85
|
+
theta = math.acos(0.5 * (trace - 1))
|
86
|
+
x = 1 / (2 * math.sin(theta)) * (matrix[2][1] - matrix[1][2])
|
87
|
+
y = 1 / (2 * math.sin(theta)) * (matrix[0][2] - matrix[2][0])
|
88
|
+
z = 1 / (2 * math.sin(theta)) * (matrix[1][0] - matrix[0][1])
|
89
|
+
|
66
90
|
return np.array([x, y, z])
|
67
91
|
|
68
92
|
|
@@ -55,7 +55,6 @@ class GateSequence:
|
|
55
55
|
self.name = " ".join(self.labels)
|
56
56
|
self.global_phase = global_phase
|
57
57
|
self.product = so3_matrix
|
58
|
-
self.product_su2 = su2_matrix
|
59
58
|
|
60
59
|
def remove_cancelling_pair(self, indices: Sequence[int]) -> None:
|
61
60
|
"""Remove a pair of indices that cancel each other and *do not* change the matrices."""
|
@@ -106,6 +105,16 @@ class GateSequence:
|
|
106
105
|
|
107
106
|
return circuit
|
108
107
|
|
108
|
+
def _to_u2(self):
|
109
|
+
"""Creates the U2 matrix corresponding to the stored sequence of gates
|
110
|
+
and the global phase.
|
111
|
+
"""
|
112
|
+
u2 = np.eye(2, dtype=complex)
|
113
|
+
for mat in self.gates:
|
114
|
+
u2 = mat.to_matrix().dot(u2)
|
115
|
+
u2 = np.exp(1j * self.global_phase) * u2
|
116
|
+
return u2
|
117
|
+
|
109
118
|
def to_dag(self):
|
110
119
|
"""Convert to a :class:`.DAGCircuit`.
|
111
120
|
|
@@ -149,7 +158,6 @@ class GateSequence:
|
|
149
158
|
so3 = _convert_su2_to_so3(su2)
|
150
159
|
|
151
160
|
self.product = so3.dot(self.product)
|
152
|
-
self.product_su2 = su2.dot(self.product_su2)
|
153
161
|
self.global_phase = self.global_phase + phase
|
154
162
|
|
155
163
|
self.gates.append(gate)
|
@@ -172,7 +180,6 @@ class GateSequence:
|
|
172
180
|
adjoint.labels = [inv.name for inv in adjoint.gates]
|
173
181
|
adjoint.name = " ".join(adjoint.labels)
|
174
182
|
adjoint.product = np.conj(self.product).T
|
175
|
-
adjoint.product_su2 = np.conj(self.product_su2).T
|
176
183
|
adjoint.global_phase = -self.global_phase
|
177
184
|
|
178
185
|
return adjoint
|
@@ -190,7 +197,6 @@ class GateSequence:
|
|
190
197
|
out.matrices = self.matrices.copy()
|
191
198
|
out.global_phase = self.global_phase
|
192
199
|
out.product = self.product.copy()
|
193
|
-
out.product_su2 = self.product_su2.copy()
|
194
200
|
out.name = self.name
|
195
201
|
out._eulers = self._eulers
|
196
202
|
return out
|
@@ -76,7 +76,7 @@ def _check_candidate_greedy(candidate, existing_sequences, tol=1e-10):
|
|
76
76
|
return False
|
77
77
|
|
78
78
|
for existing in existing_sequences:
|
79
|
-
if matrix_equal(existing.
|
79
|
+
if matrix_equal(existing.product, candidate.product, ignore_phase=True, atol=tol):
|
80
80
|
# is the new sequence less or more efficient?
|
81
81
|
return len(candidate.gates) < len(existing.gates)
|
82
82
|
return True
|
@@ -24,7 +24,7 @@ from .generate_basis_approximations import generate_basic_approximations, _1q_ga
|
|
24
24
|
class SolovayKitaevDecomposition:
|
25
25
|
"""The Solovay Kitaev discrete decomposition algorithm.
|
26
26
|
|
27
|
-
This class is called recursively by the transpiler pass, which is why it is
|
27
|
+
This class is called recursively by the transpiler pass, which is why it is separated.
|
28
28
|
See :class:`qiskit.transpiler.passes.SolovayKitaev` for more information.
|
29
29
|
"""
|
30
30
|
|
@@ -33,7 +33,7 @@ class SolovayKitaevDecomposition:
|
|
33
33
|
) -> None:
|
34
34
|
"""
|
35
35
|
Args:
|
36
|
-
basic_approximations: A specification of the basic
|
36
|
+
basic_approximations: A specification of the basic SO(3) approximations in terms
|
37
37
|
of discrete gates. At each iteration this algorithm, the remaining error is
|
38
38
|
approximated with the closest sequence of gates in this set.
|
39
39
|
If a ``str``, this specifies a ``.npy`` filename from which to load the
|
@@ -116,23 +116,33 @@ class SolovayKitaevDecomposition:
|
|
116
116
|
"""
|
117
117
|
# make input matrix SU(2) and get the according global phase
|
118
118
|
z = 1 / np.sqrt(np.linalg.det(gate_matrix))
|
119
|
-
|
119
|
+
|
120
|
+
gate_matrix_su2 = z * gate_matrix
|
121
|
+
gate_matrix_as_sequence = GateSequence.from_matrix(gate_matrix_su2)
|
120
122
|
global_phase = np.arctan2(np.imag(z), np.real(z))
|
121
123
|
|
122
124
|
# get the decomposition as GateSequence type
|
123
|
-
decomposition = self._recurse(
|
125
|
+
decomposition = self._recurse(
|
126
|
+
gate_matrix_as_sequence, recursion_degree, check_input=check_input
|
127
|
+
)
|
124
128
|
|
125
129
|
# simplify
|
126
130
|
_remove_identities(decomposition)
|
127
131
|
_remove_inverse_follows_gate(decomposition)
|
128
132
|
|
133
|
+
# adjust to the correct SU(2) phase
|
134
|
+
adjust_phase = (
|
135
|
+
np.pi if _should_adjust_phase(decomposition._to_u2(), gate_matrix_su2) else 0.0
|
136
|
+
)
|
137
|
+
|
129
138
|
# convert to a circuit and attach the right phases
|
130
139
|
if return_dag:
|
131
140
|
out = decomposition.to_dag()
|
132
141
|
else:
|
133
142
|
out = decomposition.to_circuit()
|
134
143
|
|
135
|
-
out.global_phase
|
144
|
+
out.global_phase += adjust_phase
|
145
|
+
out.global_phase -= global_phase
|
136
146
|
|
137
147
|
return out
|
138
148
|
|
@@ -155,17 +165,20 @@ class SolovayKitaevDecomposition:
|
|
155
165
|
raise ValueError("Shape of U must be (3, 3) but is", sequence.shape)
|
156
166
|
|
157
167
|
if n == 0:
|
158
|
-
|
168
|
+
res = self.find_basic_approximation(sequence)
|
159
169
|
|
160
|
-
|
170
|
+
else:
|
171
|
+
u_n1 = self._recurse(sequence, n - 1, check_input=check_input)
|
161
172
|
|
162
|
-
|
163
|
-
|
164
|
-
|
173
|
+
v_n, w_n = commutator_decompose(
|
174
|
+
sequence.dot(u_n1.adjoint()).product, check_input=check_input
|
175
|
+
)
|
176
|
+
|
177
|
+
v_n1 = self._recurse(v_n, n - 1, check_input=check_input)
|
178
|
+
w_n1 = self._recurse(w_n, n - 1, check_input=check_input)
|
179
|
+
res = v_n1.dot(w_n1).dot(v_n1.adjoint()).dot(w_n1.adjoint()).dot(u_n1)
|
165
180
|
|
166
|
-
|
167
|
-
w_n1 = self._recurse(w_n, n - 1, check_input=check_input)
|
168
|
-
return v_n1.dot(w_n1).dot(v_n1.adjoint()).dot(w_n1.adjoint()).dot(u_n1)
|
181
|
+
return res
|
169
182
|
|
170
183
|
def find_basic_approximation(self, sequence: GateSequence) -> GateSequence:
|
171
184
|
"""Find ``GateSequence`` in ``self._basic_approximations`` that approximates ``sequence``.
|
@@ -215,3 +228,13 @@ def _remove_identities(sequence):
|
|
215
228
|
sequence.gates.pop(index)
|
216
229
|
else:
|
217
230
|
index += 1
|
231
|
+
|
232
|
+
|
233
|
+
def _should_adjust_phase(computed: np.ndarray, target: np.ndarray) -> bool:
|
234
|
+
"""
|
235
|
+
The implemented SolovayKitaevDecomposition has a global phase uncertainty of +-1,
|
236
|
+
due to approximating not the original SU(2) matrix but its projection onto SO(3).
|
237
|
+
This function returns ``True`` if the global phase of the computed approximation
|
238
|
+
should be adjusted (by adding pi) to better much the target.
|
239
|
+
"""
|
240
|
+
return np.linalg.norm(-computed - target) < np.linalg.norm(computed - target)
|
@@ -91,6 +91,7 @@ Optimizations
|
|
91
91
|
Split2QUnitaries
|
92
92
|
RemoveIdentityEquivalent
|
93
93
|
ContractIdleWiresInControlFlow
|
94
|
+
LightCone
|
94
95
|
|
95
96
|
Scheduling
|
96
97
|
=============
|
@@ -225,6 +226,7 @@ from .optimization import OptimizeAnnotated
|
|
225
226
|
from .optimization import RemoveIdentityEquivalent
|
226
227
|
from .optimization import Split2QUnitaries
|
227
228
|
from .optimization import ContractIdleWiresInControlFlow
|
229
|
+
from .optimization import LightCone
|
228
230
|
|
229
231
|
# circuit analysis
|
230
232
|
from .analysis import ResourceEstimation
|
@@ -18,7 +18,7 @@ import logging
|
|
18
18
|
from collections import defaultdict
|
19
19
|
|
20
20
|
from qiskit.transpiler.basepasses import TransformationPass
|
21
|
-
from qiskit._accelerate.
|
21
|
+
from qiskit._accelerate.basis_translator import base_run
|
22
22
|
|
23
23
|
logger = logging.getLogger(__name__)
|
24
24
|
|
@@ -92,9 +92,8 @@ class FullAncillaAllocation(AnalysisPass):
|
|
92
92
|
|
93
93
|
if idle_physical_qubits:
|
94
94
|
if self.ancilla_name in dag.qregs:
|
95
|
-
qreg = QuantumRegister(
|
96
|
-
len(idle_physical_qubits),
|
97
|
-
name=f"{self.ancilla_name}{QuantumRegister.instances_count + 1}",
|
95
|
+
qreg = QuantumRegister._new_with_prefix(
|
96
|
+
len(idle_physical_qubits), self.ancilla_name
|
98
97
|
)
|
99
98
|
else:
|
100
99
|
qreg = QuantumRegister(len(idle_physical_qubits), name=self.ancilla_name)
|
@@ -305,6 +305,9 @@ class SabreLayout(TransformationPass):
|
|
305
305
|
# the layout and routing together as part of resolving the Sabre result.
|
306
306
|
physical_qubits = QuantumRegister(self.coupling_map.size(), "q")
|
307
307
|
mapped_dag = DAGCircuit()
|
308
|
+
mapped_dag.name = dag.name
|
309
|
+
mapped_dag.metadata = dag.metadata
|
310
|
+
mapped_dag.global_phase = dag.global_phase
|
308
311
|
mapped_dag.add_qreg(physical_qubits)
|
309
312
|
mapped_dag.add_clbits(dag.clbits)
|
310
313
|
for creg in dag.cregs.values():
|
@@ -319,7 +322,6 @@ class SabreLayout(TransformationPass):
|
|
319
322
|
mapped_dag.add_captured_stretch(stretch)
|
320
323
|
for stretch in dag.iter_declared_stretches():
|
321
324
|
mapped_dag.add_declared_stretch(stretch)
|
322
|
-
mapped_dag.global_phase = dag.global_phase
|
323
325
|
self.property_set["original_qubit_indices"] = {
|
324
326
|
bit: index for index, bit in enumerate(dag.qubits)
|
325
327
|
}
|
@@ -179,11 +179,8 @@ def build_average_error_map(target, coupling_map):
|
|
179
179
|
coupling_map = target.build_coupling_map()
|
180
180
|
if not built and coupling_map is not None and num_qubits is not None:
|
181
181
|
for qubit in range(num_qubits):
|
182
|
-
|
183
|
-
|
184
|
-
(coupling_map.graph.out_degree(qubit) + coupling_map.graph.in_degree(qubit))
|
185
|
-
/ num_qubits,
|
186
|
-
)
|
182
|
+
degree = len(set(coupling_map.graph.neighbors_undirected(qubit)))
|
183
|
+
avg_map.add_error((qubit, qubit), degree / num_qubits)
|
187
184
|
for edge in coupling_map.graph.edge_list():
|
188
185
|
avg_map.add_error(edge, (avg_map[edge[0], edge[0]] + avg_map[edge[1], edge[1]]) / 2)
|
189
186
|
built = True
|
@@ -39,3 +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 .light_cone import LightCone
|
@@ -91,6 +91,7 @@ class ConsolidateBlocks(TransformationPass):
|
|
91
91
|
"""
|
92
92
|
super().__init__()
|
93
93
|
self.basis_gates = None
|
94
|
+
self.basis_gate_name = None
|
94
95
|
# Bypass target if it doesn't contain any basis gates (i.e. it's a _FakeTarget), as this
|
95
96
|
# not part of the official target model.
|
96
97
|
self.target = target if target is not None and len(target.operation_names) > 0 else None
|
@@ -99,6 +100,7 @@ class ConsolidateBlocks(TransformationPass):
|
|
99
100
|
self.force_consolidate = force_consolidate
|
100
101
|
if kak_basis_gate is not None:
|
101
102
|
self.decomposer = TwoQubitBasisDecomposer(kak_basis_gate)
|
103
|
+
self.basis_gate_name = kak_basis_gate.name
|
102
104
|
elif basis_gates is not None:
|
103
105
|
kak_gates = KAK_GATE_NAMES.keys() & (basis_gates or [])
|
104
106
|
kak_param_gates = KAK_GATE_PARAM_NAMES.keys() & (basis_gates or [])
|
@@ -106,14 +108,17 @@ class ConsolidateBlocks(TransformationPass):
|
|
106
108
|
self.decomposer = TwoQubitControlledUDecomposer(
|
107
109
|
KAK_GATE_PARAM_NAMES[list(kak_param_gates)[0]]
|
108
110
|
)
|
111
|
+
self.basis_gate_name = list(kak_param_gates)[0]
|
109
112
|
elif kak_gates:
|
110
113
|
self.decomposer = TwoQubitBasisDecomposer(
|
111
114
|
KAK_GATE_NAMES[list(kak_gates)[0]], basis_fidelity=approximation_degree or 1.0
|
112
115
|
)
|
116
|
+
self.basis_gate_name = list(kak_gates)[0]
|
113
117
|
else:
|
114
118
|
self.decomposer = None
|
115
119
|
else:
|
116
120
|
self.decomposer = TwoQubitBasisDecomposer(CXGate())
|
121
|
+
self.basis_gate_name = "cx"
|
117
122
|
|
118
123
|
def run(self, dag):
|
119
124
|
"""Run the ConsolidateBlocks pass on `dag`.
|
@@ -134,7 +139,7 @@ class ConsolidateBlocks(TransformationPass):
|
|
134
139
|
consolidate_blocks(
|
135
140
|
dag,
|
136
141
|
self.decomposer._inner_decomposer,
|
137
|
-
self.
|
142
|
+
self.basis_gate_name,
|
138
143
|
self.force_consolidate,
|
139
144
|
target=self.target,
|
140
145
|
basis_gates=self.basis_gates,
|
@@ -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:
|
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
|
@@ -124,7 +124,7 @@ class BasePadding(TransformationPass):
|
|
124
124
|
|
125
125
|
new_dag.name = dag.name
|
126
126
|
new_dag.metadata = dag.metadata
|
127
|
-
new_dag.
|
127
|
+
new_dag._unit = self.property_set["time_unit"]
|
128
128
|
new_dag.global_phase = dag.global_phase
|
129
129
|
|
130
130
|
idle_after = {bit: 0 for bit in dag.qubits}
|
@@ -186,7 +186,7 @@ class BasePadding(TransformationPass):
|
|
186
186
|
prev_node=prev_node,
|
187
187
|
)
|
188
188
|
|
189
|
-
new_dag.
|
189
|
+
new_dag._duration = circuit_duration
|
190
190
|
|
191
191
|
return new_dag
|
192
192
|
|
@@ -310,14 +310,14 @@ class PadDynamicalDecoupling(BasePadding):
|
|
310
310
|
|
311
311
|
if not self.__is_dd_qubit(dag.qubits.index(qubit)):
|
312
312
|
# Target physical qubit is not the target of this DD sequence.
|
313
|
-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.
|
313
|
+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
|
314
314
|
return
|
315
315
|
|
316
316
|
if self._skip_reset_qubits and (
|
317
317
|
isinstance(prev_node, DAGInNode) or isinstance(prev_node.op, Reset)
|
318
318
|
):
|
319
319
|
# Previous node is the start edge or reset, i.e. qubit is ground state.
|
320
|
-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.
|
320
|
+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
|
321
321
|
return
|
322
322
|
|
323
323
|
slack = time_interval - np.sum(self._dd_sequence_lengths[qubit])
|
@@ -325,7 +325,7 @@ class PadDynamicalDecoupling(BasePadding):
|
|
325
325
|
|
326
326
|
if slack <= 0:
|
327
327
|
# Interval too short.
|
328
|
-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.
|
328
|
+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
|
329
329
|
return
|
330
330
|
|
331
331
|
if len(self._dd_sequence) == 1:
|
@@ -351,7 +351,7 @@ class PadDynamicalDecoupling(BasePadding):
|
|
351
351
|
sequence_gphase += phase
|
352
352
|
else:
|
353
353
|
# Don't do anything if there's no single-qubit gate to absorb the inverse
|
354
|
-
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag.
|
354
|
+
self._apply_scheduled_op(dag, t_start, Delay(time_interval, dag._unit), qubit)
|
355
355
|
return
|
356
356
|
|
357
357
|
def _constrained_length(values):
|
@@ -387,7 +387,7 @@ class PadDynamicalDecoupling(BasePadding):
|
|
387
387
|
if dd_ind < len(taus):
|
388
388
|
tau = taus[dd_ind]
|
389
389
|
if tau > 0:
|
390
|
-
self._apply_scheduled_op(dag, idle_after, Delay(tau, dag.
|
390
|
+
self._apply_scheduled_op(dag, idle_after, Delay(tau, dag._unit), qubit)
|
391
391
|
idle_after += tau
|
392
392
|
if dd_ind < len(self._dd_sequence):
|
393
393
|
gate = self._dd_sequence[dd_ind]
|
@@ -126,15 +126,19 @@ class TimeUnitConversion(TransformationPass):
|
|
126
126
|
# Check what units are used in other instructions: dt or SI or mixed
|
127
127
|
units_other = inst_durations.units_used()
|
128
128
|
unified_unit = self._unified(units_other)
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
time_unit = "dt"
|
133
|
-
else:
|
129
|
+
has_si = has_si or unified_unit in {"SI", "mixed"}
|
130
|
+
has_dt = has_dt or unified_unit in {"dt", "mixed"}
|
131
|
+
if has_si and has_dt:
|
134
132
|
raise TranspilerError(
|
135
133
|
"Fail to unify time units. SI units "
|
136
134
|
"and dt unit must not be mixed when dt is not supplied."
|
137
135
|
)
|
136
|
+
if has_si:
|
137
|
+
time_unit = "s"
|
138
|
+
else:
|
139
|
+
# Either dt units were used or no units were used and we
|
140
|
+
# default to dt
|
141
|
+
time_unit = "dt"
|
138
142
|
else:
|
139
143
|
time_unit = "dt"
|
140
144
|
|
@@ -154,7 +158,7 @@ class TimeUnitConversion(TransformationPass):
|
|
154
158
|
@staticmethod
|
155
159
|
def _unified(unit_set: Set[str]) -> str:
|
156
160
|
if not unit_set:
|
157
|
-
return "
|
161
|
+
return "none"
|
158
162
|
|
159
163
|
if len(unit_set) == 1 and "dt" in unit_set:
|
160
164
|
return "dt"
|