qiskit 1.1.1__cp38-abi3-macosx_11_0_arm64.whl → 1.2.0__cp38-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 (347) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +27 -24
  3. qiskit/_accelerate.abi3.so +0 -0
  4. qiskit/_numpy_compat.py +1 -1
  5. qiskit/assembler/assemble_circuits.py +107 -64
  6. qiskit/assembler/assemble_schedules.py +5 -12
  7. qiskit/assembler/disassemble.py +10 -1
  8. qiskit/circuit/__init__.py +6 -3
  9. qiskit/circuit/_classical_resource_map.py +5 -5
  10. qiskit/circuit/_utils.py +0 -13
  11. qiskit/circuit/add_control.py +1 -1
  12. qiskit/circuit/annotated_operation.py +23 -1
  13. qiskit/circuit/classical/expr/expr.py +4 -4
  14. qiskit/circuit/classical/expr/visitors.py +1 -1
  15. qiskit/circuit/classical/types/__init__.py +1 -1
  16. qiskit/circuit/classical/types/types.py +2 -2
  17. qiskit/circuit/classicalfunction/__init__.py +8 -0
  18. qiskit/circuit/classicalfunction/boolean_expression.py +1 -1
  19. qiskit/circuit/classicalfunction/classical_function_visitor.py +5 -5
  20. qiskit/circuit/classicalfunction/utils.py +1 -1
  21. qiskit/circuit/classicalregister.py +1 -1
  22. qiskit/circuit/commutation_checker.py +83 -35
  23. qiskit/circuit/controlflow/_builder_utils.py +1 -1
  24. qiskit/circuit/controlflow/builder.py +10 -6
  25. qiskit/circuit/controlflow/if_else.py +2 -2
  26. qiskit/circuit/controlflow/switch_case.py +1 -1
  27. qiskit/circuit/delay.py +1 -1
  28. qiskit/circuit/duration.py +2 -2
  29. qiskit/circuit/equivalence.py +5 -7
  30. qiskit/circuit/gate.py +11 -8
  31. qiskit/circuit/instruction.py +31 -13
  32. qiskit/circuit/instructionset.py +2 -5
  33. qiskit/circuit/library/__init__.py +2 -1
  34. qiskit/circuit/library/arithmetic/linear_amplitude_function.py +1 -1
  35. qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
  36. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +1 -1
  37. qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +1 -1
  38. qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +3 -3
  39. qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +1 -1
  40. qiskit/circuit/library/basis_change/__init__.py +1 -1
  41. qiskit/circuit/library/basis_change/qft.py +40 -6
  42. qiskit/circuit/library/blueprintcircuit.py +3 -5
  43. qiskit/circuit/library/data_preparation/__init__.py +9 -2
  44. qiskit/circuit/library/data_preparation/initializer.py +8 -0
  45. qiskit/circuit/library/data_preparation/state_preparation.py +98 -178
  46. qiskit/circuit/library/generalized_gates/isometry.py +8 -8
  47. qiskit/circuit/library/generalized_gates/linear_function.py +3 -2
  48. qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py +4 -4
  49. qiskit/circuit/library/generalized_gates/permutation.py +8 -9
  50. qiskit/circuit/library/generalized_gates/uc.py +3 -3
  51. qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +2 -2
  52. qiskit/circuit/library/generalized_gates/unitary.py +13 -11
  53. qiskit/circuit/library/graph_state.py +1 -1
  54. qiskit/circuit/library/hamiltonian_gate.py +1 -2
  55. qiskit/circuit/library/hidden_linear_function.py +1 -1
  56. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +3 -2
  57. qiskit/circuit/library/n_local/n_local.py +4 -5
  58. qiskit/circuit/library/n_local/pauli_two_design.py +1 -1
  59. qiskit/circuit/library/n_local/qaoa_ansatz.py +6 -8
  60. qiskit/circuit/library/n_local/two_local.py +1 -1
  61. qiskit/circuit/library/overlap.py +11 -5
  62. qiskit/circuit/library/pauli_evolution.py +7 -3
  63. qiskit/circuit/library/standard_gates/dcx.py +3 -0
  64. qiskit/circuit/library/standard_gates/ecr.py +3 -0
  65. qiskit/circuit/library/standard_gates/global_phase.py +3 -0
  66. qiskit/circuit/library/standard_gates/h.py +13 -5
  67. qiskit/circuit/library/standard_gates/i.py +3 -0
  68. qiskit/circuit/library/standard_gates/iswap.py +3 -0
  69. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +19 -10
  70. qiskit/circuit/library/standard_gates/p.py +14 -9
  71. qiskit/circuit/library/standard_gates/r.py +3 -0
  72. qiskit/circuit/library/standard_gates/rx.py +21 -6
  73. qiskit/circuit/library/standard_gates/rxx.py +40 -1
  74. qiskit/circuit/library/standard_gates/ry.py +21 -6
  75. qiskit/circuit/library/standard_gates/ryy.py +40 -1
  76. qiskit/circuit/library/standard_gates/rz.py +22 -6
  77. qiskit/circuit/library/standard_gates/rzx.py +40 -1
  78. qiskit/circuit/library/standard_gates/rzz.py +41 -2
  79. qiskit/circuit/library/standard_gates/s.py +77 -0
  80. qiskit/circuit/library/standard_gates/swap.py +12 -5
  81. qiskit/circuit/library/standard_gates/sx.py +14 -5
  82. qiskit/circuit/library/standard_gates/t.py +5 -0
  83. qiskit/circuit/library/standard_gates/u.py +22 -7
  84. qiskit/circuit/library/standard_gates/u1.py +8 -3
  85. qiskit/circuit/library/standard_gates/u2.py +3 -0
  86. qiskit/circuit/library/standard_gates/u3.py +22 -7
  87. qiskit/circuit/library/standard_gates/x.py +158 -92
  88. qiskit/circuit/library/standard_gates/xx_minus_yy.py +40 -1
  89. qiskit/circuit/library/standard_gates/xx_plus_yy.py +52 -11
  90. qiskit/circuit/library/standard_gates/y.py +6 -1
  91. qiskit/circuit/library/standard_gates/z.py +8 -1
  92. qiskit/circuit/operation.py +1 -1
  93. qiskit/circuit/parameter.py +9 -10
  94. qiskit/circuit/parameterexpression.py +16 -13
  95. qiskit/circuit/parametertable.py +1 -190
  96. qiskit/circuit/parametervector.py +1 -1
  97. qiskit/circuit/quantumcircuit.py +395 -385
  98. qiskit/circuit/quantumcircuitdata.py +3 -5
  99. qiskit/circuit/quantumregister.py +1 -1
  100. qiskit/circuit/random/__init__.py +1 -1
  101. qiskit/circuit/random/utils.py +175 -26
  102. qiskit/circuit/register.py +5 -7
  103. qiskit/circuit/singleton.py +3 -3
  104. qiskit/circuit/tools/pi_check.py +4 -4
  105. qiskit/compiler/assembler.py +95 -24
  106. qiskit/compiler/scheduler.py +2 -2
  107. qiskit/compiler/transpiler.py +42 -128
  108. qiskit/converters/circuit_to_dag.py +4 -6
  109. qiskit/converters/circuit_to_gate.py +4 -8
  110. qiskit/converters/circuit_to_instruction.py +5 -17
  111. qiskit/converters/dag_to_circuit.py +2 -6
  112. qiskit/dagcircuit/collect_blocks.py +2 -2
  113. qiskit/dagcircuit/dagcircuit.py +197 -187
  114. qiskit/dagcircuit/dagdependency.py +4 -4
  115. qiskit/dagcircuit/dagdependency_v2.py +4 -4
  116. qiskit/dagcircuit/dagdepnode.py +1 -1
  117. qiskit/dagcircuit/dagnode.py +66 -157
  118. qiskit/passmanager/flow_controllers.py +1 -1
  119. qiskit/passmanager/passmanager.py +3 -3
  120. qiskit/primitives/__init__.py +1 -5
  121. qiskit/primitives/backend_estimator.py +25 -15
  122. qiskit/primitives/backend_estimator_v2.py +31 -7
  123. qiskit/primitives/backend_sampler.py +21 -12
  124. qiskit/primitives/backend_sampler_v2.py +12 -3
  125. qiskit/primitives/base/base_estimator.py +31 -4
  126. qiskit/primitives/base/base_primitive.py +2 -2
  127. qiskit/primitives/base/base_result.py +2 -2
  128. qiskit/primitives/base/base_sampler.py +26 -2
  129. qiskit/primitives/base/estimator_result.py +2 -2
  130. qiskit/primitives/base/sampler_result.py +2 -2
  131. qiskit/primitives/containers/__init__.py +0 -1
  132. qiskit/primitives/containers/bindings_array.py +2 -2
  133. qiskit/primitives/containers/bit_array.py +113 -12
  134. qiskit/primitives/containers/shape.py +3 -3
  135. qiskit/primitives/estimator.py +9 -2
  136. qiskit/primitives/primitive_job.py +1 -1
  137. qiskit/primitives/sampler.py +10 -3
  138. qiskit/primitives/statevector_estimator.py +5 -3
  139. qiskit/primitives/statevector_sampler.py +11 -5
  140. qiskit/primitives/utils.py +16 -0
  141. qiskit/providers/backend.py +15 -6
  142. qiskit/providers/backend_compat.py +7 -4
  143. qiskit/providers/basic_provider/basic_provider_tools.py +1 -1
  144. qiskit/providers/basic_provider/basic_simulator.py +33 -25
  145. qiskit/providers/fake_provider/fake_backend.py +10 -3
  146. qiskit/providers/fake_provider/fake_openpulse_2q.py +157 -149
  147. qiskit/providers/fake_provider/fake_openpulse_3q.py +228 -220
  148. qiskit/providers/fake_provider/fake_pulse_backend.py +2 -1
  149. qiskit/providers/fake_provider/fake_qasm_backend.py +7 -2
  150. qiskit/providers/fake_provider/generic_backend_v2.py +519 -68
  151. qiskit/providers/models/__init__.py +48 -11
  152. qiskit/providers/models/backendconfiguration.py +50 -4
  153. qiskit/providers/models/backendproperties.py +13 -2
  154. qiskit/providers/models/pulsedefaults.py +10 -11
  155. qiskit/providers/options.py +13 -13
  156. qiskit/providers/providerutils.py +3 -1
  157. qiskit/pulse/configuration.py +8 -12
  158. qiskit/pulse/instruction_schedule_map.py +3 -5
  159. qiskit/pulse/instructions/acquire.py +7 -8
  160. qiskit/pulse/instructions/instruction.py +2 -3
  161. qiskit/pulse/library/samplers/decorators.py +5 -9
  162. qiskit/pulse/library/symbolic_pulses.py +4 -7
  163. qiskit/pulse/library/waveform.py +2 -5
  164. qiskit/pulse/macros.py +11 -6
  165. qiskit/pulse/parser.py +8 -10
  166. qiskit/pulse/schedule.py +12 -20
  167. qiskit/pulse/transforms/alignments.py +1 -3
  168. qiskit/pulse/utils.py +1 -2
  169. qiskit/qasm/libs/stdgates.inc +35 -28
  170. qiskit/qasm2/__init__.py +7 -7
  171. qiskit/qasm2/export.py +5 -9
  172. qiskit/qasm2/parse.py +1 -1
  173. qiskit/qasm3/ast.py +9 -25
  174. qiskit/qasm3/exporter.py +582 -479
  175. qiskit/qasm3/printer.py +7 -16
  176. qiskit/qobj/common.py +10 -0
  177. qiskit/qobj/converters/lo_config.py +9 -0
  178. qiskit/qobj/converters/pulse_instruction.py +13 -6
  179. qiskit/qobj/pulse_qobj.py +69 -15
  180. qiskit/qobj/qasm_qobj.py +72 -20
  181. qiskit/qobj/utils.py +9 -0
  182. qiskit/qpy/__init__.py +1 -1
  183. qiskit/qpy/binary_io/circuits.py +8 -5
  184. qiskit/qpy/binary_io/schedules.py +1 -1
  185. qiskit/qpy/binary_io/value.py +3 -3
  186. qiskit/qpy/interface.py +3 -2
  187. qiskit/qpy/type_keys.py +2 -2
  188. qiskit/quantum_info/operators/channel/quantum_channel.py +3 -6
  189. qiskit/quantum_info/operators/channel/superop.py +2 -2
  190. qiskit/quantum_info/operators/channel/transformations.py +1 -1
  191. qiskit/quantum_info/operators/dihedral/dihedral.py +3 -4
  192. qiskit/quantum_info/operators/dihedral/dihedral_circuits.py +1 -3
  193. qiskit/quantum_info/operators/dihedral/random.py +6 -3
  194. qiskit/quantum_info/operators/measures.py +2 -2
  195. qiskit/quantum_info/operators/op_shape.py +12 -20
  196. qiskit/quantum_info/operators/operator.py +14 -21
  197. qiskit/quantum_info/operators/predicates.py +1 -0
  198. qiskit/quantum_info/operators/symplectic/base_pauli.py +7 -11
  199. qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
  200. qiskit/quantum_info/operators/symplectic/pauli.py +14 -12
  201. qiskit/quantum_info/operators/symplectic/pauli_list.py +9 -10
  202. qiskit/quantum_info/operators/symplectic/random.py +1 -1
  203. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +15 -17
  204. qiskit/quantum_info/quaternion.py +1 -1
  205. qiskit/quantum_info/states/densitymatrix.py +5 -8
  206. qiskit/quantum_info/states/stabilizerstate.py +128 -37
  207. qiskit/quantum_info/states/statevector.py +4 -8
  208. qiskit/result/counts.py +2 -2
  209. qiskit/result/mitigation/correlated_readout_mitigator.py +2 -2
  210. qiskit/result/mitigation/local_readout_mitigator.py +2 -2
  211. qiskit/result/mitigation/utils.py +1 -3
  212. qiskit/result/models.py +17 -16
  213. qiskit/result/result.py +15 -20
  214. qiskit/scheduler/lowering.py +2 -2
  215. qiskit/synthesis/__init__.py +2 -1
  216. qiskit/synthesis/clifford/__init__.py +1 -1
  217. qiskit/synthesis/clifford/clifford_decompose_ag.py +2 -2
  218. qiskit/synthesis/clifford/clifford_decompose_bm.py +10 -240
  219. qiskit/synthesis/clifford/clifford_decompose_greedy.py +9 -303
  220. qiskit/synthesis/clifford/clifford_decompose_layers.py +25 -23
  221. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_full.py +1 -1
  222. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_general.py +1 -1
  223. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +2 -2
  224. qiskit/synthesis/discrete_basis/solovay_kitaev.py +24 -14
  225. qiskit/synthesis/evolution/evolution_synthesis.py +4 -2
  226. qiskit/synthesis/evolution/lie_trotter.py +46 -19
  227. qiskit/synthesis/evolution/product_formula.py +111 -55
  228. qiskit/synthesis/evolution/qdrift.py +40 -10
  229. qiskit/synthesis/evolution/suzuki_trotter.py +43 -33
  230. qiskit/synthesis/linear/__init__.py +1 -0
  231. qiskit/synthesis/linear/cnot_synth.py +22 -96
  232. qiskit/synthesis/linear/linear_depth_lnn.py +8 -8
  233. qiskit/synthesis/linear/linear_matrix_utils.py +13 -161
  234. qiskit/synthesis/linear_phase/cnot_phase_synth.py +1 -1
  235. qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +3 -3
  236. qiskit/synthesis/linear_phase/cz_depth_lnn.py +1 -1
  237. qiskit/synthesis/one_qubit/one_qubit_decompose.py +29 -29
  238. qiskit/synthesis/permutation/permutation_full.py +5 -29
  239. qiskit/synthesis/permutation/permutation_lnn.py +2 -24
  240. qiskit/synthesis/permutation/permutation_utils.py +2 -59
  241. qiskit/synthesis/qft/__init__.py +1 -0
  242. qiskit/synthesis/qft/qft_decompose_full.py +79 -0
  243. qiskit/synthesis/qft/qft_decompose_lnn.py +17 -9
  244. qiskit/synthesis/stabilizer/stabilizer_circuit.py +6 -6
  245. qiskit/synthesis/stabilizer/stabilizer_decompose.py +2 -2
  246. qiskit/synthesis/two_qubit/local_invariance.py +8 -38
  247. qiskit/synthesis/two_qubit/two_qubit_decompose.py +48 -129
  248. qiskit/synthesis/unitary/aqc/cnot_structures.py +1 -1
  249. qiskit/synthesis/unitary/qsd.py +5 -3
  250. qiskit/transpiler/__init__.py +6 -5
  251. qiskit/transpiler/basepasses.py +1 -1
  252. qiskit/transpiler/coupling.py +3 -3
  253. qiskit/transpiler/instruction_durations.py +1 -2
  254. qiskit/transpiler/layout.py +6 -6
  255. qiskit/transpiler/passes/__init__.py +2 -0
  256. qiskit/transpiler/passes/basis/basis_translator.py +84 -64
  257. qiskit/transpiler/passes/basis/translate_parameterized.py +3 -5
  258. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
  259. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +10 -10
  260. qiskit/transpiler/passes/calibration/rx_builder.py +3 -3
  261. qiskit/transpiler/passes/calibration/rzx_builder.py +3 -3
  262. qiskit/transpiler/passes/layout/apply_layout.py +13 -3
  263. qiskit/transpiler/passes/layout/sabre_layout.py +10 -8
  264. qiskit/transpiler/passes/layout/sabre_pre_layout.py +4 -1
  265. qiskit/transpiler/passes/layout/set_layout.py +2 -2
  266. qiskit/transpiler/passes/layout/vf2_layout.py +1 -1
  267. qiskit/transpiler/passes/layout/vf2_utils.py +3 -3
  268. qiskit/transpiler/passes/optimization/__init__.py +1 -0
  269. qiskit/transpiler/passes/optimization/collect_cliffords.py +6 -15
  270. qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
  271. qiskit/transpiler/passes/optimization/commutation_analysis.py +7 -10
  272. qiskit/transpiler/passes/optimization/commutative_cancellation.py +35 -19
  273. qiskit/transpiler/passes/optimization/consolidate_blocks.py +17 -8
  274. qiskit/transpiler/passes/optimization/inverse_cancellation.py +6 -6
  275. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +64 -41
  276. qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
  277. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +83 -0
  278. qiskit/transpiler/passes/optimization/template_matching/backward_match.py +1 -1
  279. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +2 -2
  280. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +1 -1
  281. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -2
  282. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/pauli_2q_evolution_commutation.py +5 -1
  283. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
  284. qiskit/transpiler/passes/routing/layout_transformation.py +2 -1
  285. qiskit/transpiler/passes/routing/sabre_swap.py +35 -26
  286. qiskit/transpiler/passes/routing/star_prerouting.py +80 -105
  287. qiskit/transpiler/passes/routing/stochastic_swap.py +1 -3
  288. qiskit/transpiler/passes/scheduling/alap.py +1 -2
  289. qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -2
  290. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  291. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +2 -2
  292. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +1 -1
  293. qiskit/transpiler/passes/scheduling/asap.py +1 -2
  294. qiskit/transpiler/passes/scheduling/base_scheduler.py +5 -5
  295. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +3 -3
  296. qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
  297. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +20 -14
  298. qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +7 -6
  299. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +4 -3
  300. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +211 -36
  301. qiskit/transpiler/passes/synthesis/plugin.py +2 -2
  302. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +83 -40
  303. qiskit/transpiler/passes/utils/__init__.py +0 -1
  304. qiskit/transpiler/passes/utils/check_gate_direction.py +4 -4
  305. qiskit/transpiler/passes/utils/check_map.py +3 -6
  306. qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +3 -4
  307. qiskit/transpiler/passes/utils/error.py +2 -2
  308. qiskit/transpiler/passes/utils/fixed_point.py +3 -3
  309. qiskit/transpiler/passes/utils/gate_direction.py +1 -1
  310. qiskit/transpiler/passes/utils/gates_basis.py +1 -2
  311. qiskit/transpiler/passmanager.py +7 -6
  312. qiskit/transpiler/preset_passmanagers/__init__.py +4 -228
  313. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +73 -18
  314. qiskit/transpiler/preset_passmanagers/common.py +3 -6
  315. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +518 -0
  316. qiskit/transpiler/preset_passmanagers/level0.py +1 -1
  317. qiskit/transpiler/target.py +27 -8
  318. qiskit/user_config.py +29 -6
  319. qiskit/utils/classtools.py +3 -3
  320. qiskit/utils/deprecation.py +3 -2
  321. qiskit/utils/lazy_tester.py +2 -2
  322. qiskit/utils/optionals.py +8 -8
  323. qiskit/visualization/bloch.py +62 -24
  324. qiskit/visualization/circuit/_utils.py +34 -10
  325. qiskit/visualization/circuit/circuit_visualization.py +23 -16
  326. qiskit/visualization/circuit/latex.py +29 -27
  327. qiskit/visualization/circuit/matplotlib.py +4 -2
  328. qiskit/visualization/circuit/qcstyle.py +2 -2
  329. qiskit/visualization/circuit/text.py +9 -15
  330. qiskit/visualization/dag_visualization.py +12 -5
  331. qiskit/visualization/pass_manager_visualization.py +9 -9
  332. qiskit/visualization/pulse_v2/core.py +1 -1
  333. qiskit/visualization/pulse_v2/events.py +1 -1
  334. qiskit/visualization/pulse_v2/generators/frame.py +3 -4
  335. qiskit/visualization/pulse_v2/generators/waveform.py +5 -9
  336. qiskit/visualization/pulse_v2/layouts.py +1 -5
  337. qiskit/visualization/pulse_v2/plotters/matplotlib.py +1 -2
  338. qiskit/visualization/state_visualization.py +5 -6
  339. qiskit/visualization/timeline/plotters/matplotlib.py +1 -2
  340. qiskit/visualization/transition_visualization.py +7 -2
  341. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/METADATA +28 -28
  342. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/RECORD +346 -344
  343. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/WHEEL +1 -1
  344. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/entry_points.txt +3 -0
  345. qiskit/transpiler/passes/utils/block_to_matrix.py +0 -47
  346. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/LICENSE.txt +0 -0
  347. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/top_level.txt +0 -0
