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
qiskit/qpy/binary_io/circuits.py
CHANGED
@@ -13,18 +13,23 @@
|
|
13
13
|
# pylint: disable=invalid-name
|
14
14
|
|
15
15
|
"""Binary IO for circuit objects."""
|
16
|
+
|
17
|
+
from __future__ import annotations
|
18
|
+
|
16
19
|
import itertools
|
17
20
|
from collections import defaultdict
|
18
21
|
import io
|
19
22
|
import json
|
20
23
|
import struct
|
21
24
|
import uuid
|
25
|
+
import typing
|
22
26
|
import warnings
|
23
27
|
|
24
28
|
import numpy as np
|
25
29
|
|
26
30
|
from qiskit import circuit as circuit_mod
|
27
31
|
from qiskit.circuit import library, controlflow, CircuitInstruction, ControlFlowOp, IfElseOp
|
32
|
+
from qiskit.circuit.annotation import iter_namespaces
|
28
33
|
from qiskit.circuit.classical import expr
|
29
34
|
from qiskit.circuit import ClassicalRegister, Clbit
|
30
35
|
from qiskit.circuit.gate import Gate
|
@@ -41,11 +46,81 @@ from qiskit.circuit.instruction import Instruction
|
|
41
46
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
42
47
|
from qiskit.circuit import QuantumRegister, Qubit
|
43
48
|
from qiskit.qpy import common, formats, type_keys
|
49
|
+
from qiskit.qpy.exceptions import QpyError, UnsupportedFeatureForVersion
|
44
50
|
from qiskit.qpy.binary_io import value, schedules
|
45
51
|
from qiskit.quantum_info.operators import SparsePauliOp, Clifford
|
46
52
|
from qiskit.synthesis import evolution as evo_synth
|
47
53
|
from qiskit.transpiler.layout import Layout, TranspileLayout
|
48
54
|
|
55
|
+
if typing.TYPE_CHECKING:
|
56
|
+
from qiskit.circuit.annotation import QPYSerializer, Annotation
|
57
|
+
|
58
|
+
|
59
|
+
class _AnnotationSerializationState:
|
60
|
+
def __init__(self, factories: dict[str, typing.Callable[[], QPYSerializer]]):
|
61
|
+
self.factories = factories
|
62
|
+
self.serializers = {}
|
63
|
+
self.potential_serializers = {}
|
64
|
+
|
65
|
+
@property
|
66
|
+
def num_serializers(self) -> int:
|
67
|
+
"""The number of constructed serializers."""
|
68
|
+
return len(self.serializers)
|
69
|
+
|
70
|
+
def serialize(self, annotation: Annotation) -> (int, bytes):
|
71
|
+
"""Serialize an annotation using a known serializer (initializing one, if necessary).
|
72
|
+
|
73
|
+
Returns the index of the serializer used, and the serialized annotation."""
|
74
|
+
for namespace in iter_namespaces(annotation.namespace):
|
75
|
+
if (existing := self.serializers.get(namespace, None)) is not None:
|
76
|
+
index, serializer = existing
|
77
|
+
if (out := serializer.dump_annotation(namespace, annotation)) is not NotImplemented:
|
78
|
+
return index, out
|
79
|
+
if (serializer := self.potential_serializers.get(namespace, None)) is not None:
|
80
|
+
if (out := serializer.dump_annotation(namespace, annotation)) is not NotImplemented:
|
81
|
+
del self.potential_serializers[namespace]
|
82
|
+
index = len(self.serializers)
|
83
|
+
self.serializers[namespace] = (index, serializer)
|
84
|
+
return index, out
|
85
|
+
if (factory := self.factories.get(namespace, None)) is not None:
|
86
|
+
serializer = factory()
|
87
|
+
if (out := serializer.dump_annotation(namespace, annotation)) is NotImplemented:
|
88
|
+
self.potential_serializers[namespace] = serializer
|
89
|
+
else:
|
90
|
+
index = len(self.serializers)
|
91
|
+
self.serializers[namespace] = (index, serializer)
|
92
|
+
return index, out
|
93
|
+
raise QpyError(f"No configured annotation serializer could handle {annotation}")
|
94
|
+
|
95
|
+
def iter_serializers(self) -> typing.Iterator[tuple[str, QPYSerializer]]:
|
96
|
+
"""Iterate over the namespaces and serializers that have had at least one successful use, in
|
97
|
+
order of first use."""
|
98
|
+
return (
|
99
|
+
# Python dictionaries are insertion ordered, and we assign indices in insertion order.
|
100
|
+
(namespace, serializer)
|
101
|
+
for (namespace, (_, serializer)) in self.serializers.items()
|
102
|
+
)
|
103
|
+
|
104
|
+
|
105
|
+
class _AnnotationDeserializationState:
|
106
|
+
def __init__(self, factories: dict[str, typing.Callable[[], QPYSerializer]]):
|
107
|
+
self.factories = factories
|
108
|
+
self.deserializers = []
|
109
|
+
|
110
|
+
def initialize(self, namespace: str, payload: bytes):
|
111
|
+
"""Initialize a suitable deserializer using the given state payload."""
|
112
|
+
for parent_namespace in iter_namespaces(namespace):
|
113
|
+
if (factory := self.factories.get(parent_namespace, None)) is not None:
|
114
|
+
deserializer = factory()
|
115
|
+
deserializer.load_state(namespace, payload)
|
116
|
+
self.deserializers.append(deserializer)
|
117
|
+
return
|
118
|
+
raise QpyError(f"No configured annotation deserializer matched namespace '{namespace}'")
|
119
|
+
|
120
|
+
def load(self, index: int, payload: bytes) -> Annotation:
|
121
|
+
"""Load a payload using the deserializer of a given index."""
|
122
|
+
return self.deserializers[index].load_annotation(payload)
|
123
|
+
|
49
124
|
|
50
125
|
def _read_header_v12(file_obj, version, vectors, metadata_deserializer=None):
|
51
126
|
data = formats.CIRCUIT_HEADER_V12._make(
|
@@ -158,6 +233,50 @@ def _read_registers(file_obj, num_registers):
|
|
158
233
|
return registers
|
159
234
|
|
160
235
|
|
236
|
+
def _read_annotation_states(file_obj, annotation_factories) -> _AnnotationDeserializationState:
|
237
|
+
state = _AnnotationDeserializationState(annotation_factories)
|
238
|
+
static_payload = formats.ANNOTATION_HEADER_STATIC._make(
|
239
|
+
struct.unpack(
|
240
|
+
formats.ANNOTATION_HEADER_STATIC_PACK,
|
241
|
+
file_obj.read(formats.ANNOTATION_HEADER_STATIC_SIZE),
|
242
|
+
)
|
243
|
+
)
|
244
|
+
for _ in range(static_payload.num_namespaces):
|
245
|
+
payload = formats.ANNOTATION_STATE_HEADER._make(
|
246
|
+
struct.unpack(
|
247
|
+
formats.ANNOTATION_STATE_HEADER_PACK,
|
248
|
+
file_obj.read(formats.ANNOTATION_STATE_HEADER_SIZE),
|
249
|
+
)
|
250
|
+
)
|
251
|
+
state.initialize(
|
252
|
+
file_obj.read(payload.namespace_size).decode("utf-8"), file_obj.read(payload.state_size)
|
253
|
+
)
|
254
|
+
return state
|
255
|
+
|
256
|
+
|
257
|
+
def _read_instruction_annotation(file_obj, annotation_state):
|
258
|
+
header = formats.INSTRUCTION_ANNOTATION._make(
|
259
|
+
struct.unpack(
|
260
|
+
formats.INSTRUCTION_ANNOTATION_PACK,
|
261
|
+
file_obj.read(formats.INSTRUCTION_ANNOTATION_SIZE),
|
262
|
+
)
|
263
|
+
)
|
264
|
+
return annotation_state.load(header.namespace_index, file_obj.read(header.payload_size))
|
265
|
+
|
266
|
+
|
267
|
+
def _read_instruction_annotations(file_obj, annotation_state):
|
268
|
+
header = formats.INSTRUCTION_ANNOTATIONS_HEADER._make(
|
269
|
+
struct.unpack(
|
270
|
+
formats.INSTRUCTION_ANNOTATIONS_HEADER_PACK,
|
271
|
+
file_obj.read(formats.INSTRUCTION_ANNOTATIONS_HEADER_SIZE),
|
272
|
+
)
|
273
|
+
)
|
274
|
+
return [
|
275
|
+
_read_instruction_annotation(file_obj, annotation_state)
|
276
|
+
for _ in range(header.num_annotations)
|
277
|
+
]
|
278
|
+
|
279
|
+
|
161
280
|
def _loads_instruction_parameter(
|
162
281
|
type_key,
|
163
282
|
data_bytes,
|
@@ -167,9 +286,12 @@ def _loads_instruction_parameter(
|
|
167
286
|
circuit,
|
168
287
|
use_symengine,
|
169
288
|
standalone_vars,
|
289
|
+
annotation_factories,
|
170
290
|
):
|
171
291
|
if type_key == type_keys.Program.CIRCUIT:
|
172
|
-
param = common.data_from_binary(
|
292
|
+
param = common.data_from_binary(
|
293
|
+
data_bytes, read_circuit, version=version, annotation_factories=annotation_factories
|
294
|
+
)
|
173
295
|
elif type_key == type_keys.Value.MODIFIER:
|
174
296
|
param = common.data_from_binary(data_bytes, _read_modifier)
|
175
297
|
elif type_key == type_keys.Container.RANGE:
|
@@ -186,6 +308,7 @@ def _loads_instruction_parameter(
|
|
186
308
|
circuit=circuit,
|
187
309
|
use_symengine=use_symengine,
|
188
310
|
standalone_vars=standalone_vars,
|
311
|
+
annotation_factories=annotation_factories,
|
189
312
|
)
|
190
313
|
)
|
191
314
|
elif type_key == type_keys.Value.INTEGER:
|
@@ -229,6 +352,7 @@ def _read_instruction(
|
|
229
352
|
vectors,
|
230
353
|
use_symengine,
|
231
354
|
standalone_vars,
|
355
|
+
annotation_state,
|
232
356
|
):
|
233
357
|
if version < 5:
|
234
358
|
instruction = formats.CIRCUIT_INSTRUCTION._make(
|
@@ -237,6 +361,10 @@ def _read_instruction(
|
|
237
361
|
file_obj.read(formats.CIRCUIT_INSTRUCTION_SIZE),
|
238
362
|
)
|
239
363
|
)
|
364
|
+
conditional_key = (
|
365
|
+
type_keys.Condition.TWO_TUPLE if instruction.has_condition else type_keys.Condition.NONE
|
366
|
+
)
|
367
|
+
has_annotations = False
|
240
368
|
else:
|
241
369
|
instruction = formats.CIRCUIT_INSTRUCTION_V2._make(
|
242
370
|
struct.unpack(
|
@@ -244,6 +372,11 @@ def _read_instruction(
|
|
244
372
|
file_obj.read(formats.CIRCUIT_INSTRUCTION_V2_SIZE),
|
245
373
|
)
|
246
374
|
)
|
375
|
+
conditional_key = type_keys.Condition(instruction.extras_key & 0b11)
|
376
|
+
has_annotations = bool(
|
377
|
+
instruction.extras_key & type_keys.InstructionExtraFlags.HAS_ANNOTATIONS
|
378
|
+
)
|
379
|
+
|
247
380
|
gate_name = file_obj.read(instruction.name_size).decode(common.ENCODE)
|
248
381
|
label = file_obj.read(instruction.label_size).decode(common.ENCODE)
|
249
382
|
condition_register = file_obj.read(instruction.condition_register_size).decode(common.ENCODE)
|
@@ -251,14 +384,12 @@ def _read_instruction(
|
|
251
384
|
cargs = []
|
252
385
|
params = []
|
253
386
|
condition = None
|
254
|
-
if
|
255
|
-
version >= 5 and instruction.conditional_key == type_keys.Condition.TWO_TUPLE
|
256
|
-
):
|
387
|
+
if conditional_key == type_keys.Condition.TWO_TUPLE:
|
257
388
|
condition = (
|
258
389
|
_loads_register_param(condition_register, circuit, registers),
|
259
390
|
instruction.condition_value,
|
260
391
|
)
|
261
|
-
elif
|
392
|
+
elif conditional_key == type_keys.Condition.EXPRESSION:
|
262
393
|
condition = value.read_value(
|
263
394
|
file_obj,
|
264
395
|
version,
|
@@ -268,6 +399,7 @@ def _read_instruction(
|
|
268
399
|
use_symengine=use_symengine,
|
269
400
|
standalone_vars=standalone_vars,
|
270
401
|
)
|
402
|
+
|
271
403
|
# Load Arguments
|
272
404
|
if circuit is not None:
|
273
405
|
for _qarg in range(instruction.num_qargs):
|
@@ -303,9 +435,15 @@ def _read_instruction(
|
|
303
435
|
circuit,
|
304
436
|
use_symengine,
|
305
437
|
standalone_vars,
|
438
|
+
annotation_factories=annotation_state.factories,
|
306
439
|
)
|
307
440
|
params.append(param)
|
308
441
|
|
442
|
+
# Load annotations.
|
443
|
+
annotations = (
|
444
|
+
_read_instruction_annotations(file_obj, annotation_state) if has_annotations else None
|
445
|
+
)
|
446
|
+
|
309
447
|
# Load Gate object
|
310
448
|
if gate_name in {"Gate", "Instruction", "ControlledGate"}:
|
311
449
|
inst_obj = _parse_custom_operation(
|
@@ -317,6 +455,7 @@ def _read_instruction(
|
|
317
455
|
registers,
|
318
456
|
use_symengine,
|
319
457
|
standalone_vars,
|
458
|
+
annotation_state=annotation_state,
|
320
459
|
)
|
321
460
|
if condition is not None:
|
322
461
|
warnings.warn(
|
@@ -346,6 +485,7 @@ def _read_instruction(
|
|
346
485
|
registers,
|
347
486
|
use_symengine,
|
348
487
|
standalone_vars,
|
488
|
+
annotation_state=annotation_state,
|
349
489
|
)
|
350
490
|
inst_obj.condition = condition
|
351
491
|
if instruction.label_size > 0:
|
@@ -371,7 +511,9 @@ def _read_instruction(
|
|
371
511
|
gate = gate_class(condition, *params, label=label)
|
372
512
|
elif gate_name == "BoxOp":
|
373
513
|
*params, duration, unit = params
|
374
|
-
gate = gate_class(
|
514
|
+
gate = gate_class(
|
515
|
+
*params, label=label, duration=duration, unit=unit, annotations=annotations or ()
|
516
|
+
)
|
375
517
|
elif version >= 5 and issubclass(gate_class, ControlledGate):
|
376
518
|
if gate_name in {
|
377
519
|
"MCPhaseGate",
|
@@ -460,6 +602,7 @@ def _parse_custom_operation(
|
|
460
602
|
registers,
|
461
603
|
use_symengine,
|
462
604
|
standalone_vars,
|
605
|
+
annotation_state,
|
463
606
|
):
|
464
607
|
if version >= 5:
|
465
608
|
(
|
@@ -501,6 +644,7 @@ def _parse_custom_operation(
|
|
501
644
|
vectors,
|
502
645
|
use_symengine,
|
503
646
|
standalone_vars,
|
647
|
+
annotation_state=annotation_state,
|
504
648
|
)
|
505
649
|
if ctrl_state < 2**num_ctrl_qubits - 1:
|
506
650
|
# If open controls, we need to discard the control suffix when setting the name.
|
@@ -527,6 +671,7 @@ def _parse_custom_operation(
|
|
527
671
|
vectors,
|
528
672
|
use_symengine,
|
529
673
|
standalone_vars,
|
674
|
+
annotation_state=annotation_state,
|
530
675
|
)
|
531
676
|
inst_obj = AnnotatedOperation(base_op=base_gate, modifiers=params)
|
532
677
|
return inst_obj
|
@@ -595,7 +740,7 @@ def _read_modifier(file_obj):
|
|
595
740
|
raise TypeError("Unsupported modifier.")
|
596
741
|
|
597
742
|
|
598
|
-
def _read_custom_operations(file_obj, version, vectors):
|
743
|
+
def _read_custom_operations(file_obj, version, vectors, annotation_state):
|
599
744
|
custom_operations = {}
|
600
745
|
custom_definition_header = formats.CUSTOM_CIRCUIT_DEF_HEADER._make(
|
601
746
|
struct.unpack(
|
@@ -627,7 +772,10 @@ def _read_custom_operations(file_obj, version, vectors):
|
|
627
772
|
def_binary = file_obj.read(data.size)
|
628
773
|
if version < 3 or not name.startswith(r"###PauliEvolutionGate_"):
|
629
774
|
definition_circuit = common.data_from_binary(
|
630
|
-
def_binary,
|
775
|
+
def_binary,
|
776
|
+
read_circuit,
|
777
|
+
version=version,
|
778
|
+
annotation_factories=annotation_state.factories,
|
631
779
|
)
|
632
780
|
elif name.startswith(r"###PauliEvolutionGate_"):
|
633
781
|
definition_circuit = common.data_from_binary(
|
@@ -684,11 +832,13 @@ def _dumps_register(register, index_map):
|
|
684
832
|
|
685
833
|
|
686
834
|
def _dumps_instruction_parameter(
|
687
|
-
param, index_map, use_symengine, *, version, standalone_var_indices
|
835
|
+
param, index_map, use_symengine, *, version, standalone_var_indices, annotation_factories
|
688
836
|
):
|
689
837
|
if isinstance(param, QuantumCircuit):
|
690
838
|
type_key = type_keys.Program.CIRCUIT
|
691
|
-
data_bytes = common.data_to_binary(
|
839
|
+
data_bytes = common.data_to_binary(
|
840
|
+
param, write_circuit, version=version, annotation_factories=annotation_factories
|
841
|
+
)
|
692
842
|
elif isinstance(param, Modifier):
|
693
843
|
type_key = type_keys.Value.MODIFIER
|
694
844
|
data_bytes = common.data_to_binary(param, _write_modifier)
|
@@ -704,6 +854,7 @@ def _dumps_instruction_parameter(
|
|
704
854
|
use_symengine=use_symengine,
|
705
855
|
version=version,
|
706
856
|
standalone_var_indices=standalone_var_indices,
|
857
|
+
annotation_factories=annotation_factories,
|
707
858
|
)
|
708
859
|
elif isinstance(param, int):
|
709
860
|
# TODO This uses little endian. This should be fixed in next QPY version.
|
@@ -736,6 +887,7 @@ def _write_instruction(
|
|
736
887
|
index_map,
|
737
888
|
use_symengine,
|
738
889
|
version,
|
890
|
+
annotation_state,
|
739
891
|
standalone_var_indices=None,
|
740
892
|
):
|
741
893
|
if isinstance(instruction.operation, Instruction):
|
@@ -788,14 +940,14 @@ def _write_instruction(
|
|
788
940
|
custom_operations[gate_class_name] = instruction.operation
|
789
941
|
custom_operations_list.append(gate_class_name)
|
790
942
|
|
791
|
-
|
943
|
+
extra_type = type_keys.Condition.NONE
|
792
944
|
condition_register = b""
|
793
945
|
condition_value = 0
|
794
946
|
if (op_condition := getattr(instruction.operation, "_condition", None)) is not None:
|
795
947
|
if isinstance(op_condition, expr.Expr):
|
796
|
-
|
948
|
+
extra_type = type_keys.Condition.EXPRESSION
|
797
949
|
else:
|
798
|
-
|
950
|
+
extra_type = type_keys.Condition.TWO_TUPLE
|
799
951
|
condition_register = _dumps_register(instruction.operation._condition[0], index_map)
|
800
952
|
condition_value = int(instruction.operation._condition[1])
|
801
953
|
|
@@ -806,6 +958,7 @@ def _write_instruction(
|
|
806
958
|
else:
|
807
959
|
label_raw = b""
|
808
960
|
|
961
|
+
annotations = []
|
809
962
|
# The instruction params we store are about being able to reconstruct the objects; they don't
|
810
963
|
# necessarily need to match one-to-one to the `params` field.
|
811
964
|
if isinstance(instruction.operation, controlflow.SwitchCaseOp):
|
@@ -819,6 +972,10 @@ def _write_instruction(
|
|
819
972
|
instruction.operation.duration,
|
820
973
|
instruction.operation.unit,
|
821
974
|
]
|
975
|
+
annotations = [
|
976
|
+
annotation_state.serialize(annotation)
|
977
|
+
for annotation in instruction.operation.annotations
|
978
|
+
]
|
822
979
|
elif isinstance(instruction.operation, Clifford):
|
823
980
|
instruction_params = [instruction.operation.tableau]
|
824
981
|
elif isinstance(instruction.operation, AnnotatedOperation):
|
@@ -826,6 +983,9 @@ def _write_instruction(
|
|
826
983
|
else:
|
827
984
|
instruction_params = getattr(instruction.operation, "params", [])
|
828
985
|
|
986
|
+
if annotations:
|
987
|
+
extra_type |= type_keys.InstructionExtraFlags.HAS_ANNOTATIONS
|
988
|
+
|
829
989
|
num_ctrl_qubits = getattr(instruction.operation, "num_ctrl_qubits", 0)
|
830
990
|
ctrl_state = getattr(instruction.operation, "ctrl_state", 0)
|
831
991
|
instruction_raw = struct.pack(
|
@@ -835,7 +995,7 @@ def _write_instruction(
|
|
835
995
|
len(instruction_params),
|
836
996
|
instruction.operation.num_qubits,
|
837
997
|
instruction.operation.num_clbits,
|
838
|
-
|
998
|
+
int(extra_type),
|
839
999
|
len(condition_register),
|
840
1000
|
condition_value,
|
841
1001
|
num_ctrl_qubits,
|
@@ -844,6 +1004,7 @@ def _write_instruction(
|
|
844
1004
|
file_obj.write(instruction_raw)
|
845
1005
|
file_obj.write(gate_class_name)
|
846
1006
|
file_obj.write(label_raw)
|
1007
|
+
condition_type = type_keys.Condition(extra_type & 0b11)
|
847
1008
|
if condition_type is type_keys.Condition.EXPRESSION:
|
848
1009
|
value.write_value(
|
849
1010
|
file_obj,
|
@@ -854,6 +1015,7 @@ def _write_instruction(
|
|
854
1015
|
)
|
855
1016
|
else:
|
856
1017
|
file_obj.write(condition_register)
|
1018
|
+
|
857
1019
|
# Encode instruction args
|
858
1020
|
for qbit in instruction.qubits:
|
859
1021
|
instruction_arg_raw = struct.pack(
|
@@ -873,8 +1035,20 @@ def _write_instruction(
|
|
873
1035
|
use_symengine,
|
874
1036
|
version=version,
|
875
1037
|
standalone_var_indices=standalone_var_indices,
|
1038
|
+
annotation_factories=annotation_state.factories,
|
876
1039
|
)
|
877
1040
|
common.write_generic_typed_data(file_obj, type_key, data_bytes)
|
1041
|
+
if annotations:
|
1042
|
+
if version < 15:
|
1043
|
+
raise UnsupportedFeatureForVersion("annotations", 15, version)
|
1044
|
+
file_obj.write(struct.pack(formats.INSTRUCTION_ANNOTATIONS_HEADER_PACK, len(annotations)))
|
1045
|
+
for serializer_index, annotation_payload in annotations:
|
1046
|
+
file_obj.write(
|
1047
|
+
struct.pack(
|
1048
|
+
formats.INSTRUCTION_ANNOTATION_PACK, serializer_index, len(annotation_payload)
|
1049
|
+
)
|
1050
|
+
)
|
1051
|
+
file_obj.write(annotation_payload)
|
878
1052
|
return custom_operations_list
|
879
1053
|
|
880
1054
|
|
@@ -944,7 +1118,15 @@ def _write_modifier(file_obj, modifier):
|
|
944
1118
|
|
945
1119
|
|
946
1120
|
def _write_custom_operation(
|
947
|
-
file_obj,
|
1121
|
+
file_obj,
|
1122
|
+
name,
|
1123
|
+
operation,
|
1124
|
+
custom_operations,
|
1125
|
+
use_symengine,
|
1126
|
+
version,
|
1127
|
+
*,
|
1128
|
+
standalone_var_indices,
|
1129
|
+
annotation_state,
|
948
1130
|
):
|
949
1131
|
type_key = type_keys.CircuitInstruction.assign(operation)
|
950
1132
|
has_definition = False
|
@@ -970,7 +1152,12 @@ def _write_custom_operation(
|
|
970
1152
|
# Build internal definition to support overloaded subclasses by
|
971
1153
|
# calling definition getter on object
|
972
1154
|
operation.definition # pylint: disable=pointless-statement
|
973
|
-
data = common.data_to_binary(
|
1155
|
+
data = common.data_to_binary(
|
1156
|
+
operation._definition,
|
1157
|
+
write_circuit,
|
1158
|
+
version=version,
|
1159
|
+
annotation_factories=annotation_state.factories,
|
1160
|
+
)
|
974
1161
|
size = len(data)
|
975
1162
|
num_ctrl_qubits = operation.num_ctrl_qubits
|
976
1163
|
ctrl_state = operation.ctrl_state
|
@@ -980,7 +1167,12 @@ def _write_custom_operation(
|
|
980
1167
|
base_gate = operation.base_op
|
981
1168
|
elif operation.definition is not None:
|
982
1169
|
has_definition = True
|
983
|
-
data = common.data_to_binary(
|
1170
|
+
data = common.data_to_binary(
|
1171
|
+
operation.definition,
|
1172
|
+
write_circuit,
|
1173
|
+
version=version,
|
1174
|
+
annotation_factories=annotation_state.factories,
|
1175
|
+
)
|
984
1176
|
size = len(data)
|
985
1177
|
if base_gate is None:
|
986
1178
|
base_gate_raw = b""
|
@@ -994,6 +1186,7 @@ def _write_custom_operation(
|
|
994
1186
|
use_symengine,
|
995
1187
|
version,
|
996
1188
|
standalone_var_indices=standalone_var_indices,
|
1189
|
+
annotation_state=annotation_state,
|
997
1190
|
)
|
998
1191
|
base_gate_raw = base_gate_buffer.getvalue()
|
999
1192
|
name_raw = name.encode(common.ENCODE)
|
@@ -1203,7 +1396,12 @@ def _read_layout_v2(file_obj, circuit):
|
|
1203
1396
|
|
1204
1397
|
|
1205
1398
|
def write_circuit(
|
1206
|
-
file_obj,
|
1399
|
+
file_obj,
|
1400
|
+
circuit,
|
1401
|
+
metadata_serializer=None,
|
1402
|
+
use_symengine=False,
|
1403
|
+
version=common.QPY_VERSION,
|
1404
|
+
annotation_factories=None,
|
1207
1405
|
):
|
1208
1406
|
"""Write a single QuantumCircuit object in the file like object.
|
1209
1407
|
|
@@ -1219,7 +1417,10 @@ def write_circuit(
|
|
1219
1417
|
platforms. Please check that your target platform is supported by the symengine library
|
1220
1418
|
before setting this option, as it will be required by qpy to deserialize the payload.
|
1221
1419
|
version (int): The QPY format version to use for serializing this circuit
|
1420
|
+
annotation_factories (dict): a mapping of namespaces to zero-argument factory functions that
|
1421
|
+
produce instances of :class:`.annotation.QPYSerializer`.
|
1222
1422
|
"""
|
1423
|
+
annotation_state = _AnnotationSerializationState(annotation_factories or {})
|
1223
1424
|
metadata_raw = json.dumps(
|
1224
1425
|
circuit.metadata, separators=(",", ":"), cls=metadata_serializer
|
1225
1426
|
).encode(common.ENCODE)
|
@@ -1269,6 +1470,7 @@ def write_circuit(
|
|
1269
1470
|
use_symengine,
|
1270
1471
|
version,
|
1271
1472
|
standalone_var_indices=standalone_var_indices,
|
1473
|
+
annotation_state=annotation_state,
|
1272
1474
|
)
|
1273
1475
|
|
1274
1476
|
with io.BytesIO() as custom_operations_buffer:
|
@@ -1287,12 +1489,33 @@ def write_circuit(
|
|
1287
1489
|
use_symengine,
|
1288
1490
|
version,
|
1289
1491
|
standalone_var_indices=standalone_var_indices,
|
1492
|
+
annotation_state=annotation_state,
|
1290
1493
|
)
|
1291
1494
|
)
|
1495
|
+
# We only write this out after we've done the annotations.
|
1496
|
+
custom_operations_payload = custom_operations_buffer.getvalue()
|
1292
1497
|
|
1293
|
-
|
1294
|
-
file_obj.write(
|
1498
|
+
if version >= 15:
|
1499
|
+
file_obj.write(
|
1500
|
+
struct.pack(formats.ANNOTATION_HEADER_STATIC_PACK, annotation_state.num_serializers)
|
1501
|
+
)
|
1502
|
+
for namespace, serializer in annotation_state.iter_serializers():
|
1503
|
+
namespace_bytes = namespace.encode("utf-8")
|
1504
|
+
serializer_state = serializer.dump_state()
|
1505
|
+
file_obj.write(
|
1506
|
+
struct.pack(
|
1507
|
+
formats.ANNOTATION_STATE_HEADER_PACK,
|
1508
|
+
len(namespace_bytes),
|
1509
|
+
len(serializer_state),
|
1510
|
+
)
|
1511
|
+
)
|
1512
|
+
file_obj.write(namespace_bytes)
|
1513
|
+
file_obj.write(serializer_state)
|
1514
|
+
elif annotation_state.num_serializers:
|
1515
|
+
raise UnsupportedFeatureForVersion(annotations, 15, version)
|
1295
1516
|
|
1517
|
+
file_obj.write(struct.pack(formats.CUSTOM_CIRCUIT_DEF_HEADER_PACK, len(custom_operations)))
|
1518
|
+
file_obj.write(custom_operations_payload)
|
1296
1519
|
file_obj.write(instruction_buffer.getvalue())
|
1297
1520
|
instruction_buffer.close()
|
1298
1521
|
|
@@ -1304,7 +1527,9 @@ def write_circuit(
|
|
1304
1527
|
_write_layout(file_obj, circuit)
|
1305
1528
|
|
1306
1529
|
|
1307
|
-
def read_circuit(
|
1530
|
+
def read_circuit(
|
1531
|
+
file_obj, version, metadata_deserializer=None, use_symengine=False, annotation_factories=None
|
1532
|
+
):
|
1308
1533
|
"""Read a single QuantumCircuit object from the file like object.
|
1309
1534
|
|
1310
1535
|
Args:
|
@@ -1322,6 +1547,8 @@ def read_circuit(file_obj, version, metadata_deserializer=None, use_symengine=Fa
|
|
1322
1547
|
supported in all platforms. Please check that your target platform is supported by
|
1323
1548
|
the symengine library before setting this option, as it will be required by qpy to
|
1324
1549
|
deserialize the payload.
|
1550
|
+
annotation_factories (dict): mapping of namespaces to factory functions for custom
|
1551
|
+
annotation deserializer objects.
|
1325
1552
|
Returns:
|
1326
1553
|
QuantumCircuit: The circuit object from the file.
|
1327
1554
|
|
@@ -1420,7 +1647,11 @@ def read_circuit(file_obj, version, metadata_deserializer=None, use_symengine=Fa
|
|
1420
1647
|
circ.add_uninitialized_var(declaration)
|
1421
1648
|
for stretch in var_segments[type_keys.ExprVarDeclaration.STRETCH_LOCAL]:
|
1422
1649
|
circ.add_stretch(stretch)
|
1423
|
-
|
1650
|
+
if version >= 15:
|
1651
|
+
annotation_state = _read_annotation_states(file_obj, annotation_factories or {})
|
1652
|
+
else:
|
1653
|
+
annotation_state = _AnnotationDeserializationState(annotation_factories or {})
|
1654
|
+
custom_operations = _read_custom_operations(file_obj, version, vectors, annotation_state)
|
1424
1655
|
for _instruction in range(num_instructions):
|
1425
1656
|
_read_instruction(
|
1426
1657
|
file_obj,
|
@@ -1431,16 +1662,17 @@ def read_circuit(file_obj, version, metadata_deserializer=None, use_symengine=Fa
|
|
1431
1662
|
vectors,
|
1432
1663
|
use_symengine,
|
1433
1664
|
standalone_var_indices,
|
1665
|
+
annotation_state=annotation_state,
|
1434
1666
|
)
|
1435
1667
|
|
1436
1668
|
# Consume calibrations, but don't use them since pulse gates are not supported as of Qiskit 2.0
|
1437
1669
|
if version >= 5:
|
1438
1670
|
_read_calibrations(file_obj, version, vectors, metadata_deserializer)
|
1439
1671
|
|
1440
|
-
for
|
1672
|
+
for vector, initialized_params in vectors.values():
|
1441
1673
|
if len(initialized_params) != len(vector):
|
1442
1674
|
warnings.warn(
|
1443
|
-
f"The ParameterVector: '{
|
1675
|
+
f"The ParameterVector: '{vector.name}' is not fully identical to its "
|
1444
1676
|
"pre-serialization state. Elements "
|
1445
1677
|
f"{', '.join([str(x) for x in set(range(len(vector))) - initialized_params])} "
|
1446
1678
|
"in the ParameterVector will be not equal to the pre-serialized ParameterVector "
|
@@ -15,6 +15,7 @@
|
|
15
15
|
import ast
|
16
16
|
|
17
17
|
from qiskit.qpy.exceptions import QpyError
|
18
|
+
from qiskit.utils.optionals import HAS_SYMPY
|
18
19
|
|
19
20
|
|
20
21
|
ALLOWED_CALLERS = {
|
@@ -113,6 +114,10 @@ class ParseSympyWalker(ast.NodeVisitor):
|
|
113
114
|
self.stack.append(obj)
|
114
115
|
|
115
116
|
|
117
|
+
@HAS_SYMPY.require_in_call(
|
118
|
+
"Sympy is required to parse parameter expressions encoded using sympy's "
|
119
|
+
"srepr in QPY format versions < 13"
|
120
|
+
)
|
116
121
|
def parse_sympy_repr(sympy_repr: str):
|
117
122
|
"""Parse a given sympy srepr into a symbolic expression object."""
|
118
123
|
tree = ast.parse(sympy_repr, mode="eval")
|