qiskit 2.0.1__cp39-abi3-macosx_11_0_arm64.whl → 2.1.0rc1__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 +13 -21
- qiskit/circuit/_add_control.py +57 -31
- qiskit/circuit/_classical_resource_map.py +4 -0
- qiskit/circuit/annotation.py +404 -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 +5 -5
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +3 -3
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +7 -3
- 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 +5 -5
- 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 +4 -2
- 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 +168 -98
- 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 +183 -7
- 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/quantum_info/operators/symplectic/sparse_pauli_op.py +1 -1
- 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 +19 -8
- qiskit/transpiler/instruction_durations.py +2 -20
- qiskit/transpiler/passes/__init__.py +4 -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 +13 -1
- qiskit/transpiler/passes/optimization/__init__.py +1 -1
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +6 -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 +12 -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 +472 -92
- 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/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.1.dist-info → qiskit-2.1.0rc1.dist-info}/METADATA +14 -13
- {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.dist-info}/RECORD +178 -169
- {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.dist-info}/WHEEL +1 -1
- {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.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.1.dist-info → qiskit-2.1.0rc1.dist-info}/licenses/LICENSE.txt +0 -0
- {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,404 @@
|
|
1
|
+
# This code is part of Qiskit.
|
2
|
+
#
|
3
|
+
# (C) Copyright IBM 2025.
|
4
|
+
#
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
8
|
+
#
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
11
|
+
# that they have been altered from the originals.
|
12
|
+
|
13
|
+
"""
|
14
|
+
======================================================
|
15
|
+
Circuit annotations (:mod:`qiskit.circuit.annotation`)
|
16
|
+
======================================================
|
17
|
+
|
18
|
+
.. currentmodule:: qiskit.circuit.annotation
|
19
|
+
|
20
|
+
This module contains the infrastructure for working with custom circuit annotations.
|
21
|
+
|
22
|
+
The main user-facing class is the base class :class:`qiskit.circuit.Annotation`, which is also
|
23
|
+
re-exported from this module.
|
24
|
+
|
25
|
+
.. _circuit-annotation-subclassing:
|
26
|
+
|
27
|
+
Custom annotation subclasses
|
28
|
+
============================
|
29
|
+
|
30
|
+
The :class:`.Annotation` class is intended to be subclassed. Subclasses must set their
|
31
|
+
:attr:`~.Annotation.namespace` field. This can be specific to an instance, or static for an entire
|
32
|
+
subclass. The namespace is used as part of the dispatch mechanism, as described in
|
33
|
+
:ref:`circuit-annotation-namespacing`.
|
34
|
+
|
35
|
+
Circuit equality checks also compare annotations on objects in an order-dependent manner. You will
|
36
|
+
likely want to implement the :meth:`~object.__eq__` magic method on any subclasses.
|
37
|
+
|
38
|
+
If you intend your annotation to be able to be serialized via :ref:`QPY <qiskit-qpy>` or :ref:`
|
39
|
+
OpenQASM 3 <qiskit-qasm3>`, you must provide separate implementations of the serialization and
|
40
|
+
deserialization methods as discussed in :ref:`circuit-annotation-serialization`.
|
41
|
+
|
42
|
+
.. _circuit-annotation-namespacing:
|
43
|
+
|
44
|
+
Namespacing
|
45
|
+
-----------
|
46
|
+
|
47
|
+
The "namespace" of an annotation is used as a look-up key when any consumer is deciding which
|
48
|
+
handler to invoke. This includes in QPY and OpenQASM 3 serialization contexts, but in general,
|
49
|
+
transpiler passes will also look at annotations' namespaces to determine if they are relevant, and
|
50
|
+
so on.
|
51
|
+
|
52
|
+
This can be standard Python identifier (e.g. ``my_namespace``), or a dot-separated list of
|
53
|
+
identifiers (e.g. ``my_namespace.subnamespace``). The namespace is used by all consumers of
|
54
|
+
annotations to determine what handler should be invoked.
|
55
|
+
|
56
|
+
A stand-alone function allows iterating through namespaces and parent namespaces in priority order
|
57
|
+
from most specific to least specific.
|
58
|
+
|
59
|
+
.. autofunction:: iter_namespaces
|
60
|
+
|
61
|
+
|
62
|
+
.. _circuit-annotation-serialization:
|
63
|
+
|
64
|
+
Serialization and deserialization
|
65
|
+
---------------------------------
|
66
|
+
|
67
|
+
Annotations represent completely custom data, that may persist after compilation. This may include
|
68
|
+
data that should be serialized for later consumption, such as additional data that is interpreted by
|
69
|
+
a backend-compiler. Qiskit's native binary QPY format (see :mod:`qiskit.qpy`) supports the concept
|
70
|
+
of arbitrary annotations in its payloads from version 15 onwards. In OpenQASM 3 (see
|
71
|
+
:mod:`qiskit.qasm3`), annotations are a core language feature, and Qiskit's import/export support
|
72
|
+
for OpenQASM 3 includes serialization of annotations.
|
73
|
+
|
74
|
+
However, since annotations are generally custom subclasses and unknown to Qiskit, we cannot have
|
75
|
+
built-in support for serialization. On the deserialization front, Qiskit will not, in general, have
|
76
|
+
an existing :class:`~.Annotation` object to call deserialization methods from. It is also expected
|
77
|
+
that annotations may relate to some unknown-to-Qiskit shared state within a given circuit context.
|
78
|
+
|
79
|
+
For all of these reasons, serialization and deserialization of annotations is handled by custom
|
80
|
+
objects, which must be passed at the interface points of the relevant serialization functions. For
|
81
|
+
example in QPY, the ``annotation_factories`` argument in :func:`.qpy.dump` and :func:`.qpy.load` are
|
82
|
+
used to pass serializers.
|
83
|
+
|
84
|
+
.. autoclass:: QPYSerializer
|
85
|
+
.. autoclass:: QPYFromOpenQASM3Serializer
|
86
|
+
.. autoclass:: OpenQASM3Serializer
|
87
|
+
"""
|
88
|
+
|
89
|
+
from __future__ import annotations
|
90
|
+
|
91
|
+
import abc
|
92
|
+
from typing import Literal, Iterator
|
93
|
+
|
94
|
+
from qiskit._accelerate.circuit import Annotation
|
95
|
+
|
96
|
+
|
97
|
+
__all__ = [
|
98
|
+
"Annotation", # Also exported in `qiskit.circuit`, but for convenience is here too.
|
99
|
+
"QPYSerializer",
|
100
|
+
"OpenQASM3Serializer",
|
101
|
+
"QPYFromOpenQASM3Serializer",
|
102
|
+
"iter_namespaces",
|
103
|
+
]
|
104
|
+
|
105
|
+
|
106
|
+
def iter_namespaces(namespace: str) -> Iterator[str]:
|
107
|
+
"""An iterator over all namespaces that can be used to lookup the given namespace.
|
108
|
+
|
109
|
+
This includes the namespace and all parents, including the root empty-string namespace.
|
110
|
+
|
111
|
+
Examples:
|
112
|
+
|
113
|
+
.. code-block:: python
|
114
|
+
|
115
|
+
from qiskit.circuit.annotation import iter_namespaces
|
116
|
+
assert list(iter_namespaces("hello.world")) == ["hello.world", "hello", ""]
|
117
|
+
"""
|
118
|
+
while namespace:
|
119
|
+
yield namespace
|
120
|
+
split = namespace.rsplit(".", 1)
|
121
|
+
if len(split) == 1:
|
122
|
+
break
|
123
|
+
namespace = split[0]
|
124
|
+
yield ""
|
125
|
+
|
126
|
+
|
127
|
+
class QPYSerializer(abc.ABC):
|
128
|
+
"""The interface for serializers and deserializers of :class:`.Annotation` objects to QPY.
|
129
|
+
|
130
|
+
For more information on QPY, see :mod:`qiskit.qpy`.
|
131
|
+
|
132
|
+
This interface-definition class is designed to be subclassed. The individual methods describe
|
133
|
+
their contracts, and how they will be called.
|
134
|
+
|
135
|
+
During QPY serialization and deserialization, the main QPY logic will call a factory function to
|
136
|
+
create instances of subclasses of this class. The return value from a given factory function
|
137
|
+
will be used in *either* a serialization or deserialization context, but not both.
|
138
|
+
|
139
|
+
The structure of calls during serialization of a single circuit is:
|
140
|
+
|
141
|
+
1. many calls to :meth:`dump_annotation`, which will all share the same ``namespace`` argument,
|
142
|
+
which will always be a (non-strict) prefix of all the :class:`.Annotation` objects given.
|
143
|
+
2. one call to :meth:`dump_state`.
|
144
|
+
|
145
|
+
The general structure of calls during deserialization of a single circuit out of a QPY payload
|
146
|
+
is:
|
147
|
+
|
148
|
+
1. one call to :meth:`load_state`, passing a ``namespace`` (with the same non-strict prefixing
|
149
|
+
behavior as the "serializing" form).
|
150
|
+
2. many calls to :meth:`load_annotation`, corresponding to annotations serialized under that
|
151
|
+
namespace-prefix lookup.
|
152
|
+
|
153
|
+
When subclassing this, recall that QPY is intended to have strict backwards-compatibility
|
154
|
+
guarantees, and it is strongly recommended that annotation-serialisation subclasses maintain
|
155
|
+
this. In particular, it is suggested that any non-trivial serializer includes "version"
|
156
|
+
information for the serializer in its total "state" (see :meth:`dump_state`), and the
|
157
|
+
deserialization should make every effort to support backwards compatibility with previous
|
158
|
+
versions of the same serializer.
|
159
|
+
"""
|
160
|
+
|
161
|
+
@abc.abstractmethod
|
162
|
+
def dump_annotation(
|
163
|
+
self, namespace: str, annotation: Annotation
|
164
|
+
) -> bytes | Literal[NotImplemented]:
|
165
|
+
"""Serialize an annotation to a bytestream.
|
166
|
+
|
167
|
+
This method may mutate the serializer's internal state (the object that will be serialized
|
168
|
+
by :meth:`dump_state`).
|
169
|
+
|
170
|
+
The ``namespace`` argument is the resolved key used to lookup this serializer. It may not
|
171
|
+
be identical to the :attr:`.Annotation.namespace` field of the ``annotation`` argument; it
|
172
|
+
might be an ancestor, up to and including the empty string (the root namespace). All calls
|
173
|
+
to an instance of this class, as retrieved by a factory function in :func:`.qpy.dump` will
|
174
|
+
be made using the same ``namespace``.
|
175
|
+
|
176
|
+
The method can return :data:`NotImplemented` if the serializer cannot serialize a particular
|
177
|
+
annotation. In this case, the QPY logic will attempt to use a serializer registered for
|
178
|
+
the parent namespaces.
|
179
|
+
|
180
|
+
This method is the mirror of :meth:`load_annotation`.
|
181
|
+
|
182
|
+
Args:
|
183
|
+
namespace: the namespace that this serializer was accessed under. This may be an
|
184
|
+
ancestor of the annotation.
|
185
|
+
annotation: the object to serialize to a bytestream.
|
186
|
+
|
187
|
+
Returns:
|
188
|
+
Either the serialized form of the annotation (optionally after mutating the
|
189
|
+
serialization state of this class), or :data:`NotImplemented` if the annotation cannot
|
190
|
+
be handled.
|
191
|
+
"""
|
192
|
+
|
193
|
+
@abc.abstractmethod
|
194
|
+
def load_annotation(self, payload: bytes) -> Annotation:
|
195
|
+
"""Load an annotation from a view of memory.
|
196
|
+
|
197
|
+
A subclass can assume that :meth:`load_state` will have been called exactly once before
|
198
|
+
this method is called, and all subsequent calls to this method will be for payloads
|
199
|
+
corresponding to annotations serialized under that parent namespace.
|
200
|
+
|
201
|
+
If a user configures QPY correctly, instances of this class will only be asked to
|
202
|
+
deserialize payloads that the corresponding :meth:`dump_annotation` can successfully handle
|
203
|
+
(i.e. return a payload, not :data:`NotImplemented`). Subclasses may raise an arbitrary
|
204
|
+
exception if this is not the case and this will abort the QPY load operation. Such a
|
205
|
+
situation would require that the user supplied a different serializer configuration on the
|
206
|
+
two sides of the QPY load and dump.
|
207
|
+
|
208
|
+
This method is the mirror of :meth:`dump_annotation`.
|
209
|
+
|
210
|
+
Args:
|
211
|
+
payload: the bytes to deserialized into an annotation.
|
212
|
+
|
213
|
+
Returns:
|
214
|
+
The deserialized annotation.
|
215
|
+
"""
|
216
|
+
|
217
|
+
def dump_state(self) -> bytes:
|
218
|
+
"""Serialize a state object for the given serializer.
|
219
|
+
|
220
|
+
When in a QPY dumping context, this method will be called exactly once, after all calls to
|
221
|
+
:meth:`dump_annotation`.
|
222
|
+
|
223
|
+
The default state is the empty bytestring; if your serializer is stateless, you do not need
|
224
|
+
to override this method.
|
225
|
+
|
226
|
+
This method is the mirror of :meth:`load_state`.
|
227
|
+
"""
|
228
|
+
return b""
|
229
|
+
|
230
|
+
def load_state(self, namespace: str, payload: bytes): # pylint: disable=unused-argument
|
231
|
+
"""Initialize the state of the deserializer for a given ``namespace`` key.
|
232
|
+
|
233
|
+
When in a QPY loading context, this method will be called exactly once, before all calls to
|
234
|
+
:meth:`load_annotation`. The ``namespace`` will be the same namespace that was passed to
|
235
|
+
all calls to :meth:`dump_annotation` in the dumping context; that is, a (non-strict) prefix
|
236
|
+
of the namespaces of all the :class:`.Annotation` objects its counterpart was asked to
|
237
|
+
serialize. For example, if the QPY dump was configured with::
|
238
|
+
|
239
|
+
from qiskit import qpy
|
240
|
+
from qiskit.circuit import annotation, Annotation
|
241
|
+
|
242
|
+
class MyA(Annotation):
|
243
|
+
namespace = "my.a"
|
244
|
+
class MyB(Annotation):
|
245
|
+
namespace = "my.b"
|
246
|
+
|
247
|
+
class MyQPYSerializer(annotation.QPYSerializer):
|
248
|
+
...
|
249
|
+
|
250
|
+
qpy.dump(..., annotation_factories={"my": MyQPYSerializer})
|
251
|
+
|
252
|
+
then during the corresponding call to :func:`.qpy.load`, this method in ``MyQPYSerializer``
|
253
|
+
will be called with ``"my"``, even though the annotations serialized had namespaces ``my.a``
|
254
|
+
and ``my.b``. It is up to individual dumpers to do any sub-namespace handling they choose.
|
255
|
+
|
256
|
+
The default implementation is a no-op; if you have not overridden :meth:`dump_state`, you do
|
257
|
+
not need to override this method.
|
258
|
+
|
259
|
+
This method is the mirror of :meth:`dump_state`.
|
260
|
+
|
261
|
+
Args:
|
262
|
+
namespace: the namespace key that the corresponding dump was resolved under.
|
263
|
+
payload: the state payload that was dumped by the corresponding call to
|
264
|
+
:meth:`dump_state`.
|
265
|
+
"""
|
266
|
+
pass
|
267
|
+
|
268
|
+
|
269
|
+
class OpenQASM3Serializer(abc.ABC):
|
270
|
+
"""The interface for serializers and deserializers of :class:`.Annotation` objects to
|
271
|
+
OpenQASM 3.
|
272
|
+
|
273
|
+
For more information on OpenQASM 3 support in Qiskit, see :mod:`qiskit.qasm3`.
|
274
|
+
|
275
|
+
This interface-definition class is designed to be subclassed. OpenQASM 3 annotations are
|
276
|
+
stateless within a program, therefore a subclass must not track state.
|
277
|
+
"""
|
278
|
+
|
279
|
+
@abc.abstractmethod
|
280
|
+
def dump(self, annotation: Annotation) -> str | Literal[NotImplemented]:
|
281
|
+
"""Serialize the paylaod of an annotation to a single line of UTF-8 text.
|
282
|
+
|
283
|
+
The output of this method should not include the annotation's
|
284
|
+
:attr:`~.Annotation.namespace` attribute; this is handled automatically by the OpenQASM 3
|
285
|
+
exporter.
|
286
|
+
|
287
|
+
The serialized form must not contain newline characters; it must be valid as the "arbitrary"
|
288
|
+
component of the annotation as defined by OpenQASM 3. If there is no data required, the
|
289
|
+
method should return the empty string. If this serializer cannot handle the particular
|
290
|
+
annotation, it should return :data:`NotImplemented`.
|
291
|
+
|
292
|
+
Args:
|
293
|
+
annotation: the annotation object to serialize.
|
294
|
+
|
295
|
+
Returns:
|
296
|
+
the serialized annotation (without the namespace component), or the sentinel
|
297
|
+
:data:`NotImplemented` if it cannot be handled by this object.
|
298
|
+
"""
|
299
|
+
|
300
|
+
@abc.abstractmethod
|
301
|
+
def load(self, namespace: str, payload: str) -> Annotation | Literal[NotImplemented]:
|
302
|
+
"""Load an annotation, if possible, from an OpenQASM 3 program.
|
303
|
+
|
304
|
+
The two arguments will be the two components of an annotation, as defined by the OpenQASM 3
|
305
|
+
specification. The method should return :data:`NotImplemented` if it cannot handle the
|
306
|
+
annotation.
|
307
|
+
|
308
|
+
Args:
|
309
|
+
namespace: the OpenQASM 3 "namespace" of the annotation.
|
310
|
+
payload: the rest of the payload for the annotation. This is arbitrary and free-form,
|
311
|
+
and in general should have been serialized by a call to :meth:`dump`.
|
312
|
+
|
313
|
+
Returns:
|
314
|
+
the created :class:`.Annotation` object, whose :attr:`.Annotation.namespace` attribute
|
315
|
+
should be identical to the incoming ``namespace`` argument. If this class cannot handle
|
316
|
+
the annotation, it can also return :data:`NotImplemented`.
|
317
|
+
"""
|
318
|
+
|
319
|
+
def as_qpy(self) -> QPYFromOpenQASM3Serializer:
|
320
|
+
"""Derive a serializer/deserializer for QPY from this OpenQASM 3 variant.
|
321
|
+
|
322
|
+
OpenQASM 3 serialization and deserialization is intended to be stateless and return single
|
323
|
+
lines of UTF-8 encoded text. This is a subset of the allowable serializations for QPY."""
|
324
|
+
return QPYFromOpenQASM3Serializer(self)
|
325
|
+
|
326
|
+
|
327
|
+
class QPYFromOpenQASM3Serializer(QPYSerializer):
|
328
|
+
"""An adaptor that converts a :class:`OpenQASM3Serializer` into a :class:`QPYSerializer`.
|
329
|
+
|
330
|
+
This works because OpenQASM 3 annotation serializers are required to be stateless and return
|
331
|
+
UTF-8-encoded single lines of text, which is a subset of what QPY permits.
|
332
|
+
|
333
|
+
Typically you create one of these using the :meth:`~OpenQASM3Serializer.as_qpy` method
|
334
|
+
of an OpenQASM 3 annotation serializer.
|
335
|
+
|
336
|
+
Examples:
|
337
|
+
|
338
|
+
Instances of this class can be called like a zero-argument function and return themselves. This
|
339
|
+
lets you use them directly as a factory function to the QPY entry points, such as:
|
340
|
+
|
341
|
+
.. code-block:: python
|
342
|
+
|
343
|
+
import io
|
344
|
+
from qiskit.circuit import OpenQASM3Serializer, Annotation
|
345
|
+
from qiskit import qpy
|
346
|
+
|
347
|
+
class MyAnnotation(Annotation):
|
348
|
+
namespace = "my_namespace"
|
349
|
+
|
350
|
+
class MySerializer(OpenQASM3Serializer):
|
351
|
+
def dump(self, annotation):
|
352
|
+
if not isinstance(annotation, MyAnnotation):
|
353
|
+
return NotImplemented
|
354
|
+
return ""
|
355
|
+
|
356
|
+
def load(self, namespace, payload):
|
357
|
+
assert namespace == "my_namespace"
|
358
|
+
assert payload == ""
|
359
|
+
return MyAnnotation()
|
360
|
+
|
361
|
+
qc = QuantumCircuit(2)
|
362
|
+
with qc.box(annotations=[MyAnnotation()]):
|
363
|
+
qc.cx(0, 1)
|
364
|
+
|
365
|
+
with io.BytesIO() as fptr:
|
366
|
+
qpy.dump(fptr, qc, annotation_serializers = {"my_namespace": MySerializer().as_qpy()})
|
367
|
+
|
368
|
+
This is safe, without returning separate instances, because the base OpenQASM 3 serializers are
|
369
|
+
necessarily stateless.
|
370
|
+
"""
|
371
|
+
|
372
|
+
def __init__(self, inner: OpenQASM3Serializer):
|
373
|
+
"""
|
374
|
+
Args:
|
375
|
+
inner: the OpenQASM 3 serializer that this is derived from.
|
376
|
+
"""
|
377
|
+
self.inner = inner
|
378
|
+
|
379
|
+
def dump_annotation(self, namespace, annotation):
|
380
|
+
qasm3 = self.inner.dump(annotation)
|
381
|
+
if qasm3 is NotImplemented:
|
382
|
+
return NotImplemented
|
383
|
+
return (
|
384
|
+
# For OpenQASM 3 serialisation, we need the exact namespace the annotation claims.
|
385
|
+
annotation.namespace.encode("utf-8")
|
386
|
+
+ b"\x00"
|
387
|
+
+ qasm3.encode("utf-8")
|
388
|
+
)
|
389
|
+
|
390
|
+
def load_annotation(self, payload):
|
391
|
+
namespace, payload = payload.split(b"\x00", maxsplit=1)
|
392
|
+
out = self.inner.load(namespace.decode("utf-8"), payload.decode("utf-8"))
|
393
|
+
if out is NotImplemented:
|
394
|
+
raise ValueError(
|
395
|
+
"asked to deserialize an object the provided OpenQASM deserializer cannot handle"
|
396
|
+
)
|
397
|
+
return out
|
398
|
+
|
399
|
+
def __call__(self) -> QPYFromOpenQASM3Serializer:
|
400
|
+
# Our internal object is stateless because it's an OpenQASM 3 exporter (which is a stateless
|
401
|
+
# format). Defining this method allows an instance of ourself to be used as a factory
|
402
|
+
# function, simplifying the interface for creating a QPY serializer from an OpenQASM 3 one,
|
403
|
+
# and attaching this to the class means that pickling would "just work".
|
404
|
+
return self
|
@@ -39,7 +39,7 @@ The expression system is based on tree representation. All nodes in the tree ar
|
|
39
39
|
|
40
40
|
These objects are mutable and should not be reused in a different location without a copy.
|
41
41
|
|
42
|
-
All :class
|
42
|
+
All :class:`Expr` instances define a boolean :attr:`~Expr.const` attribute, which indicates
|
43
43
|
whether the expression can be evaluated at compile time. Most expression classes infer this
|
44
44
|
during construction based on the const-ness of their operands.
|
45
45
|
|