@@ -12,12 +12,17 @@
12
12
 
13
13
  """A product formula base for decomposing non-commuting operator exponentials."""
14
14
 
15
- from typing import Callable, Optional, Union, Any, Dict
15
+ from __future__ import annotations
16
+
17
+ import inspect
18
+ from collections.abc import Callable
19
+ from typing import Any
16
20
  from functools import partial
17
21
  import numpy as np
18
22
  from qiskit.circuit.parameterexpression import ParameterExpression
19
23
  from qiskit.circuit.quantumcircuit import QuantumCircuit
20
24
  from qiskit.quantum_info import SparsePauliOp, Pauli
25
+ from qiskit.utils.deprecation import deprecate_arg
21
26
 
22
27
  from .evolution_synthesis import EvolutionSynthesis
23
28
 
@@ -28,15 +33,33 @@ class ProductFormula(EvolutionSynthesis):
28
33
  :obj:`.LieTrotter` and :obj:`.SuzukiTrotter` inherit from this class.
29
34
  """
30
35
 
36
+ @deprecate_arg(
37
+ name="atomic_evolution",
38
+ since="1.2",
39
+ predicate=lambda callable: callable is not None
40
+ and len(inspect.signature(callable).parameters) == 2,
41
+ deprecation_description=(
42
+ "The 'Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]' signature of the "
43
+ "'atomic_evolution' argument"
44
+ ),
45
+ additional_msg=(
46
+ "Instead you should update your 'atomic_evolution' function to be of the following "
47
+ "type: 'Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]'."
48
+ ),
49
+ pending=True,
50
+ )
31
51
  def __init__(
32
52
  self,
33
53
  order: int,
34
54
  reps: int = 1,
35
55
  insert_barriers: bool = False,
36
56
  cx_structure: str = "chain",
37
- atomic_evolution: Optional[
38
- Callable[[Union[Pauli, SparsePauliOp], float], QuantumCircuit]
39
- ] = None,
57
+ atomic_evolution: (
58
+ Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]
59
+ | Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
60
+ | None
61
+ ) = None,
62
+ wrap: bool = False,
40
63
  ) -> None:
41
64
  """
