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.
Files changed (180) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +19 -1
  3. qiskit/_accelerate.abi3.so +0 -0
  4. qiskit/circuit/__init__.py +13 -21
  5. qiskit/circuit/_add_control.py +57 -31
  6. qiskit/circuit/_classical_resource_map.py +4 -0
  7. qiskit/circuit/annotation.py +404 -0
  8. qiskit/circuit/classical/expr/__init__.py +1 -1
  9. qiskit/circuit/classical/expr/expr.py +104 -446
  10. qiskit/circuit/classical/expr/visitors.py +6 -0
  11. qiskit/circuit/classical/types/types.py +7 -130
  12. qiskit/circuit/controlflow/box.py +32 -7
  13. qiskit/circuit/delay.py +11 -9
  14. qiskit/circuit/library/arithmetic/adders/adder.py +5 -5
  15. qiskit/circuit/library/arithmetic/multipliers/multiplier.py +3 -3
  16. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +7 -3
  17. qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +23 -15
  18. qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +22 -14
  19. qiskit/circuit/library/arithmetic/quadratic_form.py +6 -0
  20. qiskit/circuit/library/arithmetic/weighted_adder.py +43 -24
  21. qiskit/circuit/library/basis_change/qft.py +2 -2
  22. qiskit/circuit/library/blueprintcircuit.py +6 -0
  23. qiskit/circuit/library/boolean_logic/inner_product.py +2 -2
  24. qiskit/circuit/library/boolean_logic/quantum_and.py +2 -2
  25. qiskit/circuit/library/boolean_logic/quantum_or.py +5 -5
  26. qiskit/circuit/library/boolean_logic/quantum_xor.py +2 -2
  27. qiskit/circuit/library/data_preparation/_z_feature_map.py +2 -2
  28. qiskit/circuit/library/data_preparation/_zz_feature_map.py +2 -2
  29. qiskit/circuit/library/data_preparation/pauli_feature_map.py +2 -2
  30. qiskit/circuit/library/fourier_checking.py +2 -2
  31. qiskit/circuit/library/generalized_gates/diagonal.py +5 -1
  32. qiskit/circuit/library/generalized_gates/gms.py +5 -1
  33. qiskit/circuit/library/generalized_gates/linear_function.py +2 -2
  34. qiskit/circuit/library/generalized_gates/permutation.py +5 -1
  35. qiskit/circuit/library/generalized_gates/uc.py +1 -1
  36. qiskit/circuit/library/generalized_gates/unitary.py +21 -2
  37. qiskit/circuit/library/graph_state.py +2 -2
  38. qiskit/circuit/library/grover_operator.py +2 -2
  39. qiskit/circuit/library/hidden_linear_function.py +2 -2
  40. qiskit/circuit/library/iqp.py +2 -2
  41. qiskit/circuit/library/n_local/efficient_su2.py +2 -2
  42. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +4 -2
  43. qiskit/circuit/library/n_local/excitation_preserving.py +7 -9
  44. qiskit/circuit/library/n_local/n_local.py +4 -3
  45. qiskit/circuit/library/n_local/pauli_two_design.py +2 -2
  46. qiskit/circuit/library/n_local/real_amplitudes.py +2 -2
  47. qiskit/circuit/library/n_local/two_local.py +2 -2
  48. qiskit/circuit/library/overlap.py +2 -2
  49. qiskit/circuit/library/pauli_evolution.py +3 -2
  50. qiskit/circuit/library/phase_estimation.py +2 -2
  51. qiskit/circuit/library/standard_gates/dcx.py +11 -12
  52. qiskit/circuit/library/standard_gates/ecr.py +21 -24
  53. qiskit/circuit/library/standard_gates/equivalence_library.py +232 -96
  54. qiskit/circuit/library/standard_gates/global_phase.py +5 -6
  55. qiskit/circuit/library/standard_gates/h.py +22 -45
  56. qiskit/circuit/library/standard_gates/i.py +1 -1
  57. qiskit/circuit/library/standard_gates/iswap.py +13 -31
  58. qiskit/circuit/library/standard_gates/p.py +19 -26
  59. qiskit/circuit/library/standard_gates/r.py +11 -17
  60. qiskit/circuit/library/standard_gates/rx.py +21 -45
  61. qiskit/circuit/library/standard_gates/rxx.py +7 -22
  62. qiskit/circuit/library/standard_gates/ry.py +21 -39
  63. qiskit/circuit/library/standard_gates/ryy.py +13 -28
  64. qiskit/circuit/library/standard_gates/rz.py +18 -35
  65. qiskit/circuit/library/standard_gates/rzx.py +7 -22
  66. qiskit/circuit/library/standard_gates/rzz.py +7 -19
  67. qiskit/circuit/library/standard_gates/s.py +44 -39
  68. qiskit/circuit/library/standard_gates/swap.py +25 -38
  69. qiskit/circuit/library/standard_gates/sx.py +34 -41
  70. qiskit/circuit/library/standard_gates/t.py +18 -27
  71. qiskit/circuit/library/standard_gates/u.py +8 -24
  72. qiskit/circuit/library/standard_gates/u1.py +28 -52
  73. qiskit/circuit/library/standard_gates/u2.py +9 -9
  74. qiskit/circuit/library/standard_gates/u3.py +24 -40
  75. qiskit/circuit/library/standard_gates/x.py +190 -336
  76. qiskit/circuit/library/standard_gates/xx_minus_yy.py +12 -50
  77. qiskit/circuit/library/standard_gates/xx_plus_yy.py +13 -52
  78. qiskit/circuit/library/standard_gates/y.py +19 -23
  79. qiskit/circuit/library/standard_gates/z.py +31 -38
  80. qiskit/circuit/parameter.py +14 -5
  81. qiskit/circuit/parameterexpression.py +109 -75
  82. qiskit/circuit/quantumcircuit.py +168 -98
  83. qiskit/circuit/quantumcircuitdata.py +1 -0
  84. qiskit/circuit/random/__init__.py +37 -2
  85. qiskit/circuit/random/utils.py +445 -56
  86. qiskit/circuit/tools/pi_check.py +5 -13
  87. qiskit/compiler/transpiler.py +1 -1
  88. qiskit/converters/circuit_to_instruction.py +2 -2
  89. qiskit/dagcircuit/dagnode.py +8 -3
  90. qiskit/primitives/__init__.py +2 -2
  91. qiskit/primitives/base/base_estimator.py +2 -2
  92. qiskit/primitives/containers/data_bin.py +0 -3
  93. qiskit/primitives/containers/observables_array.py +192 -108
  94. qiskit/primitives/primitive_job.py +29 -10
  95. qiskit/providers/fake_provider/generic_backend_v2.py +2 -0
  96. qiskit/qasm3/__init__.py +106 -12
  97. qiskit/qasm3/ast.py +15 -1
  98. qiskit/qasm3/exporter.py +59 -36
  99. qiskit/qasm3/printer.py +12 -0
  100. qiskit/qpy/__init__.py +183 -7
  101. qiskit/qpy/binary_io/circuits.py +256 -24
  102. qiskit/qpy/binary_io/parse_sympy_repr.py +5 -0
  103. qiskit/qpy/binary_io/schedules.py +12 -32
  104. qiskit/qpy/binary_io/value.py +36 -18
  105. qiskit/qpy/common.py +11 -3
  106. qiskit/qpy/formats.py +17 -1
  107. qiskit/qpy/interface.py +52 -12
  108. qiskit/qpy/type_keys.py +7 -1
  109. qiskit/quantum_info/__init__.py +10 -0
  110. qiskit/quantum_info/operators/__init__.py +1 -0
  111. qiskit/quantum_info/operators/symplectic/__init__.py +1 -0
  112. qiskit/quantum_info/operators/symplectic/clifford_circuits.py +26 -0
  113. qiskit/quantum_info/operators/symplectic/pauli.py +2 -2
  114. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +1 -1
  115. qiskit/result/sampled_expval.py +3 -1
  116. qiskit/synthesis/__init__.py +10 -0
  117. qiskit/synthesis/arithmetic/__init__.py +1 -1
  118. qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
  119. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
  120. qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
  121. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
  122. qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
  123. qiskit/synthesis/evolution/lie_trotter.py +10 -7
  124. qiskit/synthesis/evolution/product_formula.py +10 -7
  125. qiskit/synthesis/evolution/qdrift.py +10 -7
  126. qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
  127. qiskit/synthesis/multi_controlled/__init__.py +4 -0
  128. qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
  129. qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
  130. qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
  131. qiskit/synthesis/unitary/qsd.py +80 -9
  132. qiskit/transpiler/__init__.py +19 -8
  133. qiskit/transpiler/instruction_durations.py +2 -20
  134. qiskit/transpiler/passes/__init__.py +4 -2
  135. qiskit/transpiler/passes/layout/dense_layout.py +26 -6
  136. qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
  137. qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
  138. qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
  139. qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
  140. qiskit/transpiler/passes/layout/vf2_utils.py +13 -1
  141. qiskit/transpiler/passes/optimization/__init__.py +1 -1
  142. qiskit/transpiler/passes/optimization/consolidate_blocks.py +6 -1
  143. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
  144. qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
  145. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
  146. qiskit/transpiler/passes/routing/sabre_swap.py +12 -2
  147. qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
  148. qiskit/transpiler/passes/scheduling/__init__.py +1 -1
  149. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  150. qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
  151. qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
  152. qiskit/transpiler/passes/synthesis/__init__.py +1 -0
  153. qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
  154. qiskit/transpiler/passes/synthesis/hls_plugins.py +472 -92
  155. qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +27 -22
  156. qiskit/transpiler/passmanager_config.py +3 -0
  157. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +149 -28
  158. qiskit/transpiler/preset_passmanagers/common.py +101 -0
  159. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +6 -0
  160. qiskit/transpiler/preset_passmanagers/level3.py +2 -2
  161. qiskit/utils/optionals.py +6 -5
  162. qiskit/visualization/circuit/_utils.py +5 -3
  163. qiskit/visualization/circuit/latex.py +9 -2
  164. qiskit/visualization/circuit/matplotlib.py +26 -4
  165. qiskit/visualization/circuit/qcstyle.py +9 -157
  166. qiskit/visualization/dag/__init__.py +13 -0
  167. qiskit/visualization/dag/dagstyle.py +103 -0
  168. qiskit/visualization/dag/styles/__init__.py +13 -0
  169. qiskit/visualization/dag/styles/color.json +10 -0
  170. qiskit/visualization/dag/styles/plain.json +5 -0
  171. qiskit/visualization/dag_visualization.py +169 -98
  172. qiskit/visualization/style.py +223 -0
  173. {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.dist-info}/METADATA +14 -13
  174. {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.dist-info}/RECORD +178 -169
  175. {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.dist-info}/WHEEL +1 -1
  176. {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.dist-info}/entry_points.txt +6 -0
  177. qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
  178. qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
  179. {qiskit-2.0.1.dist-info → qiskit-2.1.0rc1.dist-info}/licenses/LICENSE.txt +0 -0
  180. {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`Expr` instances define a boolean :attr:`~Expr.const` attribute, which indicates
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