qiskit 1.0.2__cp38-abi3-win32.whl → 1.1.0__cp38-abi3-win32.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 (263) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +27 -16
  3. qiskit/_accelerate.pyd +0 -0
  4. qiskit/_numpy_compat.py +73 -0
  5. qiskit/assembler/__init__.py +5 -10
  6. qiskit/assembler/disassemble.py +5 -6
  7. qiskit/circuit/__init__.py +1061 -232
  8. qiskit/circuit/_classical_resource_map.py +10 -6
  9. qiskit/circuit/_utils.py +18 -8
  10. qiskit/circuit/annotated_operation.py +21 -0
  11. qiskit/circuit/barrier.py +10 -13
  12. qiskit/circuit/bit.py +0 -1
  13. qiskit/circuit/classical/__init__.py +2 -2
  14. qiskit/circuit/classical/expr/__init__.py +39 -5
  15. qiskit/circuit/classical/expr/constructors.py +84 -1
  16. qiskit/circuit/classical/expr/expr.py +83 -13
  17. qiskit/circuit/classical/expr/visitors.py +83 -0
  18. qiskit/circuit/classical/types/__init__.py +5 -4
  19. qiskit/circuit/classicalfunction/__init__.py +1 -0
  20. qiskit/circuit/commutation_checker.py +86 -51
  21. qiskit/circuit/controlflow/_builder_utils.py +9 -1
  22. qiskit/circuit/controlflow/break_loop.py +8 -22
  23. qiskit/circuit/controlflow/builder.py +116 -1
  24. qiskit/circuit/controlflow/continue_loop.py +8 -22
  25. qiskit/circuit/controlflow/control_flow.py +47 -8
  26. qiskit/circuit/controlflow/for_loop.py +8 -23
  27. qiskit/circuit/controlflow/if_else.py +13 -27
  28. qiskit/circuit/controlflow/switch_case.py +14 -21
  29. qiskit/circuit/controlflow/while_loop.py +9 -23
  30. qiskit/circuit/controlledgate.py +2 -2
  31. qiskit/circuit/delay.py +7 -5
  32. qiskit/circuit/gate.py +20 -7
  33. qiskit/circuit/instruction.py +31 -30
  34. qiskit/circuit/instructionset.py +9 -22
  35. qiskit/circuit/library/__init__.py +3 -13
  36. qiskit/circuit/library/arithmetic/integer_comparator.py +2 -2
  37. qiskit/circuit/library/arithmetic/quadratic_form.py +3 -2
  38. qiskit/circuit/library/blueprintcircuit.py +29 -7
  39. qiskit/circuit/library/data_preparation/state_preparation.py +6 -5
  40. qiskit/circuit/library/generalized_gates/diagonal.py +5 -4
  41. qiskit/circuit/library/generalized_gates/isometry.py +51 -254
  42. qiskit/circuit/library/generalized_gates/pauli.py +2 -2
  43. qiskit/circuit/library/generalized_gates/permutation.py +4 -1
  44. qiskit/circuit/library/generalized_gates/rv.py +15 -11
  45. qiskit/circuit/library/generalized_gates/uc.py +2 -98
  46. qiskit/circuit/library/generalized_gates/unitary.py +9 -4
  47. qiskit/circuit/library/hamiltonian_gate.py +11 -5
  48. qiskit/circuit/library/n_local/efficient_su2.py +5 -5
  49. qiskit/circuit/library/n_local/n_local.py +100 -49
  50. qiskit/circuit/library/n_local/two_local.py +3 -59
  51. qiskit/circuit/library/overlap.py +3 -3
  52. qiskit/circuit/library/phase_oracle.py +1 -1
  53. qiskit/circuit/library/quantum_volume.py +39 -38
  54. qiskit/circuit/library/standard_gates/equivalence_library.py +50 -0
  55. qiskit/circuit/library/standard_gates/global_phase.py +4 -2
  56. qiskit/circuit/library/standard_gates/i.py +1 -2
  57. qiskit/circuit/library/standard_gates/iswap.py +1 -2
  58. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +11 -5
  59. qiskit/circuit/library/standard_gates/p.py +31 -15
  60. qiskit/circuit/library/standard_gates/r.py +4 -3
  61. qiskit/circuit/library/standard_gates/rx.py +7 -4
  62. qiskit/circuit/library/standard_gates/rxx.py +4 -3
  63. qiskit/circuit/library/standard_gates/ry.py +7 -4
  64. qiskit/circuit/library/standard_gates/ryy.py +4 -3
  65. qiskit/circuit/library/standard_gates/rz.py +7 -4
  66. qiskit/circuit/library/standard_gates/rzx.py +4 -3
  67. qiskit/circuit/library/standard_gates/rzz.py +4 -3
  68. qiskit/circuit/library/standard_gates/s.py +4 -8
  69. qiskit/circuit/library/standard_gates/t.py +2 -4
  70. qiskit/circuit/library/standard_gates/u.py +16 -11
  71. qiskit/circuit/library/standard_gates/u1.py +6 -2
  72. qiskit/circuit/library/standard_gates/u2.py +4 -2
  73. qiskit/circuit/library/standard_gates/u3.py +9 -5
  74. qiskit/circuit/library/standard_gates/x.py +22 -11
  75. qiskit/circuit/library/standard_gates/xx_minus_yy.py +4 -3
  76. qiskit/circuit/library/standard_gates/xx_plus_yy.py +7 -5
  77. qiskit/circuit/library/standard_gates/z.py +1 -2
  78. qiskit/circuit/measure.py +4 -1
  79. qiskit/circuit/operation.py +13 -8
  80. qiskit/circuit/parameter.py +11 -6
  81. qiskit/circuit/quantumcircuit.py +1910 -260
  82. qiskit/circuit/quantumcircuitdata.py +2 -2
  83. qiskit/circuit/reset.py +5 -2
  84. qiskit/circuit/store.py +95 -0
  85. qiskit/compiler/assembler.py +22 -22
  86. qiskit/compiler/transpiler.py +63 -112
  87. qiskit/converters/__init__.py +17 -2
  88. qiskit/converters/circuit_to_dag.py +7 -0
  89. qiskit/converters/circuit_to_dagdependency_v2.py +47 -0
  90. qiskit/converters/circuit_to_gate.py +2 -0
  91. qiskit/converters/circuit_to_instruction.py +22 -0
  92. qiskit/converters/dag_to_circuit.py +4 -0
  93. qiskit/converters/dag_to_dagdependency_v2.py +44 -0
  94. qiskit/dagcircuit/collect_blocks.py +15 -10
  95. qiskit/dagcircuit/dagcircuit.py +434 -124
  96. qiskit/dagcircuit/dagdependency.py +19 -12
  97. qiskit/dagcircuit/dagdependency_v2.py +641 -0
  98. qiskit/dagcircuit/dagdepnode.py +19 -16
  99. qiskit/dagcircuit/dagnode.py +14 -4
  100. qiskit/passmanager/passmanager.py +11 -11
  101. qiskit/primitives/__init__.py +22 -12
  102. qiskit/primitives/backend_estimator.py +3 -5
  103. qiskit/primitives/backend_estimator_v2.py +410 -0
  104. qiskit/primitives/backend_sampler_v2.py +287 -0
  105. qiskit/primitives/base/base_estimator.py +4 -9
  106. qiskit/primitives/base/base_sampler.py +2 -2
  107. qiskit/primitives/containers/__init__.py +6 -4
  108. qiskit/primitives/containers/bit_array.py +293 -2
  109. qiskit/primitives/containers/data_bin.py +123 -50
  110. qiskit/primitives/containers/estimator_pub.py +10 -3
  111. qiskit/primitives/containers/observables_array.py +2 -2
  112. qiskit/primitives/containers/pub_result.py +1 -1
  113. qiskit/primitives/containers/sampler_pub.py +19 -3
  114. qiskit/primitives/containers/sampler_pub_result.py +74 -0
  115. qiskit/primitives/containers/shape.py +4 -4
  116. qiskit/primitives/statevector_estimator.py +4 -4
  117. qiskit/primitives/statevector_sampler.py +7 -12
  118. qiskit/providers/__init__.py +65 -34
  119. qiskit/providers/backend.py +2 -2
  120. qiskit/providers/backend_compat.py +8 -10
  121. qiskit/providers/basic_provider/__init__.py +2 -23
  122. qiskit/providers/basic_provider/basic_provider_tools.py +67 -31
  123. qiskit/providers/basic_provider/basic_simulator.py +81 -21
  124. qiskit/providers/fake_provider/__init__.py +1 -1
  125. qiskit/providers/fake_provider/fake_1q.py +1 -1
  126. qiskit/providers/fake_provider/fake_backend.py +3 -408
  127. qiskit/providers/fake_provider/generic_backend_v2.py +26 -14
  128. qiskit/providers/models/__init__.py +2 -2
  129. qiskit/providers/provider.py +16 -0
  130. qiskit/pulse/builder.py +4 -1
  131. qiskit/pulse/parameter_manager.py +60 -4
  132. qiskit/pulse/schedule.py +29 -13
  133. qiskit/pulse/utils.py +61 -20
  134. qiskit/qasm2/__init__.py +1 -5
  135. qiskit/qasm2/parse.py +1 -4
  136. qiskit/qasm3/__init__.py +42 -5
  137. qiskit/qasm3/ast.py +19 -0
  138. qiskit/qasm3/exporter.py +178 -106
  139. qiskit/qasm3/printer.py +27 -5
  140. qiskit/qobj/converters/pulse_instruction.py +6 -6
  141. qiskit/qpy/__init__.py +299 -67
  142. qiskit/qpy/binary_io/circuits.py +216 -47
  143. qiskit/qpy/binary_io/schedules.py +42 -36
  144. qiskit/qpy/binary_io/value.py +201 -22
  145. qiskit/qpy/common.py +1 -1
  146. qiskit/qpy/exceptions.py +20 -0
  147. qiskit/qpy/formats.py +29 -0
  148. qiskit/qpy/type_keys.py +21 -0
  149. qiskit/quantum_info/analysis/distance.py +3 -3
  150. qiskit/quantum_info/analysis/make_observable.py +2 -1
  151. qiskit/quantum_info/analysis/z2_symmetries.py +2 -1
  152. qiskit/quantum_info/operators/channel/chi.py +9 -8
  153. qiskit/quantum_info/operators/channel/choi.py +10 -9
  154. qiskit/quantum_info/operators/channel/kraus.py +2 -1
  155. qiskit/quantum_info/operators/channel/ptm.py +10 -9
  156. qiskit/quantum_info/operators/channel/quantum_channel.py +2 -1
  157. qiskit/quantum_info/operators/channel/stinespring.py +2 -1
  158. qiskit/quantum_info/operators/channel/superop.py +12 -11
  159. qiskit/quantum_info/operators/channel/transformations.py +12 -11
  160. qiskit/quantum_info/operators/dihedral/dihedral.py +5 -4
  161. qiskit/quantum_info/operators/operator.py +43 -30
  162. qiskit/quantum_info/operators/scalar_op.py +10 -9
  163. qiskit/quantum_info/operators/symplectic/base_pauli.py +70 -59
  164. qiskit/quantum_info/operators/symplectic/clifford.py +36 -9
  165. qiskit/quantum_info/operators/symplectic/pauli.py +53 -6
  166. qiskit/quantum_info/operators/symplectic/pauli_list.py +36 -14
  167. qiskit/quantum_info/operators/symplectic/random.py +3 -2
  168. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +61 -36
  169. qiskit/quantum_info/states/densitymatrix.py +13 -13
  170. qiskit/quantum_info/states/stabilizerstate.py +3 -3
  171. qiskit/quantum_info/states/statevector.py +14 -13
  172. qiskit/quantum_info/states/utils.py +5 -3
  173. qiskit/result/__init__.py +6 -0
  174. qiskit/result/mitigation/correlated_readout_mitigator.py +3 -2
  175. qiskit/result/mitigation/local_readout_mitigator.py +2 -1
  176. qiskit/result/mitigation/utils.py +3 -2
  177. qiskit/scheduler/__init__.py +10 -1
  178. qiskit/scheduler/methods/__init__.py +1 -8
  179. qiskit/synthesis/__init__.py +3 -6
  180. qiskit/synthesis/discrete_basis/commutator_decompose.py +2 -2
  181. qiskit/synthesis/evolution/lie_trotter.py +7 -14
  182. qiskit/synthesis/evolution/qdrift.py +3 -4
  183. qiskit/synthesis/linear/cnot_synth.py +1 -3
  184. qiskit/synthesis/linear/linear_circuits_utils.py +1 -1
  185. qiskit/synthesis/linear_phase/cz_depth_lnn.py +4 -18
  186. qiskit/synthesis/permutation/__init__.py +1 -0
  187. qiskit/synthesis/permutation/permutation_reverse_lnn.py +90 -0
  188. qiskit/synthesis/qft/qft_decompose_lnn.py +2 -6
  189. qiskit/synthesis/two_qubit/two_qubit_decompose.py +165 -954
  190. qiskit/synthesis/two_qubit/xx_decompose/circuits.py +13 -12
  191. qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +7 -1
  192. qiskit/synthesis/unitary/aqc/__init__.py +1 -1
  193. qiskit/synthesis/unitary/aqc/cnot_structures.py +2 -1
  194. qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +2 -1
  195. qiskit/synthesis/unitary/qsd.py +3 -2
  196. qiskit/transpiler/__init__.py +7 -3
  197. qiskit/transpiler/layout.py +140 -61
  198. qiskit/transpiler/passes/__init__.py +10 -2
  199. qiskit/transpiler/passes/basis/basis_translator.py +9 -4
  200. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
  201. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
  202. qiskit/transpiler/passes/calibration/rzx_builder.py +2 -1
  203. qiskit/transpiler/passes/layout/apply_layout.py +8 -3
  204. qiskit/transpiler/passes/layout/sabre_layout.py +15 -3
  205. qiskit/transpiler/passes/layout/set_layout.py +1 -1
  206. qiskit/transpiler/passes/optimization/__init__.py +2 -0
  207. qiskit/transpiler/passes/optimization/commutation_analysis.py +2 -2
  208. qiskit/transpiler/passes/optimization/commutative_cancellation.py +1 -1
  209. qiskit/transpiler/passes/optimization/consolidate_blocks.py +1 -1
  210. qiskit/transpiler/passes/optimization/cx_cancellation.py +10 -0
  211. qiskit/transpiler/passes/optimization/elide_permutations.py +114 -0
  212. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +9 -3
  213. qiskit/transpiler/passes/optimization/optimize_annotated.py +248 -12
  214. qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
  215. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +1 -3
  216. qiskit/transpiler/passes/routing/__init__.py +1 -0
  217. qiskit/transpiler/passes/routing/basic_swap.py +13 -2
  218. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +8 -1
  219. qiskit/transpiler/passes/routing/lookahead_swap.py +7 -1
  220. qiskit/transpiler/passes/routing/sabre_swap.py +10 -6
  221. qiskit/transpiler/passes/routing/star_prerouting.py +417 -0
  222. qiskit/transpiler/passes/routing/stochastic_swap.py +24 -8
  223. qiskit/transpiler/passes/scheduling/__init__.py +1 -1
  224. qiskit/transpiler/passes/scheduling/alap.py +1 -2
  225. qiskit/transpiler/passes/scheduling/alignments/align_measures.py +1 -2
  226. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +9 -6
  227. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +8 -0
  228. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +13 -4
  229. qiskit/transpiler/passes/scheduling/asap.py +1 -2
  230. qiskit/transpiler/passes/scheduling/base_scheduler.py +21 -2
  231. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +26 -4
  232. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +24 -2
  233. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +28 -4
  234. qiskit/transpiler/passes/synthesis/aqc_plugin.py +2 -2
  235. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +120 -13
  236. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +162 -55
  237. qiskit/transpiler/passes/utils/gates_basis.py +3 -3
  238. qiskit/transpiler/passmanager.py +44 -1
  239. qiskit/transpiler/preset_passmanagers/__init__.py +3 -3
  240. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +34 -16
  241. qiskit/transpiler/preset_passmanagers/common.py +4 -6
  242. qiskit/transpiler/preset_passmanagers/plugin.py +9 -1
  243. qiskit/utils/__init__.py +3 -2
  244. qiskit/utils/optionals.py +6 -2
  245. qiskit/utils/parallel.py +24 -15
  246. qiskit/visualization/array.py +1 -1
  247. qiskit/visualization/bloch.py +2 -3
  248. qiskit/visualization/circuit/matplotlib.py +44 -14
  249. qiskit/visualization/circuit/text.py +38 -18
  250. qiskit/visualization/counts_visualization.py +3 -6
  251. qiskit/visualization/dag_visualization.py +6 -7
  252. qiskit/visualization/gate_map.py +9 -1
  253. qiskit/visualization/pulse_v2/interface.py +8 -3
  254. qiskit/visualization/state_visualization.py +3 -2
  255. qiskit/visualization/timeline/interface.py +18 -8
  256. {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/METADATA +12 -8
  257. {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/RECORD +261 -251
  258. {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/WHEEL +1 -1
  259. qiskit/_qasm2.pyd +0 -0
  260. qiskit/_qasm3.pyd +0 -0
  261. {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/LICENSE.txt +0 -0
  262. {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/entry_points.txt +0 -0
  263. {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/top_level.txt +0 -0
@@ -21,7 +21,6 @@
21
21
 
22
22
  from __future__ import annotations
23
23
 
24
- import cmath
25
24
  import math
26
25
 
27
26
  import numpy as np
@@ -33,14 +32,11 @@ from qiskit.circuit.quantumregister import QuantumRegister
33
32
  from qiskit.circuit.quantumcircuit import QuantumCircuit
34
33
  from qiskit.circuit.exceptions import CircuitError
35
34
  from qiskit.exceptions import QiskitError
36
-
37
- # pylint: disable=cyclic-import
38
- from qiskit.synthesis.one_qubit.one_qubit_decompose import OneQubitEulerDecomposer
35
+ from qiskit._accelerate import uc_gate
39
36
 
40
37
  from .diagonal import Diagonal
41
38
 
42
39
  _EPS = 1e-10 # global variable used to chop very small numbers to zero
43
- _DECOMPOSER1Q = OneQubitEulerDecomposer("U3")
44
40
 
45
41
 
46
42
  class UCGate(Gate):
@@ -203,99 +199,7 @@ class UCGate(Gate):
203
199
  https://arxiv.org/pdf/quant-ph/0410066.pdf.
204
200
  """
205
201
  single_qubit_gates = [gate.astype(complex) for gate in self.params]
206
- diag = np.ones(2**self.num_qubits, dtype=complex)
207
- num_contr = self.num_qubits - 1
208
- for dec_step in range(num_contr):
209
- num_ucgs = 2**dec_step
210
- # The decomposition works recursively and the following loop goes over the different
211
- # UCGates that arise in the decomposition
212
- for ucg_index in range(num_ucgs):
213
- len_ucg = 2 ** (num_contr - dec_step)
214
- for i in range(int(len_ucg / 2)):
215
- shift = ucg_index * len_ucg
216
- a = single_qubit_gates[shift + i]
217
- b = single_qubit_gates[shift + len_ucg // 2 + i]
218
- # Apply the decomposition for UCGates given in equation (3) in
219
- # https://arxiv.org/pdf/quant-ph/0410066.pdf
220
- # to demultiplex one control of all the num_ucgs uniformly-controlled gates
221
- # with log2(len_ucg) uniform controls
222
- v, u, r = self._demultiplex_single_uc(a, b)
223
- # replace the single-qubit gates with v,u (the already existing ones
224
- # are not needed any more)
225
- single_qubit_gates[shift + i] = v
226
- single_qubit_gates[shift + len_ucg // 2 + i] = u
227
- # Now we decompose the gates D as described in Figure 4 in
228
- # https://arxiv.org/pdf/quant-ph/0410066.pdf and merge some of the gates
229
- # into the UCGates and the diagonal at the end of the circuit
230
-
231
- # Remark: The Rz(pi/2) rotation acting on the target qubit and the Hadamard
232
- # gates arising in the decomposition of D are ignored for the moment (they will
233
- # be added together with the C-NOT gates at the end of the decomposition
234
- # (in the method dec_ucg()))
235
- if ucg_index < num_ucgs - 1:
236
- # Absorb the Rz(pi/2) rotation on the control into the UC-Rz gate and
237
- # merge the UC-Rz rotation with the following UCGate,
238
- # which hasn't been decomposed yet.
239
- k = shift + len_ucg + i
240
- single_qubit_gates[k] = single_qubit_gates[k].dot(
241
- UCGate._ct(r)
242
- ) * UCGate._rz(np.pi / 2).item((0, 0))
243
- k = k + len_ucg // 2
244
- single_qubit_gates[k] = single_qubit_gates[k].dot(r) * UCGate._rz(
245
- np.pi / 2
246
- ).item((1, 1))
247
- else:
248
- # Absorb the Rz(pi/2) rotation on the control into the UC-Rz gate and merge
249
- # the trailing UC-Rz rotation into a diagonal gate at the end of the circuit
250
- for ucg_index_2 in range(num_ucgs):
251
- shift_2 = ucg_index_2 * len_ucg
252
- k = 2 * (i + shift_2)
253
- diag[k] = (
254
- diag[k]
255
- * UCGate._ct(r).item((0, 0))
256
- * UCGate._rz(np.pi / 2).item((0, 0))
257
- )
258
- diag[k + 1] = (
259
- diag[k + 1]
260
- * UCGate._ct(r).item((1, 1))
261
- * UCGate._rz(np.pi / 2).item((0, 0))
262
- )
263
- k = len_ucg + k
264
- diag[k] *= r.item((0, 0)) * UCGate._rz(np.pi / 2).item((1, 1))
265
- diag[k + 1] *= r.item((1, 1)) * UCGate._rz(np.pi / 2).item((1, 1))
266
- return single_qubit_gates, diag
267
-
268
- def _demultiplex_single_uc(self, a, b):
269
- """
270
- This method implements the decomposition given in equation (3) in
271
- https://arxiv.org/pdf/quant-ph/0410066.pdf.
272
- The decomposition is used recursively to decompose uniformly controlled gates.
273
- a,b = single qubit unitaries
274
- v,u,r = outcome of the decomposition given in the reference mentioned above
275
- (see there for the details).
276
- """
277
- # The notation is chosen as in https://arxiv.org/pdf/quant-ph/0410066.pdf.
278
- x = a.dot(UCGate._ct(b))
279
- det_x = np.linalg.det(x)
280
- x11 = x.item((0, 0)) / cmath.sqrt(det_x)
281
- phi = cmath.phase(det_x)
282
- r1 = cmath.exp(1j / 2 * (np.pi / 2 - phi / 2 - cmath.phase(x11)))
283
- r2 = cmath.exp(1j / 2 * (np.pi / 2 - phi / 2 + cmath.phase(x11) + np.pi))
284
- r = np.array([[r1, 0], [0, r2]], dtype=complex)
285
- d, u = np.linalg.eig(r.dot(x).dot(r))
286
- # If d is not equal to diag(i,-i), then we put it into this "standard" form
287
- # (see eq. (13) in https://arxiv.org/pdf/quant-ph/0410066.pdf) by interchanging
288
- # the eigenvalues and eigenvectors.
289
- if abs(d[0] + 1j) < _EPS:
290
- d = np.flip(d, 0)
291
- u = np.flip(u, 1)
292
- d = np.diag(np.sqrt(d))
293
- v = d.dot(UCGate._ct(u)).dot(UCGate._ct(r)).dot(b)
294
- return v, u, r
295
-
296
- @staticmethod
297
- def _ct(m):
298
- return np.transpose(np.conjugate(m))
202
+ return uc_gate.dec_ucg_help(single_qubit_gates, self.num_qubits)
299
203
 
300
204
  @staticmethod
301
205
  def _rz(alpha):
@@ -13,10 +13,12 @@
13
13
  """Arbitrary unitary circuit instruction."""
14
14
 
15
15
  from __future__ import annotations
16
+ import math
16
17
 
17
18
  import typing
18
19
  import numpy
19
20
 
21
+ from qiskit import _numpy_compat
20
22
  from qiskit.circuit.gate import Gate
21
23
  from qiskit.circuit.controlledgate import ControlledGate
22
24
  from qiskit.circuit.annotated_operation import AnnotatedOperation, ControlModifier
@@ -69,6 +71,8 @@ class UnitaryGate(Gate):
69
71
  data: numpy.ndarray | Gate | BaseOperator,
70
72
  label: str | None = None,
71
73
  check_input: bool = True,
74
+ *,
75
+ num_qubits: int | None = None,
72
76
  ) -> None:
73
77
  """Create a gate from a numeric unitary matrix.
74
78
 
@@ -80,6 +84,7 @@ class UnitaryGate(Gate):
80
84
  be skipped. This should only ever be used if you know the
81
85
  input is unitary, setting this to ``False`` and passing in
82
86
  a non-unitary matrix will result unexpected behavior and errors.
87
+ num_qubits: If given, the number of qubits in the matrix. If not given, it is inferred.
83
88
 
84
89
  Raises:
85
90
  ValueError: If input data is not an N-qubit unitary operator.
@@ -96,7 +101,7 @@ class UnitaryGate(Gate):
96
101
  # Convert to numpy array in case not already an array
97
102
  data = numpy.asarray(data, dtype=complex)
98
103
  input_dim, output_dim = data.shape
99
- num_qubits = int(numpy.log2(input_dim))
104
+ num_qubits = num_qubits if num_qubits is not None else int(math.log2(input_dim))
100
105
  if check_input:
101
106
  # Check input is unitary
102
107
  if not is_unitary_matrix(data):
@@ -114,10 +119,10 @@ class UnitaryGate(Gate):
114
119
  return False
115
120
  return matrix_equal(self.params[0], other.params[0])
116
121
 
117
- def __array__(self, dtype=None):
122
+ def __array__(self, dtype=None, copy=_numpy_compat.COPY_ONLY_IF_NEEDED):
118
123
  """Return matrix for the unitary."""
119
- # pylint: disable=unused-argument
120
- return self.params[0]
124
+ dtype = self.params[0].dtype if dtype is None else dtype
125
+ return numpy.array(self.params[0], dtype=dtype, copy=copy)
121
126
 
122
127
  def inverse(self, annotated: bool = False):
123
128
  """Return the adjoint of the unitary."""
@@ -15,11 +15,13 @@ Gate described by the time evolution of a Hermitian Hamiltonian operator.
15
15
  """
16
16
 
17
17
  from __future__ import annotations
18
+ import math
18
19
  import typing
19
20
 
20
21
  from numbers import Number
21
22
  import numpy as np
22
23
 
24
+ from qiskit import _numpy_compat
23
25
  from qiskit.circuit.gate import Gate
24
26
  from qiskit.circuit.quantumcircuit import QuantumCircuit
25
27
  from qiskit.circuit.quantumregister import QuantumRegister
@@ -67,7 +69,7 @@ class HamiltonianGate(Gate):
67
69
  # numpy matrix from `Operator.data`.
68
70
  data = data.to_operator().data
69
71
  # Convert to np array in case not already an array
70
- data = np.array(data, dtype=complex)
72
+ data = np.asarray(data, dtype=complex)
71
73
  # Check input is unitary
72
74
  if not is_hermitian_matrix(data):
73
75
  raise ValueError("Input matrix is not Hermitian.")
@@ -75,7 +77,7 @@ class HamiltonianGate(Gate):
75
77
  raise ValueError("Evolution time is not real.")
76
78
  # Check input is N-qubit matrix
77
79
  input_dim, output_dim = data.shape
78
- num_qubits = int(np.log2(input_dim))
80
+ num_qubits = int(math.log2(input_dim))
79
81
  if input_dim != output_dim or 2**num_qubits != input_dim:
80
82
  raise ValueError("Input matrix is not an N-qubit operator.")
81
83
 
@@ -91,18 +93,22 @@ class HamiltonianGate(Gate):
91
93
  times_eq = self.params[1] == other.params[1]
92
94
  return operators_eq and times_eq
93
95
 
94
- def __array__(self, dtype=None):
96
+ def __array__(self, dtype=None, copy=None):
95
97
  """Return matrix for the unitary."""
96
- # pylint: disable=unused-argument
97
98
  import scipy.linalg
98
99
 
100
+ if copy is False:
101
+ raise ValueError("unable to avoid copy while creating an array as requested")
99
102
  try:
100
- return scipy.linalg.expm(-1j * self.params[0] * float(self.params[1]))
103
+ time = float(self.params[1])
101
104
  except TypeError as ex:
102
105
  raise TypeError(
103
106
  "Unable to generate Unitary matrix for "
104
107
  "unbound t parameter {}".format(self.params[1])
105
108
  ) from ex
109
+ arr = scipy.linalg.expm(-1j * self.params[0] * time)
110
+ dtype = complex if dtype is None else dtype
111
+ return np.array(arr, dtype=dtype, copy=_numpy_compat.COPY_ONLY_IF_NEEDED)
106
112
 
107
113
  def inverse(self, annotated: bool = False):
108
114
  """Return the adjoint of the unitary."""
@@ -110,11 +110,11 @@ class EfficientSU2(TwoLocal):
110
110
  If only one gate is provided, the same gate is applied to each qubit.
111
111
  If a list of gates is provided, all gates are applied to each qubit in the provided
112
112
  order.
113
- entanglement: Specifies the entanglement structure. Can be a string ('full', 'linear'
114
- , 'reverse_linear', 'circular' or 'sca'), a list of integer-pairs specifying the indices
115
- of qubits entangled with one another, or a callable returning such a list provided with
116
- the index of the entanglement layer.
117
- Default to 'reverse_linear' entanglement.
113
+ entanglement: Specifies the entanglement structure. Can be a string
114
+ ('full', 'linear', 'reverse_linear', 'pairwise', 'circular', or 'sca'),
115
+ a list of integer-pairs specifying the indices of qubits entangled with one another,
116
+ or a callable returning such a list provided with the index of the entanglement layer.
117
+ Defaults to 'reverse_linear' entanglement.
118
118
  Note that 'reverse_linear' entanglement provides the same unitary as 'full'
119
119
  with fewer entangling gates.
120
120
  See the Examples section of :class:`~qiskit.circuit.library.TwoLocal` for more
@@ -13,16 +13,24 @@
13
13
  """The n-local circuit class."""
14
14
 
15
15
  from __future__ import annotations
16
+
17
+ import collections
18
+ import itertools
16
19
  import typing
17
20
  from collections.abc import Callable, Mapping, Sequence
18
21
 
19
- from itertools import combinations
20
-
21
22
  import numpy
22
23
  from qiskit.circuit.quantumcircuit import QuantumCircuit
23
24
  from qiskit.circuit.quantumregister import QuantumRegister
24
- from qiskit.circuit import Instruction, Parameter, ParameterVector, ParameterExpression
25
+ from qiskit.circuit import (
26
+ Instruction,
27
+ Parameter,
28
+ ParameterVector,
29
+ ParameterExpression,
30
+ CircuitInstruction,
31
+ )
25
32
  from qiskit.exceptions import QiskitError
33
+ from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping
26
34
 
27
35
  from ..blueprintcircuit import BlueprintCircuit
28
36
 
@@ -154,6 +162,17 @@ class NLocal(BlueprintCircuit):
154
162
  self._bounds: list[tuple[float | None, float | None]] | None = None
155
163
  self._flatten = flatten
156
164
 
165
+ # During the build, if a subclass hasn't overridden our parametrisation methods, we can use
166
+ # a newer fast-path method to parametrise the rotation and entanglement blocks if internally
167
+ # those are just simple stdlib gates that have been promoted to circuits. We don't
168
+ # precalculate the fast-path layers themselves because there's far too much that can be
169
+ # overridden between object construction and build, and far too many subclasses of `NLocal`
170
+ # that override bits and bobs of the internal private methods, so it'd be too hard to keep
171
+ # everything in sync.
172
+ self._allow_fast_path_parametrization = (
173
+ getattr(self._parameter_generator, "__func__", None) is NLocal._parameter_generator
174
+ )
175
+
157
176
  if int(reps) != reps:
158
177
  raise TypeError("The value of reps should be int")
159
178
 
@@ -779,13 +798,10 @@ class NLocal(BlueprintCircuit):
779
798
  else:
780
799
  entangler_map = entanglement
781
800
 
782
- layer = QuantumCircuit(self.num_qubits)
783
801
  for i in entangler_map:
784
802
  params = self.ordered_parameters[-len(get_parameters(block)) :]
785
803
  parameterized_block = self._parameterize_block(block, params=params)
786
- layer.compose(parameterized_block, i, inplace=True)
787
-
788
- self.compose(layer, inplace=True)
804
+ self.compose(parameterized_block, i, inplace=True, copy=False)
789
805
  else:
790
806
  # cannot prepend a block currently, just rebuild
791
807
  self._invalidate()
@@ -843,52 +859,65 @@ class NLocal(BlueprintCircuit):
843
859
  """Build a rotation layer."""
844
860
  # if the unentangled qubits are skipped, compute the set of qubits that are not entangled
845
861
  if self._skip_unentangled_qubits:
846
- unentangled_qubits = self.get_unentangled_qubits()
862
+ skipped_qubits = self.get_unentangled_qubits()
863
+ else:
864
+ skipped_qubits = set()
865
+
866
+ target_qubits = circuit.qubits
847
867
 
848
868
  # iterate over all rotation blocks
849
869
  for j, block in enumerate(self.rotation_blocks):
850
- # create a new layer
851
- layer = QuantumCircuit(*self.qregs)
852
-
853
- # we apply the rotation gates stacked on top of each other, i.e.
854
- # if we have 4 qubits and a rotation block of width 2, we apply two instances
855
- block_indices = [
856
- list(range(k * block.num_qubits, (k + 1) * block.num_qubits))
857
- for k in range(self.num_qubits // block.num_qubits)
858
- ]
859
-
860
- # if unentangled qubits should not be acted on, remove all operations that
861
- # touch an unentangled qubit
862
- if self._skip_unentangled_qubits:
870
+ skipped_blocks = {qubit // block.num_qubits for qubit in skipped_qubits}
871
+ if (
872
+ self._allow_fast_path_parametrization
873
+ and (simple_block := _stdlib_gate_from_simple_block(block)) is not None
874
+ ):
875
+ all_qubits = (
876
+ tuple(target_qubits[k * block.num_qubits : (k + 1) * block.num_qubits])
877
+ for k in range(self.num_qubits // block.num_qubits)
878
+ if k not in skipped_blocks
879
+ )
880
+ for qubits in all_qubits:
881
+ instr = CircuitInstruction(
882
+ simple_block.gate(*itertools.islice(param_iter, simple_block.num_params)),
883
+ qubits,
884
+ )
885
+ circuit._append(instr)
886
+ else:
863
887
  block_indices = [
864
- indices
865
- for indices in block_indices
866
- if set(indices).isdisjoint(unentangled_qubits)
888
+ list(range(k * block.num_qubits, (k + 1) * block.num_qubits))
889
+ for k in range(self.num_qubits // block.num_qubits)
890
+ if k not in skipped_blocks
867
891
  ]
868
-
869
- # apply the operations in the layer
870
- for indices in block_indices:
871
- parameterized_block = self._parameterize_block(block, param_iter, i, j, indices)
872
- layer.compose(parameterized_block, indices, inplace=True)
873
-
874
- # add the layer to the circuit
875
- circuit.compose(layer, inplace=True)
892
+ # apply the operations in the layer
893
+ for indices in block_indices:
894
+ parameterized_block = self._parameterize_block(block, param_iter, i, j, indices)
895
+ circuit.compose(parameterized_block, indices, inplace=True, copy=False)
876
896
 
877
897
  def _build_entanglement_layer(self, circuit, param_iter, i):
878
898
  """Build an entanglement layer."""
879
899
  # iterate over all entanglement blocks
900
+ target_qubits = circuit.qubits
880
901
  for j, block in enumerate(self.entanglement_blocks):
881
- # create a new layer and get the entangler map for this block
882
- layer = QuantumCircuit(*self.qregs)
883
902
  entangler_map = self.get_entangler_map(i, j, block.num_qubits)
884
-
885
- # apply the operations in the layer
886
- for indices in entangler_map:
887
- parameterized_block = self._parameterize_block(block, param_iter, i, j, indices)
888
- layer.compose(parameterized_block, indices, inplace=True)
889
-
890
- # add the layer to the circuit
891
- circuit.compose(layer, inplace=True)
903
+ if (
904
+ self._allow_fast_path_parametrization
905
+ and (simple_block := _stdlib_gate_from_simple_block(block)) is not None
906
+ ):
907
+ for indices in entangler_map:
908
+ # It's actually nontrivially faster to use a listcomp and pass that to `tuple`
909
+ # than to pass a generator expression directly.
910
+ # pylint: disable=consider-using-generator
911
+ instr = CircuitInstruction(
912
+ simple_block.gate(*itertools.islice(param_iter, simple_block.num_params)),
913
+ tuple([target_qubits[i] for i in indices]),
914
+ )
915
+ circuit._append(instr)
916
+ else:
917
+ # apply the operations in the layer
918
+ for indices in entangler_map:
919
+ parameterized_block = self._parameterize_block(block, param_iter, i, j, indices)
920
+ circuit.compose(parameterized_block, indices, inplace=True, copy=False)
892
921
 
893
922
  def _build_additional_layers(self, circuit, which):
894
923
  if which == "appended":
@@ -901,13 +930,10 @@ class NLocal(BlueprintCircuit):
901
930
  raise ValueError("`which` must be either `appended` or `prepended`.")
902
931
 
903
932
  for block, ent in zip(blocks, entanglements):
904
- layer = QuantumCircuit(*self.qregs)
905
933
  if isinstance(ent, str):
906
934
  ent = get_entangler_map(block.num_qubits, self.num_qubits, ent)
907
935
  for indices in ent:
908
- layer.compose(block, indices, inplace=True)
909
-
910
- circuit.compose(layer, inplace=True)
936
+ circuit.compose(block, indices, inplace=True, copy=False)
911
937
 
912
938
  def _build(self) -> None:
913
939
  """If not already built, build the circuit."""
@@ -926,7 +952,7 @@ class NLocal(BlueprintCircuit):
926
952
 
927
953
  # use the initial state as starting circuit, if it is set
928
954
  if self.initial_state:
929
- circuit.compose(self.initial_state.copy(), inplace=True)
955
+ circuit.compose(self.initial_state.copy(), inplace=True, copy=False)
930
956
 
931
957
  param_iter = iter(self.ordered_parameters)
932
958
 
@@ -972,7 +998,7 @@ class NLocal(BlueprintCircuit):
972
998
  except QiskitError:
973
999
  block = circuit.to_instruction()
974
1000
 
975
- self.append(block, self.qubits)
1001
+ self.append(block, self.qubits, copy=False)
976
1002
 
977
1003
  # pylint: disable=unused-argument
978
1004
  def _parameter_generator(self, rep: int, block: int, indices: list[int]) -> Parameter | None:
@@ -1023,7 +1049,7 @@ def get_entangler_map(
1023
1049
  raise ValueError("Pairwise entanglement is not defined for blocks with more than 2 qubits.")
1024
1050
 
1025
1051
  if entanglement == "full":
1026
- return list(combinations(list(range(n)), m))
1052
+ return list(itertools.combinations(list(range(n)), m))
1027
1053
  elif entanglement == "reverse_linear":
1028
1054
  # reverse linear connectivity. In the case of m=2 and the entanglement_block='cx'
1029
1055
  # then it's equivalent to 'full' entanglement
@@ -1057,3 +1083,28 @@ def get_entangler_map(
1057
1083
 
1058
1084
  else:
1059
1085
  raise ValueError(f"Unsupported entanglement type: {entanglement}")
1086
+
1087
+
1088
+ _StdlibGateResult = collections.namedtuple("_StdlibGateResult", ("gate", "num_params"))
1089
+ _STANDARD_GATE_MAPPING = get_standard_gate_name_mapping()
1090
+
1091
+
1092
+ def _stdlib_gate_from_simple_block(block: QuantumCircuit) -> _StdlibGateResult | None:
1093
+ if block.global_phase != 0.0 or len(block) != 1:
1094
+ return None
1095
+ instruction = block.data[0]
1096
+ # If the single instruction isn't a standard-library gate that spans the full width of the block
1097
+ # in the correct order, we're not simple. If the gate isn't fully parametrised with pure,
1098
+ # unique `Parameter` instances (expressions are too complex) that are in order, we're not
1099
+ # simple.
1100
+ if (
1101
+ instruction.clbits
1102
+ or tuple(instruction.qubits) != tuple(block.qubits)
1103
+ or (
1104
+ getattr(_STANDARD_GATE_MAPPING.get(instruction.operation.name), "base_class", None)
1105
+ is not instruction.operation.base_class
1106
+ )
1107
+ or tuple(instruction.operation.params) != tuple(block.parameters)
1108
+ ):
1109
+ return None
1110
+ return _StdlibGateResult(instruction.operation.base_class, len(instruction.operation.params))
@@ -17,35 +17,10 @@ import typing
17
17
  from collections.abc import Callable, Sequence
18
18
 
19
19
  from qiskit.circuit.quantumcircuit import QuantumCircuit
20
- from qiskit.circuit import Gate, Instruction, Parameter
20
+ from qiskit.circuit import Gate, Instruction
21
21
 
22
22
  from .n_local import NLocal
23
- from ..standard_gates import (
24
- IGate,
25
- XGate,
26
- YGate,
27
- ZGate,
28
- RXGate,
29
- RYGate,
30
- RZGate,
31
- HGate,
32
- SGate,
33
- SdgGate,
34
- TGate,
35
- TdgGate,
36
- RXXGate,
37
- RYYGate,
38
- RZXGate,
39
- RZZGate,
40
- SwapGate,
41
- CXGate,
42
- CYGate,
43
- CZGate,
44
- CRXGate,
45
- CRYGate,
46
- CRZGate,
47
- CHGate,
48
- )
23
+ from ..standard_gates import get_standard_gate_name_mapping
49
24
 
50
25
  if typing.TYPE_CHECKING:
51
26
  import qiskit # pylint: disable=cyclic-import
@@ -269,38 +244,7 @@ class TwoLocal(NLocal):
269
244
  if isinstance(layer, QuantumCircuit):
270
245
  return layer
271
246
 
272
- # check the list of valid layers
273
- # this could be a lot easier if the standard layers would have ``name`` and ``num_params``
274
- # as static types, which might be something they should have anyway
275
- theta = Parameter("θ")
276
- valid_layers = {
277
- "ch": CHGate(),
278
- "cx": CXGate(),
279
- "cy": CYGate(),
280
- "cz": CZGate(),
281
- "crx": CRXGate(theta),
282
- "cry": CRYGate(theta),
283
- "crz": CRZGate(theta),
284
- "h": HGate(),
285
- "i": IGate(),
286
- "id": IGate(),
287
- "iden": IGate(),
288
- "rx": RXGate(theta),
289
- "rxx": RXXGate(theta),
290
- "ry": RYGate(theta),
291
- "ryy": RYYGate(theta),
292
- "rz": RZGate(theta),
293
- "rzx": RZXGate(theta),
294
- "rzz": RZZGate(theta),
295
- "s": SGate(),
296
- "sdg": SdgGate(),
297
- "swap": SwapGate(),
298
- "x": XGate(),
299
- "y": YGate(),
300
- "z": ZGate(),
301
- "t": TGate(),
302
- "tdg": TdgGate(),
303
- }
247
+ valid_layers = get_standard_gate_name_mapping()
304
248
 
305
249
  # try to exchange `layer` from a string to a gate instance
306
250
  if isinstance(layer, str):
@@ -26,11 +26,11 @@ class UnitaryOverlap(QuantumCircuit):
26
26
  names `"p1"` (for circuit ``unitary1``) and `"p2"` (for circuit ``unitary_2``) in the output
27
27
  circuit.
28
28
 
29
- This circuit is usually employed in computing the fidelity::
29
+ This circuit is usually employed in computing the fidelity:
30
30
 
31
- .. math::
31
+ .. math::
32
32
 
33
- \left|\langle 0| U_2^{\dag} U_1|0\rangle\right|^{2}
33
+ \left|\langle 0| U_2^{\dag} U_1|0\rangle\right|^{2}
34
34
 
35
35
  by computing the probability of being in the all-zeros bit-string, or equivalently,
36
36
  the expectation value of projector :math:`|0\rangle\langle 0|`.
@@ -87,7 +87,7 @@ class PhaseOracle(QuantumCircuit):
87
87
 
88
88
  super().__init__(oracle.num_qubits, name="Phase Oracle")
89
89
 
90
- self.compose(oracle, inplace=True)
90
+ self.compose(oracle, inplace=True, copy=False)
91
91
 
92
92
  def evaluate_bitstring(self, bitstring: str) -> bool:
93
93
  """Evaluate the oracle on a bitstring.