42
65
  Args:
@@ -45,10 +68,18 @@ class ProductFormula(EvolutionSynthesis):
45
68
  insert_barriers: Whether to insert barriers between the atomic evolutions.
46
69
  cx_structure: How to arrange the CX gates for the Pauli evolutions, can be
47
70
  ``"chain"``, where next neighbor connections are used, or ``"fountain"``,
48
- where all qubits are connected to one.
49
- atomic_evolution: A function to construct the circuit for the evolution of single
50
- Pauli string. Per default, a single Pauli evolution is decomposed in a CX chain
51
- and a single qubit Z rotation.
71
+ where all qubits are connected to one. This only takes effect when
72
+ ``atomic_evolution is None``.
73
+ atomic_evolution: A function to apply the evolution of a single :class:`.Pauli`, or
74
+ :class:`.SparsePauliOp` of only commuting terms, to a circuit. The function takes in
75
+ three arguments: the circuit to append the evolution to, the Pauli operator to
76
+ evolve, and the evolution time. By default, a single Pauli evolution is decomposed
77
+ into a chain of ``CX`` gates and a single ``RZ`` gate.
78
+ Alternatively, the function can also take Pauli operator and evolution time as
79
+ inputs and returns the circuit that will be appended to the overall circuit being
80
+ built.
81
+ wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
82
+ effect when ``atomic_evolution is None``.
52
83
  """
53
84
  super().__init__()
54
85
  self.order = order
@@ -58,15 +89,27 @@ class ProductFormula(EvolutionSynthesis):
58
89
  # user-provided atomic evolution, stored for serialization
59
90
  self._atomic_evolution = atomic_evolution
60
91
  self._cx_structure = cx_structure
92
+ self._wrap = wrap
61
93
 
62
94
  # if atomic evolution is not provided, set a default
63
95
  if atomic_evolution is None:
64
- atomic_evolution = partial(_default_atomic_evolution, cx_structure=cx_structure)
96
+ self.atomic_evolution = partial(
97
+ _default_atomic_evolution, cx_structure=cx_structure, wrap=wrap
98
+ )
99
+
100
+ elif len(inspect.signature(atomic_evolution).parameters) == 2:
101
+
102
+ def wrap_atomic_evolution(output, operator, time):
103
+ definition = atomic_evolution(operator, time)
104
+ output.compose(definition, wrap=wrap, inplace=True)
105
+
106
+ self.atomic_evolution = wrap_atomic_evolution
65
107
 
66
- self.atomic_evolution = atomic_evolution
108
+ else:
109
+ self.atomic_evolution = atomic_evolution
67
110
 
68
111
  @property
69
- def settings(self) -> Dict[str, Any]:
112
+ def settings(self) -> dict[str, Any]:
70
113
  """Return the settings in a dictionary, which can be used to reconstruct the object.
