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.
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 +104 -20
  5. qiskit/circuit/_add_control.py +57 -31
  6. qiskit/circuit/_classical_resource_map.py +4 -0
  7. qiskit/circuit/annotation.py +504 -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 +4 -4
  15. qiskit/circuit/library/arithmetic/multipliers/multiplier.py +2 -2
  16. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +8 -4
  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 +3 -3
  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 +1 -1
  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 +172 -99
  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 +182 -6
  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/result/sampled_expval.py +3 -1
  115. qiskit/synthesis/__init__.py +10 -0
  116. qiskit/synthesis/arithmetic/__init__.py +1 -1
  117. qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
  118. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
  119. qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
  120. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
  121. qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
  122. qiskit/synthesis/evolution/lie_trotter.py +10 -7
  123. qiskit/synthesis/evolution/product_formula.py +10 -7
  124. qiskit/synthesis/evolution/qdrift.py +10 -7
  125. qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
  126. qiskit/synthesis/multi_controlled/__init__.py +4 -0
  127. qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
  128. qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
  129. qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
  130. qiskit/synthesis/unitary/qsd.py +80 -9
  131. qiskit/transpiler/__init__.py +10 -3
  132. qiskit/transpiler/instruction_durations.py +2 -20
  133. qiskit/transpiler/passes/__init__.py +5 -2
  134. qiskit/transpiler/passes/layout/dense_layout.py +26 -6
  135. qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
  136. qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
  137. qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
  138. qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
  139. qiskit/transpiler/passes/layout/vf2_utils.py +10 -0
  140. qiskit/transpiler/passes/optimization/__init__.py +1 -1
  141. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
  142. qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
  143. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
  144. qiskit/transpiler/passes/routing/sabre_swap.py +4 -2
  145. qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
  146. qiskit/transpiler/passes/scheduling/__init__.py +1 -1
  147. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  148. qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
  149. qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
  150. qiskit/transpiler/passes/synthesis/__init__.py +1 -0
  151. qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
  152. qiskit/transpiler/passes/synthesis/hls_plugins.py +494 -93
  153. qiskit/transpiler/passes/synthesis/plugin.py +4 -0
  154. qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +27 -22
  155. qiskit/transpiler/passmanager_config.py +3 -0
  156. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +149 -28
  157. qiskit/transpiler/preset_passmanagers/common.py +101 -0
  158. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +6 -0
  159. qiskit/transpiler/preset_passmanagers/level3.py +2 -2
  160. qiskit/transpiler/target.py +15 -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.3.dist-info → qiskit-2.1.0.dist-info}/METADATA +7 -6
  174. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/RECORD +178 -169
  175. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/entry_points.txt +6 -0
  176. qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
  177. qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
  178. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/WHEEL +0 -0
  179. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/licenses/LICENSE.txt +0 -0
  180. {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/top_level.txt +0 -0
@@ -18,12 +18,10 @@ The purpose of the `_read` and `_load` methods below is just to advance
18
18
  the file handle while consuming pulse data."""
19
19
  import json
20
20
  import struct
21
- import zlib
22
21
 
23
22
  from io import BytesIO
24
23
 
25
24
  import numpy as np
26
- import symengine as sym
27
25
 
28
26
  from qiskit.exceptions import QiskitError
29
27
  from qiskit.qpy import formats, common, type_keys
@@ -87,20 +85,6 @@ def _read_discriminator(file_obj, version) -> None:
87
85
  value.read_value(file_obj, version, {}) # read name
88
86
 
89
87
 
90
- def _loads_symbolic_expr(expr_bytes, use_symengine=False):
91
- if expr_bytes == b"":
92
- return None
93
- expr_bytes = zlib.decompress(expr_bytes)
94
- if use_symengine:
95
- return common.load_symengine_payload(expr_bytes)
96
- else:
97
- from sympy import parse_expr
98
-
99
- expr_txt = expr_bytes.decode(common.ENCODE)
100
- expr = parse_expr(expr_txt)
101
- return sym.sympify(expr)
102
-
103
-
104
88
  def _read_symbolic_pulse(file_obj, version) -> None:
105
89
  make = formats.SYMBOLIC_PULSE._make
106
90
  pack = formats.SYMBOLIC_PULSE_PACK
@@ -113,11 +97,9 @@ def _read_symbolic_pulse(file_obj, version) -> None:
113
97
  )
114
98
  )
115
99
  pulse_type = file_obj.read(header.type_size).decode(common.ENCODE)
116
- _loads_symbolic_expr(file_obj.read(header.envelope_size)) # read envelope
117
- _loads_symbolic_expr(file_obj.read(header.constraints_size)) # read constraints
118
- _loads_symbolic_expr(
119
- file_obj.read(header.valid_amp_conditions_size)
120
- ) # read valid amp conditions
100
+ file_obj.read(header.envelope_size) # read envelope
101
+ file_obj.read(header.constraints_size) # read constraints
102
+ file_obj.read(header.valid_amp_conditions_size) # read valid amp conditions
121
103
  # read parameters
122
104
  common.read_mapping(
123
105
  file_obj,
@@ -146,7 +128,7 @@ def _read_symbolic_pulse(file_obj, version) -> None:
146
128
  raise NotImplementedError(f"Unknown class '{class_name}'")
147
129
 
148
130
 
149
- def _read_symbolic_pulse_v6(file_obj, version, use_symengine) -> None:
131
+ def _read_symbolic_pulse_v6(file_obj, version) -> None:
150
132
  make = formats.SYMBOLIC_PULSE_V2._make
151
133
  pack = formats.SYMBOLIC_PULSE_PACK_V2
152
134
  size = formats.SYMBOLIC_PULSE_SIZE_V2
@@ -159,11 +141,9 @@ def _read_symbolic_pulse_v6(file_obj, version, use_symengine) -> None:
159
141
  )
160
142
  class_name = file_obj.read(header.class_name_size).decode(common.ENCODE)
161
143
  file_obj.read(header.type_size).decode(common.ENCODE) # read pulse type
162
- _loads_symbolic_expr(file_obj.read(header.envelope_size), use_symengine) # read envelope
163
- _loads_symbolic_expr(file_obj.read(header.constraints_size), use_symengine) # read constraints
164
- _loads_symbolic_expr(
165
- file_obj.read(header.valid_amp_conditions_size), use_symengine
166
- ) # read valid_amp_conditions
144
+ file_obj.read(header.envelope_size) # read envelope
145
+ file_obj.read(header.constraints_size) # read constraints
146
+ file_obj.read(header.valid_amp_conditions_size) # read valid_amp_conditions
167
147
  # read parameters
168
148
  common.read_mapping(
169
149
  file_obj,
@@ -191,16 +171,14 @@ def _read_alignment_context(file_obj, version) -> None:
191
171
 
192
172
 
193
173
  # pylint: disable=too-many-return-statements
194
- def _loads_operand(type_key, data_bytes, version, use_symengine):
174
+ def _loads_operand(type_key, data_bytes, version):
195
175
  if type_key == type_keys.ScheduleOperand.WAVEFORM:
196
176
  return common.data_from_binary(data_bytes, _read_waveform, version=version)
197
177
  if type_key == type_keys.ScheduleOperand.SYMBOLIC_PULSE:
198
178
  if version < 6:
199
179
  return common.data_from_binary(data_bytes, _read_symbolic_pulse, version=version)
200
180
  else:
201
- return common.data_from_binary(
202
- data_bytes, _read_symbolic_pulse_v6, version=version, use_symengine=use_symengine
203
- )
181
+ return common.data_from_binary(data_bytes, _read_symbolic_pulse_v6, version=version)
204
182
  if type_key == type_keys.ScheduleOperand.CHANNEL:
205
183
  return common.data_from_binary(data_bytes, _read_channel, version=version)
206
184
  if type_key == type_keys.ScheduleOperand.OPERAND_STR:
@@ -229,7 +207,9 @@ def _read_element(file_obj, version, metadata_deserializer, use_symengine) -> No
229
207
 
230
208
  # read operands
231
209
  common.read_sequence(
232
- file_obj, deserializer=_loads_operand, version=version, use_symengine=use_symengine
210
+ file_obj,
211
+ deserializer=_loads_operand,
212
+ version=version,
233
213
  )
234
214
  # read name
235
215
  value.read_value(file_obj, version, {})
@@ -20,8 +20,6 @@ import struct
20
20
  import uuid
21
21
 
22
22
  import numpy as np
23
- import symengine
24
-
25
23
 
26
24
  from qiskit.circuit import CASE_DEFAULT, Clbit, ClassicalRegister, Duration
27
25
  from qiskit.circuit.classical import expr, types
@@ -124,7 +122,10 @@ def _encode_replay_entry(inst, file_obj, version, r_side=False):
124
122
 
125
123
  def _encode_replay_subs(subs, file_obj, version):
126
124
  with io.BytesIO() as mapping_buf:
127
- subs_dict = {k.name: v for k, v in subs.binds.items()}
125
+ if version < 15:
126
+ subs_dict = {k.name: v for k, v in subs.binds.items()}
127
+ else:
128
+ subs_dict = {k.uuid.bytes: v for k, v in subs.binds.items()}
128
129
  common.write_mapping(
129
130
  mapping_buf, mapping=subs_dict, serializer=dumps_value, version=version
130
131
  )
@@ -459,14 +460,21 @@ def _read_parameter_vec(file_obj, vectors):
459
460
  file_obj.read(formats.PARAMETER_VECTOR_ELEMENT_SIZE),
460
461
  ),
461
462
  )
462
- param_uuid = uuid.UUID(bytes=data.uuid)
463
+ # Starting in version 15, the parameter vector root uuid
464
+ # is used as a key instead of the parameter name.
465
+ root_uuid_int = uuid.UUID(bytes=data.uuid).int - data.index
466
+ root_uuid = uuid.UUID(int=root_uuid_int)
463
467
  name = file_obj.read(data.vector_name_size).decode(common.ENCODE)
464
- if name not in vectors:
465
- vectors[name] = (ParameterVector(name, data.vector_size), set())
466
- vector = vectors[name][0]
467
- if vector[data.index].uuid != param_uuid:
468
- vectors[name][1].add(data.index)
469
- vector._params[data.index] = ParameterVectorElement(vector, data.index, uuid=param_uuid)
468
+
469
+ if root_uuid not in vectors:
470
+ vectors[root_uuid] = (ParameterVector(name, data.vector_size), set())
471
+ vector = vectors[root_uuid][0]
472
+
473
+ if vector[data.index].uuid != root_uuid:
474
+ vectors[root_uuid][1].add(data.index)
475
+ vector._params[data.index] = ParameterVectorElement(
476
+ vector, data.index, uuid=uuid.UUID(int=root_uuid_int + data.index)
477
+ )
470
478
  return vector[data.index]
471
479
 
472
480
 
@@ -476,7 +484,7 @@ def _read_parameter_expression(file_obj):
476
484
  )
477
485
 
478
486
  sympy_str = file_obj.read(data.expr_size).decode(common.ENCODE)
479
- expr_ = symengine.sympify(parse_sympy_repr(sympy_str))
487
+ expr_ = parse_sympy_repr(sympy_str)
480
488
  symbol_map = {}
481
489
  for _ in range(data.map_elements):
482
490
  elem_data = formats.PARAM_EXPR_MAP_ELEM(
@@ -503,7 +511,7 @@ def _read_parameter_expression(file_obj):
503
511
  raise exceptions.QpyError(f"Invalid parameter expression map type: {elem_key}")
504
512
  symbol_map[symbol] = value
505
513
 
506
- return ParameterExpression(symbol_map, expr_)
514
+ return ParameterExpression(symbol_map, str(expr_))
507
515
 
508
516
 
509
517
  def _read_parameter_expression_v3(file_obj, vectors, use_symengine):
@@ -516,7 +524,7 @@ def _read_parameter_expression_v3(file_obj, vectors, use_symengine):
516
524
  expr_ = common.load_symengine_payload(payload)
517
525
  else:
518
526
  sympy_str = payload.decode(common.ENCODE)
519
- expr_ = symengine.sympify(parse_sympy_repr(sympy_str))
527
+ expr_ = parse_sympy_repr(sympy_str)
520
528
 
521
529
  symbol_map = {}
522
530
  for _ in range(data.map_elements):
@@ -556,7 +564,7 @@ def _read_parameter_expression_v3(file_obj, vectors, use_symengine):
556
564
  raise exceptions.QpyError(f"Invalid parameter expression map type: {elem_key}")
557
565
  symbol_map[symbol] = value
558
566
 
559
- return ParameterExpression(symbol_map, expr_)
567
+ return ParameterExpression(symbol_map, str(expr_))
560
568
 
561
569
 
562
570
  def _read_parameter_expression_v13(file_obj, vectors, version):
@@ -641,9 +649,16 @@ def _read_parameter_expr_v13(buf, symbol_map, version, vectors):
641
649
  subs_map_data = buf.read(size)
642
650
  with io.BytesIO(subs_map_data) as mapping_buf:
643
651
  mapping = common.read_mapping(
644
- mapping_buf, deserializer=loads_value, version=version, vectors=vectors
652
+ mapping_buf,
653
+ deserializer=loads_value,
654
+ version=version,
655
+ vectors=vectors,
645
656
  )
646
- stack.append({name_map[k]: v for k, v in mapping.items()})
657
+ # Starting in version 15, the uuid is used instead of the name
658
+ if version < 15:
659
+ stack.append({name_map[k]: v for k, v in mapping.items()})
660
+ else:
661
+ stack.append({param_uuid_map[k]: v for k, v in mapping.items()})
647
662
  else:
648
663
  raise exceptions.QpyError(
649
664
  "Unknown ParameterExpression operation type {expression_data.LHS_TYPE}"
@@ -1067,7 +1082,6 @@ def loads_value(
1067
1082
  before setting this option, as it will be required by qpy to deserialize the payload.
1068
1083
  standalone_vars (Sequence[Var]): standalone :class:`.expr.Var` nodes in the order that they
1069
1084
  were declared by the circuit header.
1070
-
1071
1085
  Returns:
1072
1086
  any: Deserialized value object.
1073
1087
 
@@ -1094,7 +1108,11 @@ def loads_value(
1094
1108
  if type_key == type_keys.Value.CASE_DEFAULT:
1095
1109
  return CASE_DEFAULT
1096
1110
  if type_key == type_keys.Value.PARAMETER_VECTOR:
1097
- return common.data_from_binary(binary_data, _read_parameter_vec, vectors=vectors)
1111
+ return common.data_from_binary(
1112
+ binary_data,
1113
+ _read_parameter_vec,
1114
+ vectors=vectors,
1115
+ )
1098
1116
  if type_key == type_keys.Value.PARAMETER:
1099
1117
  return common.data_from_binary(binary_data, _read_parameter)
1100
1118
  if type_key == type_keys.Value.PARAMETER_EXPRESSION:
qiskit/qpy/common.py CHANGED
@@ -17,12 +17,13 @@ Common functions across several serialization and deserialization modules.
17
17
 
18
18
  import io
19
19
  import struct
20
+ import uuid
20
21
 
21
22
  from qiskit.utils.optionals import HAS_SYMENGINE
22
23
 
23
24
  from qiskit.qpy import formats, exceptions
24
25
 
25
- QPY_VERSION = 14
26
+ QPY_VERSION = 15
26
27
  QPY_COMPATIBILITY_VERSION = 13
27
28
  ENCODE = "utf8"
28
29
 
@@ -95,7 +96,11 @@ def read_mapping(file_obj, deserializer, **kwargs):
95
96
  map_header = formats.MAP_ITEM._make(
96
97
  struct.unpack(formats.MAP_ITEM_PACK, file_obj.read(formats.MAP_ITEM_SIZE))
97
98
  )
98
- key = file_obj.read(map_header.key_size).decode(ENCODE)
99
+ if kwargs.get("version", 15) < 15:
100
+ key = file_obj.read(map_header.key_size).decode(ENCODE)
101
+ else:
102
+ key = uuid.UUID(bytes=file_obj.read(map_header.key_size))
103
+
99
104
  datum = deserializer(map_header.type, file_obj.read(map_header.size), **kwargs)
100
105
  mapping[key] = datum
101
106
 
@@ -167,7 +172,10 @@ def write_mapping(file_obj, mapping, serializer, **kwargs):
167
172
 
168
173
  file_obj.write(struct.pack(formats.SEQUENCE_PACK, num_elements))
169
174
  for key, datum in mapping.items():
170
- key_bytes = key.encode(ENCODE)
175
+ if kwargs.get("version", 15) < 15:
176
+ key_bytes = key.encode(ENCODE)
177
+ else:
178
+ key_bytes = key
171
179
  type_key, datum_bytes = serializer(datum, **kwargs)
172
180
  item_header = struct.pack(formats.MAP_ITEM_PACK, len(key_bytes), type_key, len(datum_bytes))
173
181
  file_obj.write(item_header)
qiskit/qpy/formats.py CHANGED
@@ -128,7 +128,7 @@ CIRCUIT_INSTRUCTION_V2 = namedtuple(
128
128
  "num_parameters",
129
129
  "num_qargs",
130
130
  "num_cargs",
131
- "conditional_key",
131
+ "extras_key",
132
132
  "condition_register_size",
133
133
  "condition_value",
134
134
  "num_ctrl_qubits",
@@ -144,6 +144,22 @@ CIRCUIT_INSTRUCTION_ARG = namedtuple("CIRCUIT_INSTRUCTION_ARG", ["type", "size"]
144
144
  CIRCUIT_INSTRUCTION_ARG_PACK = "!1cI"
145
145
  CIRCUIT_INSTRUCTION_ARG_SIZE = struct.calcsize(CIRCUIT_INSTRUCTION_ARG_PACK)
146
146
 
147
+ ANNOTATION_HEADER_STATIC = namedtuple("ANNOTATION_HEADER_STATIC", ["num_namespaces"])
148
+ ANNOTATION_HEADER_STATIC_PACK = "!I"
149
+ ANNOTATION_HEADER_STATIC_SIZE = struct.calcsize(ANNOTATION_HEADER_STATIC_PACK)
150
+
151
+ ANNOTATION_STATE_HEADER = namedtuple("ANNOTATION_STATE_HEADER", ["namespace_size", "state_size"])
152
+ ANNOTATION_STATE_HEADER_PACK = "!IQ"
153
+ ANNOTATION_STATE_HEADER_SIZE = struct.calcsize(ANNOTATION_STATE_HEADER_PACK)
154
+
155
+ INSTRUCTION_ANNOTATIONS_HEADER = namedtuple("INSTRUCTION_ANNOTATIONS_HEADER", ["num_annotations"])
156
+ INSTRUCTION_ANNOTATIONS_HEADER_PACK = "!I"
157
+ INSTRUCTION_ANNOTATIONS_HEADER_SIZE = struct.calcsize(INSTRUCTION_ANNOTATIONS_HEADER_PACK)
158
+
159
+ INSTRUCTION_ANNOTATION = namedtuple("INSTRUCTION_ANNOTATION", ["namespace_index", "payload_size"])
160
+ INSTRUCTION_ANNOTATION_PACK = "!IQ"
161
+ INSTRUCTION_ANNOTATION_SIZE = struct.calcsize(INSTRUCTION_ANNOTATION_PACK)
162
+
147
163
  # SparsePauliOp List
148
164
  SPARSE_PAULI_OP_LIST_ELEM = namedtuple("SPARSE_PAULI_OP_LIST_ELEMENT", ["size"])
149
165
  SPARSE_PAULI_OP_LIST_ELEM_PACK = "!Q"
qiskit/qpy/interface.py CHANGED
@@ -15,8 +15,8 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from json import JSONEncoder, JSONDecoder
18
- from typing import Union, List, BinaryIO, Type, Optional
19
- from collections.abc import Iterable
18
+ from typing import Union, List, BinaryIO, Type, Optional, Callable, TYPE_CHECKING
19
+ from collections.abc import Iterable, Mapping
20
20
  import struct
21
21
  import warnings
22
22
  import re
@@ -27,6 +27,9 @@ from qiskit.qpy import formats, common, binary_io, type_keys
27
27
  from qiskit.qpy.exceptions import QpyError
28
28
  from qiskit.version import __version__
29
29
 
30
+ if TYPE_CHECKING:
31
+ from qiskit.circuit import annotation
32
+
30
33
 
31
34
  # pylint: disable=invalid-name
32
35
  QPY_SUPPORTED_TYPES = QuantumCircuit
@@ -78,6 +81,7 @@ def dump(
78
81
  metadata_serializer: Optional[Type[JSONEncoder]] = None,
79
82
  use_symengine: bool = False,
80
83
  version: int = common.QPY_VERSION,
84
+ annotation_factories: Optional[Mapping[str, Callable[[], annotation.QPYSerializer]]] = None,
81
85
  ):
82
86
  """Write QPY binary data to a file
83
87
 
@@ -152,6 +156,11 @@ def dump(
152
156
  QPY files containing ``symengine``-serialized :class:`.ParameterExpression` objects
153
157
  unless the version of ``symengine`` used between the loading and generating
154
158
  environments matches.
159
+ annotation_factories: Mapping of namespaces to functions that create new instances of
160
+ :class:`.annotation.QPUSerializer`, for handling the dumping of custom
161
+ :class:`.Annotation` objects. The subsequent call to :func:`load` will need to use
162
+ similar serializer objects, that understand the custom output format of those
163
+ serializers.
155
164
 
156
165
 
157
166
  Raises:
@@ -166,9 +175,6 @@ def dump(
166
175
  if not issubclass(type(program), QuantumCircuit):
167
176
  raise TypeError(f"'{type(program)}' is not a supported data type.")
168
177
 
169
- type_key = type_keys.Program.CIRCUIT
170
- writer = binary_io.write_circuit
171
-
172
178
  if version is None:
173
179
  version = common.QPY_VERSION
174
180
  elif common.QPY_COMPATIBILITY_VERSION > version or version > common.QPY_VERSION:
@@ -192,21 +198,23 @@ def dump(
192
198
  encoding,
193
199
  )
194
200
  file_obj.write(header)
195
- common.write_type_key(file_obj, type_key)
201
+ common.write_type_key(file_obj, type_keys.Program.CIRCUIT)
196
202
 
197
203
  for program in programs:
198
- writer(
204
+ binary_io.write_circuit(
199
205
  file_obj,
200
206
  program,
201
207
  metadata_serializer=metadata_serializer,
202
208
  use_symengine=use_symengine,
203
209
  version=version,
210
+ annotation_factories=annotation_factories,
204
211
  )
205
212
 
206
213
 
207
214
  def load(
208
215
  file_obj: BinaryIO,
209
216
  metadata_deserializer: Optional[Type[JSONDecoder]] = None,
217
+ annotation_factories: Optional[Mapping[str, Callable[[], annotation.QPYSerializer]]] = None,
210
218
  ) -> List[QPY_SUPPORTED_TYPES]:
211
219
  """Load a QPY binary file
212
220
 
@@ -244,6 +252,9 @@ def load(
244
252
  If this is not specified the circuit metadata will
245
253
  be parsed as JSON with the stdlib ``json.load()`` function using
246
254
  the default ``JSONDecoder`` class.
255
+ annotation_factories: Mapping of namespaces to functions that create new instances of
256
+ :class:`.annotation.QPUSerializer`, for handling the loading of custom
257
+ :class:`.Annotation` objects.
247
258
 
248
259
  Returns:
249
260
  The list of Qiskit programs contained in the QPY data.
@@ -316,14 +327,12 @@ def load(
316
327
  else:
317
328
  type_key = common.read_type_key(file_obj)
318
329
 
319
- if type_key == type_keys.Program.CIRCUIT:
320
- loader = binary_io.read_circuit
321
- elif type_key == type_keys.Program.SCHEDULE_BLOCK:
330
+ if type_key == type_keys.Program.SCHEDULE_BLOCK:
322
331
  raise QpyError(
323
332
  "Payloads of type `ScheduleBlock` cannot be loaded as of Qiskit 2.0. "
324
333
  "Use an earlier version of Qiskit if you want to load `ScheduleBlock` payloads."
325
334
  )
326
- else:
335
+ if type_key != type_keys.Program.CIRCUIT:
327
336
  raise TypeError(f"Invalid payload format data kind '{type_key}'.")
328
337
 
329
338
  if data.qpy_version < 10:
@@ -334,11 +343,42 @@ def load(
334
343
  programs = []
335
344
  for _ in range(data.num_programs):
336
345
  programs.append(
337
- loader(
346
+ binary_io.read_circuit(
338
347
  file_obj,
339
348
  data.qpy_version,
340
349
  metadata_deserializer=metadata_deserializer,
341
350
  use_symengine=use_symengine,
351
+ annotation_factories=annotation_factories,
342
352
  )
343
353
  )
344
354
  return programs
355
+
356
+
357
+ def get_qpy_version(
358
+ file_obj: BinaryIO,
359
+ ) -> int:
360
+ """This function identifies the QPY version of the file.
361
+
362
+ This function will read the header of ``file_obj`` and will
363
+ return the QPY format version. It will **not** advance the
364
+ cursor of ``file_obj``. If you are using this for a subsequent
365
+ read, such as to call :func:`.load`, you can pass ``file_obj``
366
+ directly. For example::
367
+
368
+ from qiskit import qpy
369
+
370
+ qpy_version = qpy.get_qpy_version(qpy_file)
371
+ if qpy_version > 12:
372
+ qpy.load(qpy_file)
373
+
374
+ Args:
375
+ file_obj: A file like object that contains the QPY binary
376
+ data for a circuit.
377
+
378
+ Returns:
379
+ The QPY version of the specified file.
380
+ """
381
+
382
+ version = struct.unpack("!6sB", file_obj.read(7))[1]
383
+ file_obj.seek(-7, 1)
384
+ return version
qiskit/qpy/type_keys.py CHANGED
@@ -18,7 +18,7 @@ QPY Type keys for several namespace.
18
18
 
19
19
  import uuid
20
20
  from abc import abstractmethod
21
- from enum import Enum, IntEnum
21
+ from enum import Enum, IntEnum, IntFlag
22
22
 
23
23
  import numpy as np
24
24
 
@@ -138,6 +138,12 @@ class Condition(IntEnum):
138
138
  EXPRESSION = 2
139
139
 
140
140
 
141
+ class InstructionExtraFlags(IntFlag):
142
+ """If an instruction has extra payloads associated with it."""
143
+
144
+ HAS_ANNOTATIONS = 0b1000_0000
145
+
146
+
141
147
  class Container(TypeKeyBase):
142
148
  """Type key enum for container-like object."""
143
149
 
@@ -30,9 +30,13 @@ Operators
30
30
  ScalarOp
31
31
  SparseObservable
32
32
  SparsePauliOp
33
+ PauliLindbladMap
34
+ QubitSparsePauli
35
+ QubitSparsePauliList
33
36
  CNOTDihedral
34
37
  PauliList
35
38
  pauli_basis
39
+ get_clifford_gate_names
36
40
 
37
41
  .. _quantum_info_states:
38
42
 
@@ -115,6 +119,11 @@ Analysis
115
119
 
116
120
  from __future__ import annotations
117
121
 
122
+ from qiskit._accelerate.pauli_lindblad_map import (
123
+ QubitSparsePauliList,
124
+ QubitSparsePauli,
125
+ PauliLindbladMap,
126
+ )
118
127
  from qiskit._accelerate.sparse_observable import SparseObservable
119
128
 
120
129
  from .analysis import hellinger_distance, hellinger_fidelity, Z2Symmetries
@@ -129,6 +138,7 @@ from .operators import (
129
138
  commutator,
130
139
  double_commutator,
131
140
  pauli_basis,
141
+ get_clifford_gate_names,
132
142
  )
133
143
  from .operators.channel import PTM, Chi, Choi, Kraus, Stinespring, SuperOp
134
144
  from .operators.dihedral import CNOTDihedral
@@ -24,5 +24,6 @@ from .symplectic import (
24
24
  PauliList,
25
25
  SparsePauliOp,
26
26
  pauli_basis,
27
+ get_clifford_gate_names,
27
28
  )
28
29
  from .utils import anti_commutator, commutator, double_commutator
@@ -17,6 +17,7 @@ Symplectic Operators
17
17
  from __future__ import annotations
18
18
 
19
19
  from .clifford import Clifford
20
+ from .clifford_circuits import get_clifford_gate_names
20
21
  from .pauli import Pauli
21
22
  from .pauli_list import PauliList
22
23
  from .pauli_utils import pauli_basis
@@ -554,5 +554,31 @@ _BASIS_2Q = {
554
554
  "ecr": _append_ecr,
555
555
  "dcx": _append_dcx,
556
556
  }
557
+
558
+ # Clifford gate names
559
+ _CLIFFORD_GATE_NAMES = [
560
+ "id",
561
+ "x",
562
+ "y",
563
+ "z",
564
+ "h",
565
+ "s",
566
+ "sdg",
567
+ "sx",
568
+ "sxdg",
569
+ "cx",
570
+ "cz",
571
+ "cy",
572
+ "swap",
573
+ "iswap",
574
+ "ecr",
575
+ "dcx",
576
+ ]
577
+
557
578
  # Non-clifford gates
558
579
  _NON_CLIFFORD = {"t", "tdg", "ccx", "ccz"}
580
+
581
+
582
+ def get_clifford_gate_names() -> list:
583
+ """Returns the list of Clifford gate names."""
584
+ return _CLIFFORD_GATE_NAMES
@@ -708,7 +708,7 @@ class Pauli(BasePauli):
708
708
  def apply_layout(
709
709
  self, layout: TranspileLayout | list[int] | None, num_qubits: int | None = None
710
710
  ) -> Pauli:
711
- """Apply a transpiler layout to this :class:`~.Pauli`
711
+ """Apply a transpiler layout to this :class:`~.quantum_info.Pauli`
712
712
 
713
713
  Args:
714
714
  layout: Either a :class:`~.TranspileLayout`, a list of integers or None.
@@ -722,7 +722,7 @@ class Pauli(BasePauli):
722
722
  None, the operator will be expanded to the given number of qubits.
723
723
 
724
724
  Returns:
725
- A new :class:`.Pauli` with the provided layout applied
725
+ A new :class:`~.quantum_info.Pauli` with the provided layout applied
726
726
  """
727
727
  from qiskit.transpiler.layout import TranspileLayout
728
728
 
@@ -23,6 +23,7 @@ from .distributions import QuasiDistribution, ProbDistribution
23
23
  OPERS = {"Z", "I", "0", "1"}
24
24
 
25
25
 
26
+ # pylint: disable=missing-param-doc,missing-type-doc
26
27
  def sampled_expectation_value(dist, oper):
27
28
  """Computes expectation value from a sampled distribution
28
29
 
@@ -30,7 +31,8 @@ def sampled_expectation_value(dist, oper):
30
31
 
31
32
  Parameters:
32
33
  dist (Counts or QuasiDistribution or ProbDistribution or dict): Input sampled distribution
33
- oper (str or Pauli or SparsePauliOp): The operator for the observable
34
+ oper (str or :class:`~.quantum_info.Pauli` or SparsePauliOp): The operator for the
35
+ observable
34
36
 
35
37
  Returns:
36
38
  float: The expectation value
@@ -127,6 +127,10 @@ Multi Controlled Synthesis
127
127
  ==========================
128
128
 
129
129
  .. autofunction:: synth_mcmt_vchain
130
+ .. autofunction:: synth_mcx_1_clean_kg24
131
+ .. autofunction:: synth_mcx_1_dirty_kg24
132
+ .. autofunction:: synth_mcx_2_clean_kg24
133
+ .. autofunction:: synth_mcx_2_dirty_kg24
130
134
  .. autofunction:: synth_mcx_n_dirty_i15
131
135
  .. autofunction:: synth_mcx_n_clean_m15
132
136
  .. autofunction:: synth_mcx_1_clean_b95
@@ -144,6 +148,7 @@ Adders
144
148
  .. autofunction:: adder_qft_d00
145
149
  .. autofunction:: adder_ripple_c04
146
150
  .. autofunction:: adder_ripple_v95
151
+ .. autofunction:: adder_ripple_r25
147
152
 
148
153
  Multipliers
149
154
  -----------
@@ -220,6 +225,10 @@ from .two_qubit.two_qubit_decompose import (
220
225
  )
221
226
  from .multi_controlled import (
222
227
  synth_mcmt_vchain,
228
+ synth_mcx_1_clean_kg24,
229
+ synth_mcx_1_dirty_kg24,
230
+ synth_mcx_2_clean_kg24,
231
+ synth_mcx_2_dirty_kg24,
223
232
  synth_mcx_n_dirty_i15,
224
233
  synth_mcx_n_clean_m15,
225
234
  synth_mcx_1_clean_b95,
@@ -232,6 +241,7 @@ from .arithmetic import (
232
241
  adder_qft_d00,
233
242
  adder_ripple_c04,
234
243
  adder_ripple_v95,
244
+ adder_ripple_r25,
235
245
  multiplier_cumulative_h18,
236
246
  multiplier_qft_r17,
237
247
  synth_integer_comparator_greedy,
@@ -13,6 +13,6 @@
13
13
  """Synthesis for arithmetic circuits."""
14
14
 
15
15
  from .comparators import synth_integer_comparator_2s, synth_integer_comparator_greedy
16
- from .adders import adder_qft_d00, adder_ripple_c04, adder_ripple_v95
16
+ from .adders import adder_qft_d00, adder_ripple_c04, adder_ripple_v95, adder_ripple_r25
17
17
  from .multipliers import multiplier_cumulative_h18, multiplier_qft_r17
18
18
  from .weighted_sum import synth_weighted_sum_carry
@@ -15,3 +15,4 @@
15
15
  from .cdkm_ripple_carry_adder import adder_ripple_c04
16
16
  from .vbe_ripple_carry_adder import adder_ripple_v95
17
17
  from .draper_qft_adder import adder_qft_d00
18
+ from .rv_ripple_carry_adder import adder_ripple_r25
@@ -19,7 +19,9 @@ from qiskit.circuit import QuantumRegister
19
19
  from qiskit.circuit.library.basis_change import QFTGate
20
20
 
21
21
 
22
- def adder_qft_d00(num_state_qubits: int, kind: str = "half") -> QuantumCircuit:
22
+ def adder_qft_d00(
23
+ num_state_qubits: int, kind: str = "half", annotated: bool = False
24
+ ) -> QuantumCircuit:
23
25
  r"""A circuit that uses QFT to perform in-place addition on two qubit registers.
24
26
 
25
27
  For registers with :math:`n` qubits, the QFT adder can perform addition modulo
@@ -51,6 +53,8 @@ def adder_qft_d00(num_state_qubits: int, kind: str = "half") -> QuantumCircuit:
51
53
  ``"fixed"`` for a fixed-sized adder. A half adder contains a carry-out to represent
52
54
  the most-significant bit, but the fixed-sized adder doesn't and hence performs
53
55
  addition modulo ``2 ** num_state_qubits``.
56
+ annotated: If ``True``, creates appropriate control and inverse operations as
57
+ ``AnnotatedOperation`` objects.
54
58
 
55
59
  **References:**
56
60
 
@@ -98,6 +102,6 @@ def adder_qft_d00(num_state_qubits: int, kind: str = "half") -> QuantumCircuit:
98
102
  # can be elided and cancelled by the compiler
99
103
  circuit.cp(lam, qr_a[j], qr_sum[~(j + k)])
100
104
 
101
- circuit.append(qft.inverse(), qr_sum[:])
105
+ circuit.append(qft.inverse(annotated=annotated), qr_sum[:])
102
106
 
103
107
  return circuit