71
114
 
72
115
  Returns:
@@ -85,15 +128,18 @@ class ProductFormula(EvolutionSynthesis):
85
128
  "reps": self.reps,
86
129
  "insert_barriers": self.insert_barriers,
87
130
  "cx_structure": self._cx_structure,
131
+ "wrap": self._wrap,
88
132
  }
89
133
 
90
134
 
91
135
  def evolve_pauli(
136
+ output: QuantumCircuit,
92
137
  pauli: Pauli,
93
- time: Union[float, ParameterExpression] = 1.0,
138
+ time: float | ParameterExpression = 1.0,
94
139
  cx_structure: str = "chain",
95
- label: Optional[str] = None,
96
- ) -> QuantumCircuit:
140
+ wrap: bool = False,
141
+ label: str | None = None,
142
+ ) -> None:
97
143
  r"""Construct a circuit implementing the time evolution of a single Pauli string.
98
144
 
99
145
  For a Pauli string :math:`P = \{I, X, Y, Z\}^{\otimes n}` on :math:`n` qubits and an
@@ -106,79 +152,91 @@ def evolve_pauli(
106
152
  Since only a single Pauli string is evolved the circuit decomposition is exact.
107
153
 
108
154
  Args:
155
+ output: The circuit object to which to append the evolved Pauli.
109
156
  pauli: The Pauli to evolve.
110
157
  time: The evolution time.
111
158
  cx_structure: Determine the structure of CX gates, can be either ``"chain"`` for
112
159
  next-neighbor connections or ``"fountain"`` to connect directly to the top qubit.
160
+ wrap: Whether to wrap the single Pauli evolutions into custom gate objects.
113
161
  label: A label for the gate.
114
-
115
- Returns:
116
- A quantum circuit implementing the time evolution of the Pauli.
117
162
  """
118
163
  num_non_identity = len([label for label in pauli.to_label() if label != "I"])
119
164
 
120
165
  # first check, if the Pauli is only the identity, in which case the evolution only
121
166
  # adds a global phase
122
167
  if num_non_identity == 0:
123
- definition = QuantumCircuit(pauli.num_qubits, global_phase=-time)
168
+ output.global_phase -= time
124
169
  # if we evolve on a single qubit, if yes use the corresponding qubit rotation
125
170
  elif num_non_identity == 1:
126
- definition = _single_qubit_evolution(pauli, time)
171
+ _single_qubit_evolution(output, pauli, time, wrap)
127
172
  # same for two qubits, use Qiskit's native rotations
128
173
  elif num_non_identity == 2:
129
- definition = _two_qubit_evolution(pauli, time, cx_structure)
174
+ _two_qubit_evolution(output, pauli, time, cx_structure, wrap)
130
175
  # otherwise do basis transformation and CX chains
131
176
  else:
132
- definition = _multi_qubit_evolution(pauli, time, cx_structure)
133
-
134
- definition.name = f"exp(it {pauli.to_label()})"
177
+ _multi_qubit_evolution(output, pauli, time, cx_structure, wrap)
135
178
 
136
- return definition
137
179
 
138
-
139
- def _single_qubit_evolution(pauli, time):
140
- definition = QuantumCircuit(pauli.num_qubits)
180
+ def _single_qubit_evolution(output, pauli, time, wrap):
181
+ dest = QuantumCircuit(1) if wrap else output
141
182
  # Note that all phases are removed from the pauli label and are only in the coefficients.
142
183
  # That's because the operators we evolved have all been translated to a SparsePauliOp.
184
+ qubits = []
185
+ label = ""
143
186
  for i, pauli_i in enumerate(reversed(pauli.to_label())):
187
+ idx = 0 if wrap else i
144
188
  if pauli_i == "X":
145
- definition.rx(2 * time, i)
189
+ dest.rx(2 * time, idx)
190
+ qubits.append(i)
191
+ label += "X"
146
192
  elif pauli_i == "Y":
147
- definition.ry(2 * time, i)
193
+ dest.ry(2 * time, idx)
194
+ qubits.append(i)
195
+ label += "Y"
148
196
  elif pauli_i == "Z":
149
- definition.rz(2 * time, i)
197
+ dest.rz(2 * time, idx)
198
+ qubits.append(i)
199
+ label += "Z"
150
200
 
151
- return definition
201
+ if wrap:
202
+ gate = dest.to_gate(label=f"exp(it {label})")
203
+ qubits = [output.qubits[q] for q in qubits]
204
+ output.append(gate, qargs=qubits, copy=False)
152
205
 
153
206
 
154
- def _two_qubit_evolution(pauli, time, cx_structure):
207
+ def _two_qubit_evolution(output, pauli, time, cx_structure, wrap):
155
208
  # Get the Paulis and the qubits they act on.
156
209
  # Note that all phases are removed from the pauli label and are only in the coefficients.
157
210
  # That's because the operators we evolved have all been translated to a SparsePauliOp.
158
211
  labels_as_array = np.array(list(reversed(pauli.to_label())))
159
212
  qubits = np.where(labels_as_array != "I")[0]
213
+ indices = [0, 1] if wrap else qubits
160
214
  labels = np.array([labels_as_array[idx] for idx in qubits])
161
215
 
162
- definition = QuantumCircuit(pauli.num_qubits)
216
+ dest = QuantumCircuit(2) if wrap else output
163
217
 
164
218
  # go through all cases we have implemented in Qiskit
165
219
  if all(labels == "X"): # RXX
166
- definition.rxx(2 * time, qubits[0], qubits[1])
220
+ dest.rxx(2 * time, indices[0], indices[1])
167
221
  elif all(labels == "Y"): # RYY
168
- definition.ryy(2 * time, qubits[0], qubits[1])
222
+ dest.ryy(2 * time, indices[0], indices[1])
169
223
  elif all(labels == "Z"): # RZZ
170
- definition.rzz(2 * time, qubits[0], qubits[1])
224
+ dest.rzz(2 * time, indices[0], indices[1])
171
225
  elif labels[0] == "Z" and labels[1] == "X": # RZX
172
- definition.rzx(2 * time, qubits[0], qubits[1])
226
+ dest.rzx(2 * time, indices[0], indices[1])
173
227
  elif labels[0] == "X" and labels[1] == "Z": # RXZ
174
- definition.rzx(2 * time, qubits[1], qubits[0])
228
+ dest.rzx(2 * time, indices[1], indices[0])
175
229
  else: # all the others are not native in Qiskit, so use default the decomposition
176
- definition = _multi_qubit_evolution(pauli, time, cx_structure)
230
+ _multi_qubit_evolution(output, pauli, time, cx_structure, wrap)
231
+ return
177
232
 
178
- return definition
233
+ if wrap:
234
+ gate = dest.to_gate(label=f"exp(it {''.join(labels)})")
235
+ qubits = [output.qubits[q] for q in qubits]
236
+ output.append(gate, qargs=qubits, copy=False)
179
237
 
180
238
 
181
- def _multi_qubit_evolution(pauli, time, cx_structure):
239
+ def _multi_qubit_evolution(output, pauli, time, cx_structure, wrap):
182
240
  # get diagonalizing clifford
183
241
  cliff = diagonalizing_clifford(pauli)
184
242
 
@@ -198,14 +256,16 @@ def _multi_qubit_evolution(pauli, time, cx_structure):
198
256
  break
199
257
 
200
258
  # build the evolution as: diagonalization, reduction, 1q evolution, followed by inverses
201
- definition = QuantumCircuit(pauli.num_qubits)
202
- definition.compose(cliff, inplace=True)
203
- definition.compose(chain, inplace=True)
204
- definition.rz(2 * time, target)
205
- definition.compose(chain.inverse(), inplace=True)
206
- definition.compose(cliff.inverse(), inplace=True)
259
+ dest = QuantumCircuit(pauli.num_qubits) if wrap else output
260
+ dest.compose(cliff, inplace=True)
261
+ dest.compose(chain, inplace=True)
262
+ dest.rz(2 * time, target)
263
+ dest.compose(chain.inverse(), inplace=True)
264
+ dest.compose(cliff.inverse(), inplace=True)
207
265
 
208
- return definition
266
+ if wrap:
267
+ gate = dest.to_gate(label=f"exp(it {pauli.to_label()})")
268
+ output.append(gate, qargs=output.qubits, copy=False)
209
269
 
210
270
 
211
271
  def diagonalizing_clifford(pauli: Pauli) -> QuantumCircuit:
@@ -313,16 +373,12 @@ def cnot_fountain(pauli: Pauli) -> QuantumCircuit:
313
373
  return chain
314
374
 
315
375
 
316
- def _default_atomic_evolution(operator, time, cx_structure):
376
+ def _default_atomic_evolution(output, operator, time, cx_structure, wrap):
317
377
  if isinstance(operator, Pauli):
318
378
  # single Pauli operator: just exponentiate it
319
- evolution_circuit = evolve_pauli(operator, time, cx_structure)
379
+ evolve_pauli(output, operator, time, cx_structure, wrap)
320
380
  else:
321
381
  # sum of Pauli operators: exponentiate each term (this assumes they commute)
322
382
  pauli_list = [(Pauli(op), np.real(coeff)) for op, coeff in operator.to_list()]
323
- name = f"exp(it {[pauli.to_label() for pauli, _ in pauli_list]})"
324
- evolution_circuit = QuantumCircuit(operator.num_qubits, name=name)
325
383
  for pauli, coeff in pauli_list:
326
- evolution_circuit.compose(evolve_pauli(pauli, coeff * time, cx_structure), inplace=True)
327
-
328
- return evolution_circuit
384
+ evolve_pauli(output, pauli, coeff * time, cx_structure, wrap)
@@ -12,11 +12,15 @@
12
12
 
13
13
  """QDrift Class"""
14
14
 
15
+ from __future__ import annotations
16
+
17
+ import inspect
15
18
  import math
16
- from typing import Union, Optional, Callable
19
+ from collections.abc import Callable
17
20
  import numpy as np
18
21
  from qiskit.circuit.quantumcircuit import QuantumCircuit
19
22
  from qiskit.quantum_info.operators import SparsePauliOp, Pauli
23
+ from qiskit.utils.deprecation import deprecate_arg
20
24
 
21
25
  from .product_formula import ProductFormula
22
26
  from .lie_trotter import LieTrotter
@@ -32,15 +36,33 @@ class QDrift(ProductFormula):
32
36
  `arXiv:quant-ph/1811.08017 <https://arxiv.org/abs/1811.08017>`_
33
37
  """
34
38
 
39
+ @deprecate_arg(
40
+ name="atomic_evolution",
41
+ since="1.2",
42
+ predicate=lambda callable: callable is not None
43
+ and len(inspect.signature(callable).parameters) == 2,
44
+ deprecation_description=(
45
+ "The 'Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]' signature of the "
46
+ "'atomic_evolution' argument"
47
+ ),
48
+ additional_msg=(
49
+ "Instead you should update your 'atomic_evolution' function to be of the following "
50
+ "type: 'Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]'."
51
+ ),
52
+ pending=True,
53
+ )
35
54
  def __init__(
36
55
  self,
37
56
  reps: int = 1,
38
57
  insert_barriers: bool = False,
39
58
  cx_structure: str = "chain",
40
- atomic_evolution: Optional[
41
- Callable[[Union[Pauli, SparsePauliOp], float], QuantumCircuit]
42
- ] = None,
43
- seed: Optional[int] = None,
59
+ atomic_evolution: (
60
+ Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]
61
+ | Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
62
+ | None
63
+ ) = None,
64
+ seed: int | None = None,
65
+ wrap: bool = False,
44
66
  ) -> None:
45
67
  r"""
46
68
  Args:
@@ -48,13 +70,21 @@ class QDrift(ProductFormula):
48
70
  insert_barriers: Whether to insert barriers between the atomic evolutions.
49
71
  cx_structure: How to arrange the CX gates for the Pauli evolutions, can be
50
72
  ``"chain"``, where next neighbor connections are used, or ``"fountain"``, where all
51
- qubits are connected to one.
52
- atomic_evolution: A function to construct the circuit for the evolution of single
53
- Pauli string. Per default, a single Pauli evolution is decomposed in a CX chain
54
- and a single qubit Z rotation.
73
+ qubits are connected to one. This only takes effect when
74
+ ``atomic_evolution is None``.
75
+ atomic_evolution: A function to apply the evolution of a single :class:`.Pauli`, or
76
+ :class:`.SparsePauliOp` of only commuting terms, to a circuit. The function takes in
77
+ three arguments: the circuit to append the evolution to, the Pauli operator to
78
+ evolve, and the evolution time. By default, a single Pauli evolution is decomposed
79
+ into a chain of ``CX`` gates and a single ``RZ`` gate.
80
+ Alternatively, the function can also take Pauli operator and evolution time as
81
+ inputs and returns the circuit that will be appended to the overall circuit being
82
+ built.
55
83
  seed: An optional seed for reproducibility of the random sampling process.
84
+ wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
85
+ effect when ``atomic_evolution is None``.
56
86
  """
57
- super().__init__(1, reps, insert_barriers, cx_structure, atomic_evolution)
87
+ super().__init__(1, reps, insert_barriers, cx_structure, atomic_evolution, wrap)
58
88
  self.sampled_ops = None
59
89
  self.rng = np.random.default_rng(seed)
60
90
 
@@ -12,12 +12,16 @@
12
12
 
13
13
  """The Suzuki-Trotter product formula."""
14
14
 
15
- from typing import Callable, Optional, Union
15
+ from __future__ import annotations
16
+
17
+ import inspect
18
+ from collections.abc import Callable
16
19
 
17
20
  import numpy as np
18
21
 
19
22
  from qiskit.circuit.quantumcircuit import QuantumCircuit
20
23
  from qiskit.quantum_info.operators import SparsePauliOp, Pauli
24
+ from qiskit.utils.deprecation import deprecate_arg
21
25
 
22
26
 
23
27
  from .product_formula import ProductFormula
@@ -51,15 +55,33 @@ class SuzukiTrotter(ProductFormula):
51
55
  `arXiv:math-ph/0506007 <https://arxiv.org/pdf/math-ph/0506007.pdf>`_
52
56
  """
53
57
 
58
+ @deprecate_arg(
59
+ name="atomic_evolution",
60
+ since="1.2",
61
+ predicate=lambda callable: callable is not None
62
+ and len(inspect.signature(callable).parameters) == 2,
63
+ deprecation_description=(
64
+ "The 'Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]' signature of the "
65
+ "'atomic_evolution' argument"
66
+ ),
67
+ additional_msg=(
68
+ "Instead you should update your 'atomic_evolution' function to be of the following "
69
+ "type: 'Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]'."
70
+ ),
71
+ pending=True,
72
+ )
54
73
  def __init__(
55
74
  self,
56
75
  order: int = 2,
57
76
  reps: int = 1,
58
77
  insert_barriers: bool = False,
59
78
  cx_structure: str = "chain",
60
- atomic_evolution: Optional[
61
- Callable[[Union[Pauli, SparsePauliOp], float], QuantumCircuit]
62
- ] = None,
79
+ atomic_evolution: (
80
+ Callable[[Pauli | SparsePauliOp, float], QuantumCircuit]
81
+ | Callable[[QuantumCircuit, Pauli | SparsePauliOp, float], None]
82
+ | None
83
+ ) = None,
84
+ wrap: bool = False,
63
85
  ) -> None:
64
86
  """
65
87
  Args:
@@ -68,10 +90,17 @@ class SuzukiTrotter(ProductFormula):
68
90
  insert_barriers: Whether to insert barriers between the atomic evolutions.
69
91
  cx_structure: How to arrange the CX gates for the Pauli evolutions, can be ``"chain"``,
70
92
  where next neighbor connections are used, or ``"fountain"``, where all qubits are
71
- connected to one.
72
- atomic_evolution: A function to construct the circuit for the evolution of single
73
- Pauli string. Per default, a single Pauli evolution is decomposed in a CX chain
74
- and a single qubit Z rotation.
93
+ connected to one. This only takes effect when ``atomic_evolution is None``.
94
+ atomic_evolution: A function to apply the evolution of a single :class:`.Pauli`, or
95
+ :class:`.SparsePauliOp` of only commuting terms, to a circuit. The function takes in
96
+ three arguments: the circuit to append the evolution to, the Pauli operator to
97
+ evolve, and the evolution time. By default, a single Pauli evolution is decomposed
98
+ into a chain of ``CX`` gates and a single ``RZ`` gate.
99
+ Alternatively, the function can also take Pauli operator and evolution time as
100
+ inputs and returns the circuit that will be appended to the overall circuit being
101
+ built.
102
+ wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
103
+ effect when ``atomic_evolution is None``.
75
104
  Raises:
76
105
  ValueError: If order is not even
77
106
  """
@@ -81,7 +110,7 @@ class SuzukiTrotter(ProductFormula):
81
110
  "Suzuki product formulae are symmetric and therefore only defined "
82
111
  "for even orders."
83
112
  )
84
- super().__init__(order, reps, insert_barriers, cx_structure, atomic_evolution)
113
+ super().__init__(order, reps, insert_barriers, cx_structure, atomic_evolution, wrap)
85
114
 
86
115
  def synthesize(self, evolution):
87
116
  # get operators and time to evolve
@@ -97,32 +126,13 @@ class SuzukiTrotter(ProductFormula):
97
126
 
98
127
  # construct the evolution circuit
99
128
  single_rep = QuantumCircuit(operators[0].num_qubits)
100
- first_barrier = False
101
-
102
- for op, coeff in ops_to_evolve:
103
- # add barriers
104
- if first_barrier:
105
- if self.insert_barriers:
106
- single_rep.barrier()
107
- else:
108
- first_barrier = True
109
-
110
- single_rep.compose(self.atomic_evolution(op, coeff), wrap=True, inplace=True)
111
-
112
- evolution_circuit = QuantumCircuit(operators[0].num_qubits)
113
- first_barrier = False
114
-
115
- for _ in range(self.reps):
116
- # add barriers
117
- if first_barrier:
118
- if self.insert_barriers:
119
- single_rep.barrier()
120
- else:
121
- first_barrier = True
122
129
 
123
- evolution_circuit.compose(single_rep, inplace=True)
130
+ for i, (op, coeff) in enumerate(ops_to_evolve):
131
+ self.atomic_evolution(single_rep, op, coeff)
132
+ if self.insert_barriers and i != len(ops_to_evolve) - 1:
133
+ single_rep.barrier()
124
134
 
125
- return evolution_circuit
135
+ return single_rep.repeat(self.reps, insert_barriers=self.insert_barriers).decompose()
126
136
 
127
137
  @staticmethod
128
138
  def _recurse(order, time, pauli_list):
@@ -18,6 +18,7 @@ from .linear_matrix_utils import (
18
18
  random_invertible_binary_matrix,
19
19
  calc_inverse_matrix,
20
20
  check_invertible_binary_matrix,
21
+ binary_matmul,
21
22
  )
22
23
 
23
24
  # This is re-import is kept for compatibility with Terra 0.23. Eligible for deprecation in 0.25+.
@@ -17,33 +17,37 @@ for optimal synthesis of linear (CNOT-only) reversible circuits.
17
17
  """
18
18
 
19
19
  from __future__ import annotations
20
- import copy
20
+
21
21
  import numpy as np
22
22
  from qiskit.circuit import QuantumCircuit
23
- from qiskit.exceptions import QiskitError
23
+
24
+ from qiskit._accelerate.synthesis.linear import synth_cnot_count_full_pmh as fast_pmh
24
25
 
25
26
 
26
27
  def synth_cnot_count_full_pmh(
27
- state: list[list[bool]] | np.ndarray[bool], section_size: int = 2
28
+ state: list[list[bool]] | np.ndarray[bool], section_size: int | None = None
28
29
  ) -> QuantumCircuit:
29
- """
30
+ r"""
30
31
  Synthesize linear reversible circuits for all-to-all architecture
31
32
  using Patel, Markov and Hayes method.
32
33
 
33
34
  This function is an implementation of the Patel, Markov and Hayes algorithm from [1]
34
35
  for optimal synthesis of linear reversible circuits for all-to-all architecture,
35
- as specified by an :math:`n \\times n` matrix.
36
+ as specified by an :math:`n \times n` matrix.
36
37
 
37
38
  Args:
38
- state: :math:`n \\times n` boolean invertible matrix, describing
39
- the state of the input circuit
39
+ state: :math:`n \times n` boolean invertible matrix, describing
40
+ the state of the input circuit.
40
41
  section_size: The size of each section in the Patel–Markov–Hayes algorithm [1].
42
+ If ``None`` it is chosen to be :math:`\max(2, \alpha\log_2(n))` with
43
+ :math:`\alpha = 0.56`, which approximately minimizes the upper bound on the number
44
+ of row operations given in [1] Eq. (3).
41
45
 
42
46
  Returns:
43
- QuantumCircuit: a CX-only circuit implementing the linear transformation.
47
+ A CX-only circuit implementing the linear transformation.
44
48
 
45
49
  Raises:
46
- QiskitError: when variable ``state`` isn't of type ``numpy.ndarray``
50
+ ValueError: When ``section_size`` is larger than the number of columns.
47
51
 
48
52
  References:
49
53
  1. Patel, Ketan N., Igor L. Markov, and John P. Hayes,
@@ -51,93 +55,15 @@ def synth_cnot_count_full_pmh(
51
55
  Quantum Information & Computation 8.3 (2008): 282-294.
52
56
  `arXiv:quant-ph/0302002 [quant-ph] <https://arxiv.org/abs/quant-ph/0302002>`_
53
57
  """
54
- if not isinstance(state, (list, np.ndarray)):
55
- raise QiskitError(
56
- "state should be of type list or numpy.ndarray, "
57
- "but was of the type {}".format(type(state))
58
+ normalized = np.asarray(state).astype(bool)
59
+ if section_size is not None and normalized.shape[1] < section_size:
60
+ raise ValueError(
61
+ f"The section_size ({section_size}) cannot be larger than the number of columns "
62
+ f"({normalized.shape[1]})."
58
63
  )
59
- state = np.array(state)
60
- # Synthesize lower triangular part
61
- [state, circuit_l] = _lwr_cnot_synth(state, section_size)
62
- state = np.transpose(state)
63
- # Synthesize upper triangular part
64
- [state, circuit_u] = _lwr_cnot_synth(state, section_size)
65
- circuit_l.reverse()
66
- for i in circuit_u:
67
- i.reverse()
68
- # Convert the list into a circuit of C-NOT gates
69
- circ = QuantumCircuit(state.shape[0])
70
- for i in circuit_u + circuit_l:
71
- circ.cx(i[0], i[1])
72
- return circ
73
-
74
-
75
- def _lwr_cnot_synth(state, section_size):
76
- """
77
- This function is a helper function of the algorithm for optimal synthesis
78
- of linear reversible circuits (the Patel–Markov–Hayes algorithm). It works
79
- like gaussian elimination, except that it works a lot faster, and requires
80
- fewer steps (and therefore fewer CNOTs). It takes the matrix "state" and
81
- splits it into sections of size section_size. Then it eliminates all non-zero
82
- sub-rows within each section, which are the same as a non-zero sub-row
83
- above. Once this has been done, it continues with normal gaussian elimination.
84
- The benefit is that with small section sizes (m), most of the sub-rows will
85
- be cleared in the first step, resulting in a factor m fewer row row operations
86
- during Gaussian elimination.
87
64
 
88
- The algorithm is described in detail in the following paper
89
- "Optimal synthesis of linear reversible circuits."
90
- Patel, Ketan N., Igor L. Markov, and John P. Hayes.
91
- Quantum Information & Computation 8.3 (2008): 282-294.
92
-
93
- Note:
94
- This implementation tweaks the Patel, Markov, and Hayes algorithm by adding
95
- a "back reduce" which adds rows below the pivot row with a high degree of
96
- overlap back to it. The intuition is to avoid a high-weight pivot row
97
- increasing the weight of lower rows.
98
-
99
- Args:
100
- state (ndarray): n x n matrix, describing a linear quantum circuit
101
- section_size (int): the section size the matrix columns are divided into
102
-
103
- Returns:
104
- numpy.matrix: n by n matrix, describing the state of the output circuit
105
- list: a k by 2 list of C-NOT operations that need to be applied
106
- """
107
- circuit = []
108
- num_qubits = state.shape[0]
109
- cutoff = 1
65
+ # call Rust implementation with normalized input
66
+ circuit_data = fast_pmh(normalized, section_size)
110
67
 
111
- # Iterate over column sections
112
- for sec in range(1, int(np.floor(num_qubits / section_size) + 1)):
113
- # Remove duplicate sub-rows in section sec
114
- patt = {}
115
- for row in range((sec - 1) * section_size, num_qubits):
116
- sub_row_patt = copy.deepcopy(state[row, (sec - 1) * section_size : sec * section_size])
117
- if np.sum(sub_row_patt) == 0:
118
- continue
119
- if str(sub_row_patt) not in patt:
120
- patt[str(sub_row_patt)] = row
121
- else:
122
- state[row, :] ^= state[patt[str(sub_row_patt)], :]
123
- circuit.append([patt[str(sub_row_patt)], row])
124
- # Use gaussian elimination for remaining entries in column section
125
- for col in range((sec - 1) * section_size, sec * section_size):
126
- # Check if 1 on diagonal
127
- diag_one = 1
128
- if state[col, col] == 0:
129
- diag_one = 0
130
- # Remove ones in rows below column col
131
- for row in range(col + 1, num_qubits):
132
- if state[row, col] == 1:
133
- if diag_one == 0:
134
- state[col, :] ^= state[row, :]
135
- circuit.append([row, col])
136
- diag_one = 1
137
- state[row, :] ^= state[col, :]
138
- circuit.append([col, row])
139
- # Back reduce the pivot row using the current row
140
- if sum(state[col, :] & state[row, :]) > cutoff:
141
- state[col, :] ^= state[row, :]
142
- circuit.append([row, col])
143
- return [state, circuit]
68
+ # construct circuit from the data
69
+ return QuantumCircuit._from_circuit_data(circuit_data)