qiskit 1.0.2__cp38-abi3-macosx_11_0_arm64.whl → 1.1.0rc1__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 (247) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +27 -16
  3. qiskit/_accelerate.abi3.so +0 -0
  4. qiskit/_numpy_compat.py +73 -0
  5. qiskit/assembler/disassemble.py +5 -6
  6. qiskit/circuit/__init__.py +1131 -169
  7. qiskit/circuit/_classical_resource_map.py +7 -6
  8. qiskit/circuit/_utils.py +18 -8
  9. qiskit/circuit/annotated_operation.py +21 -0
  10. qiskit/circuit/barrier.py +10 -13
  11. qiskit/circuit/bit.py +0 -1
  12. qiskit/circuit/classical/__init__.py +2 -2
  13. qiskit/circuit/classical/expr/__init__.py +39 -5
  14. qiskit/circuit/classical/expr/constructors.py +84 -1
  15. qiskit/circuit/classical/expr/expr.py +83 -13
  16. qiskit/circuit/classical/expr/visitors.py +83 -0
  17. qiskit/circuit/commutation_checker.py +86 -51
  18. qiskit/circuit/controlflow/_builder_utils.py +9 -1
  19. qiskit/circuit/controlflow/break_loop.py +8 -22
  20. qiskit/circuit/controlflow/builder.py +116 -1
  21. qiskit/circuit/controlflow/continue_loop.py +8 -22
  22. qiskit/circuit/controlflow/control_flow.py +47 -8
  23. qiskit/circuit/controlflow/for_loop.py +8 -23
  24. qiskit/circuit/controlflow/if_else.py +13 -27
  25. qiskit/circuit/controlflow/switch_case.py +14 -21
  26. qiskit/circuit/controlflow/while_loop.py +9 -23
  27. qiskit/circuit/controlledgate.py +2 -2
  28. qiskit/circuit/delay.py +7 -5
  29. qiskit/circuit/gate.py +20 -7
  30. qiskit/circuit/instruction.py +31 -30
  31. qiskit/circuit/instructionset.py +9 -22
  32. qiskit/circuit/library/__init__.py +8 -2
  33. qiskit/circuit/library/arithmetic/integer_comparator.py +2 -2
  34. qiskit/circuit/library/arithmetic/quadratic_form.py +3 -2
  35. qiskit/circuit/library/blueprintcircuit.py +29 -7
  36. qiskit/circuit/library/data_preparation/state_preparation.py +6 -5
  37. qiskit/circuit/library/generalized_gates/diagonal.py +5 -4
  38. qiskit/circuit/library/generalized_gates/isometry.py +51 -254
  39. qiskit/circuit/library/generalized_gates/pauli.py +2 -2
  40. qiskit/circuit/library/generalized_gates/permutation.py +4 -1
  41. qiskit/circuit/library/generalized_gates/rv.py +15 -11
  42. qiskit/circuit/library/generalized_gates/uc.py +2 -98
  43. qiskit/circuit/library/generalized_gates/unitary.py +9 -4
  44. qiskit/circuit/library/hamiltonian_gate.py +11 -5
  45. qiskit/circuit/library/n_local/efficient_su2.py +5 -5
  46. qiskit/circuit/library/n_local/n_local.py +100 -49
  47. qiskit/circuit/library/n_local/two_local.py +3 -59
  48. qiskit/circuit/library/overlap.py +3 -3
  49. qiskit/circuit/library/phase_oracle.py +1 -1
  50. qiskit/circuit/library/quantum_volume.py +39 -38
  51. qiskit/circuit/library/standard_gates/equivalence_library.py +50 -0
  52. qiskit/circuit/library/standard_gates/global_phase.py +4 -2
  53. qiskit/circuit/library/standard_gates/i.py +1 -2
  54. qiskit/circuit/library/standard_gates/iswap.py +1 -2
  55. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +11 -5
  56. qiskit/circuit/library/standard_gates/p.py +31 -15
  57. qiskit/circuit/library/standard_gates/r.py +4 -3
  58. qiskit/circuit/library/standard_gates/rx.py +7 -4
  59. qiskit/circuit/library/standard_gates/rxx.py +4 -3
  60. qiskit/circuit/library/standard_gates/ry.py +7 -4
  61. qiskit/circuit/library/standard_gates/ryy.py +4 -3
  62. qiskit/circuit/library/standard_gates/rz.py +7 -4
  63. qiskit/circuit/library/standard_gates/rzx.py +4 -3
  64. qiskit/circuit/library/standard_gates/rzz.py +4 -3
  65. qiskit/circuit/library/standard_gates/s.py +4 -8
  66. qiskit/circuit/library/standard_gates/t.py +2 -4
  67. qiskit/circuit/library/standard_gates/u.py +16 -11
  68. qiskit/circuit/library/standard_gates/u1.py +6 -2
  69. qiskit/circuit/library/standard_gates/u2.py +4 -2
  70. qiskit/circuit/library/standard_gates/u3.py +9 -5
  71. qiskit/circuit/library/standard_gates/x.py +22 -11
  72. qiskit/circuit/library/standard_gates/xx_minus_yy.py +4 -3
  73. qiskit/circuit/library/standard_gates/xx_plus_yy.py +7 -5
  74. qiskit/circuit/library/standard_gates/z.py +1 -2
  75. qiskit/circuit/measure.py +4 -1
  76. qiskit/circuit/operation.py +13 -8
  77. qiskit/circuit/parameter.py +11 -6
  78. qiskit/circuit/quantumcircuit.py +864 -128
  79. qiskit/circuit/quantumcircuitdata.py +2 -2
  80. qiskit/circuit/reset.py +5 -2
  81. qiskit/circuit/store.py +95 -0
  82. qiskit/compiler/assembler.py +22 -22
  83. qiskit/compiler/transpiler.py +63 -112
  84. qiskit/converters/circuit_to_dag.py +7 -0
  85. qiskit/converters/circuit_to_dagdependency_v2.py +47 -0
  86. qiskit/converters/circuit_to_gate.py +2 -0
  87. qiskit/converters/circuit_to_instruction.py +22 -0
  88. qiskit/converters/dag_to_circuit.py +4 -0
  89. qiskit/converters/dag_to_dagdependency_v2.py +44 -0
  90. qiskit/dagcircuit/collect_blocks.py +15 -10
  91. qiskit/dagcircuit/dagcircuit.py +434 -124
  92. qiskit/dagcircuit/dagdependency.py +19 -12
  93. qiskit/dagcircuit/dagdependency_v2.py +641 -0
  94. qiskit/dagcircuit/dagdepnode.py +19 -16
  95. qiskit/dagcircuit/dagnode.py +14 -4
  96. qiskit/primitives/__init__.py +12 -8
  97. qiskit/primitives/backend_estimator.py +3 -5
  98. qiskit/primitives/backend_estimator_v2.py +410 -0
  99. qiskit/primitives/backend_sampler_v2.py +287 -0
  100. qiskit/primitives/base/base_estimator.py +4 -9
  101. qiskit/primitives/base/base_sampler.py +2 -2
  102. qiskit/primitives/containers/__init__.py +5 -4
  103. qiskit/primitives/containers/bit_array.py +292 -2
  104. qiskit/primitives/containers/data_bin.py +123 -50
  105. qiskit/primitives/containers/estimator_pub.py +10 -3
  106. qiskit/primitives/containers/observables_array.py +2 -2
  107. qiskit/primitives/containers/pub_result.py +1 -1
  108. qiskit/primitives/containers/sampler_pub.py +19 -3
  109. qiskit/primitives/containers/sampler_pub_result.py +74 -0
  110. qiskit/primitives/containers/shape.py +1 -1
  111. qiskit/primitives/statevector_estimator.py +4 -4
  112. qiskit/primitives/statevector_sampler.py +7 -12
  113. qiskit/providers/__init__.py +17 -18
  114. qiskit/providers/backend.py +2 -2
  115. qiskit/providers/backend_compat.py +8 -10
  116. qiskit/providers/basic_provider/basic_provider_tools.py +67 -31
  117. qiskit/providers/basic_provider/basic_simulator.py +81 -21
  118. qiskit/providers/fake_provider/fake_1q.py +1 -1
  119. qiskit/providers/fake_provider/fake_backend.py +3 -408
  120. qiskit/providers/fake_provider/generic_backend_v2.py +26 -14
  121. qiskit/providers/provider.py +16 -0
  122. qiskit/pulse/builder.py +4 -1
  123. qiskit/pulse/parameter_manager.py +60 -4
  124. qiskit/pulse/schedule.py +29 -13
  125. qiskit/pulse/utils.py +61 -20
  126. qiskit/qasm2/__init__.py +1 -5
  127. qiskit/qasm2/parse.py +1 -4
  128. qiskit/qasm3/__init__.py +42 -5
  129. qiskit/qasm3/ast.py +19 -0
  130. qiskit/qasm3/exporter.py +178 -106
  131. qiskit/qasm3/printer.py +27 -5
  132. qiskit/qpy/__init__.py +247 -13
  133. qiskit/qpy/binary_io/circuits.py +216 -47
  134. qiskit/qpy/binary_io/schedules.py +42 -36
  135. qiskit/qpy/binary_io/value.py +201 -22
  136. qiskit/qpy/common.py +1 -1
  137. qiskit/qpy/exceptions.py +20 -0
  138. qiskit/qpy/formats.py +29 -0
  139. qiskit/qpy/type_keys.py +21 -0
  140. qiskit/quantum_info/analysis/distance.py +3 -3
  141. qiskit/quantum_info/analysis/make_observable.py +2 -1
  142. qiskit/quantum_info/analysis/z2_symmetries.py +2 -1
  143. qiskit/quantum_info/operators/channel/chi.py +9 -8
  144. qiskit/quantum_info/operators/channel/choi.py +10 -9
  145. qiskit/quantum_info/operators/channel/kraus.py +2 -1
  146. qiskit/quantum_info/operators/channel/ptm.py +10 -9
  147. qiskit/quantum_info/operators/channel/quantum_channel.py +2 -1
  148. qiskit/quantum_info/operators/channel/stinespring.py +2 -1
  149. qiskit/quantum_info/operators/channel/superop.py +12 -11
  150. qiskit/quantum_info/operators/channel/transformations.py +12 -11
  151. qiskit/quantum_info/operators/dihedral/dihedral.py +5 -4
  152. qiskit/quantum_info/operators/operator.py +43 -30
  153. qiskit/quantum_info/operators/scalar_op.py +10 -9
  154. qiskit/quantum_info/operators/symplectic/base_pauli.py +70 -59
  155. qiskit/quantum_info/operators/symplectic/clifford.py +36 -9
  156. qiskit/quantum_info/operators/symplectic/pauli.py +48 -4
  157. qiskit/quantum_info/operators/symplectic/pauli_list.py +36 -14
  158. qiskit/quantum_info/operators/symplectic/random.py +3 -2
  159. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +54 -33
  160. qiskit/quantum_info/states/densitymatrix.py +13 -13
  161. qiskit/quantum_info/states/stabilizerstate.py +3 -3
  162. qiskit/quantum_info/states/statevector.py +14 -13
  163. qiskit/quantum_info/states/utils.py +5 -3
  164. qiskit/result/mitigation/correlated_readout_mitigator.py +3 -2
  165. qiskit/result/mitigation/local_readout_mitigator.py +2 -1
  166. qiskit/result/mitigation/utils.py +3 -2
  167. qiskit/synthesis/__init__.py +2 -0
  168. qiskit/synthesis/discrete_basis/commutator_decompose.py +2 -2
  169. qiskit/synthesis/evolution/lie_trotter.py +7 -14
  170. qiskit/synthesis/evolution/qdrift.py +3 -4
  171. qiskit/synthesis/linear/cnot_synth.py +1 -3
  172. qiskit/synthesis/linear/linear_circuits_utils.py +1 -1
  173. qiskit/synthesis/linear_phase/cz_depth_lnn.py +4 -18
  174. qiskit/synthesis/permutation/__init__.py +1 -0
  175. qiskit/synthesis/permutation/permutation_reverse_lnn.py +90 -0
  176. qiskit/synthesis/qft/qft_decompose_lnn.py +2 -6
  177. qiskit/synthesis/two_qubit/two_qubit_decompose.py +165 -954
  178. qiskit/synthesis/two_qubit/xx_decompose/circuits.py +13 -12
  179. qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +7 -1
  180. qiskit/synthesis/unitary/aqc/__init__.py +1 -1
  181. qiskit/synthesis/unitary/aqc/cnot_structures.py +2 -1
  182. qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +2 -1
  183. qiskit/synthesis/unitary/qsd.py +3 -2
  184. qiskit/transpiler/__init__.py +7 -3
  185. qiskit/transpiler/layout.py +140 -61
  186. qiskit/transpiler/passes/__init__.py +6 -0
  187. qiskit/transpiler/passes/basis/basis_translator.py +7 -2
  188. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
  189. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
  190. qiskit/transpiler/passes/calibration/rzx_builder.py +2 -1
  191. qiskit/transpiler/passes/layout/apply_layout.py +8 -3
  192. qiskit/transpiler/passes/layout/sabre_layout.py +15 -3
  193. qiskit/transpiler/passes/layout/set_layout.py +1 -1
  194. qiskit/transpiler/passes/optimization/__init__.py +2 -0
  195. qiskit/transpiler/passes/optimization/commutation_analysis.py +2 -2
  196. qiskit/transpiler/passes/optimization/commutative_cancellation.py +1 -1
  197. qiskit/transpiler/passes/optimization/consolidate_blocks.py +1 -1
  198. qiskit/transpiler/passes/optimization/cx_cancellation.py +10 -0
  199. qiskit/transpiler/passes/optimization/elide_permutations.py +114 -0
  200. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +9 -3
  201. qiskit/transpiler/passes/optimization/optimize_annotated.py +248 -12
  202. qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
  203. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +1 -3
  204. qiskit/transpiler/passes/routing/__init__.py +1 -0
  205. qiskit/transpiler/passes/routing/basic_swap.py +13 -2
  206. qiskit/transpiler/passes/routing/lookahead_swap.py +7 -1
  207. qiskit/transpiler/passes/routing/sabre_swap.py +10 -6
  208. qiskit/transpiler/passes/routing/star_prerouting.py +417 -0
  209. qiskit/transpiler/passes/routing/stochastic_swap.py +24 -8
  210. qiskit/transpiler/passes/scheduling/__init__.py +1 -1
  211. qiskit/transpiler/passes/scheduling/alap.py +1 -2
  212. qiskit/transpiler/passes/scheduling/alignments/align_measures.py +1 -2
  213. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +9 -6
  214. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +8 -0
  215. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +13 -4
  216. qiskit/transpiler/passes/scheduling/asap.py +1 -2
  217. qiskit/transpiler/passes/scheduling/base_scheduler.py +21 -2
  218. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +26 -4
  219. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +24 -2
  220. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +28 -4
  221. qiskit/transpiler/passes/synthesis/aqc_plugin.py +2 -2
  222. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +120 -13
  223. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +162 -55
  224. qiskit/transpiler/passes/utils/gates_basis.py +3 -3
  225. qiskit/transpiler/passmanager.py +44 -1
  226. qiskit/transpiler/preset_passmanagers/__init__.py +3 -3
  227. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +34 -16
  228. qiskit/transpiler/preset_passmanagers/common.py +4 -6
  229. qiskit/transpiler/preset_passmanagers/plugin.py +9 -1
  230. qiskit/utils/optionals.py +6 -2
  231. qiskit/visualization/array.py +1 -1
  232. qiskit/visualization/bloch.py +2 -3
  233. qiskit/visualization/circuit/matplotlib.py +44 -14
  234. qiskit/visualization/circuit/text.py +38 -18
  235. qiskit/visualization/counts_visualization.py +3 -6
  236. qiskit/visualization/dag_visualization.py +6 -7
  237. qiskit/visualization/pulse_v2/interface.py +8 -3
  238. qiskit/visualization/state_visualization.py +3 -2
  239. qiskit/visualization/timeline/interface.py +18 -8
  240. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/METADATA +12 -8
  241. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/RECORD +245 -235
  242. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/WHEEL +1 -1
  243. qiskit/_qasm2.abi3.so +0 -0
  244. qiskit/_qasm3.abi3.so +0 -0
  245. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/LICENSE.txt +0 -0
  246. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/entry_points.txt +0 -0
  247. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -21,7 +21,7 @@ Generic isometries from m to n qubits.
21
21
 
22
22
  from __future__ import annotations
23
23
 
24
- import itertools
24
+ import math
25
25
  import numpy as np
26
26
  from qiskit.circuit.exceptions import CircuitError
27
27
  from qiskit.circuit.instruction import Instruction
@@ -29,6 +29,7 @@ from qiskit.circuit.quantumcircuit import QuantumCircuit
29
29
  from qiskit.circuit.quantumregister import QuantumRegister
30
30
  from qiskit.exceptions import QiskitError
31
31
  from qiskit.quantum_info.operators.predicates import is_isometry
32
+ from qiskit._accelerate import isometry as isometry_rs
32
33
 
33
34
  from .diagonal import Diagonal
34
35
  from .uc import UCGate
@@ -93,8 +94,8 @@ class Isometry(Instruction):
93
94
  self._epsilon = epsilon
94
95
 
95
96
  # Check if the isometry has the right dimension and if the columns are orthonormal
96
- n = np.log2(isometry.shape[0])
97
- m = np.log2(isometry.shape[1])
97
+ n = math.log2(isometry.shape[0])
98
+ m = math.log2(isometry.shape[1])
98
99
  if not n.is_integer() or n < 0:
99
100
  raise QiskitError(
100
101
  "The number of rows of the isometry is not a non negative power of 2."
@@ -150,18 +151,22 @@ class Isometry(Instruction):
150
151
  # to keep a copyof the input isometry)
151
152
  remaining_isometry = self.iso_data.astype(complex) # note: "astype" does copy the isometry
152
153
  diag = []
153
- m = int(np.log2((self.iso_data).shape[1]))
154
+ m = int(math.log2(self.iso_data.shape[1]))
154
155
  # Decompose the column with index column_index and attache the gate to the circuit object.
155
156
  # Return the isometry that is left to decompose, where the columns up to index column_index
156
157
  # correspond to the firstfew columns of the identity matrix up to diag, and hence we only
157
158
  # have to save a list containing them.
158
159
  for column_index in range(2**m):
159
- self._decompose_column(circuit, q, diag, remaining_isometry, column_index)
160
+ remaining_isometry, diag = self._decompose_column(
161
+ circuit, q, diag, remaining_isometry, column_index
162
+ )
160
163
  # extract phase of the state that was sent to the basis state ket(column_index)
161
164
  diag.append(remaining_isometry[column_index, 0])
162
165
  # remove first column (which is now stored in diag)
163
166
  remaining_isometry = remaining_isometry[:, 1:]
164
- if len(diag) > 1 and not _diag_is_identity_up_to_global_phase(diag, self._epsilon):
167
+ if len(diag) > 1 and not isometry_rs.diag_is_identity_up_to_global_phase(
168
+ diag, self._epsilon
169
+ ):
165
170
  diagonal = Diagonal(np.conj(diag))
166
171
  circuit.append(diagonal, q_input)
167
172
  return circuit
@@ -170,9 +175,12 @@ class Isometry(Instruction):
170
175
  """
171
176
  Decomposes the column with index column_index.
172
177
  """
173
- n = int(np.log2(self.iso_data.shape[0]))
178
+ n = int(math.log2(self.iso_data.shape[0]))
174
179
  for s in range(n):
175
- self._disentangle(circuit, q, diag, remaining_isometry, column_index, s)
180
+ remaining_isometry, diag = self._disentangle(
181
+ circuit, q, diag, remaining_isometry, column_index, s
182
+ )
183
+ return remaining_isometry, diag
176
184
 
177
185
  def _disentangle(self, circuit, q, diag, remaining_isometry, column_index, s):
178
186
  """
@@ -185,16 +193,22 @@ class Isometry(Instruction):
185
193
  # (note that we remove columns of the isometry during the procedure for efficiency)
186
194
  k_prime = 0
187
195
  v = remaining_isometry
188
- n = int(np.log2(self.iso_data.shape[0]))
196
+ n = int(math.log2(self.iso_data.shape[0]))
189
197
 
190
198
  # MCG to set one entry to zero (preparation for disentangling with UCGate):
191
- index1 = 2 * _a(k, s + 1) * 2**s + _b(k, s + 1)
192
- index2 = (2 * _a(k, s + 1) + 1) * 2**s + _b(k, s + 1)
199
+ index1 = 2 * isometry_rs.a(k, s + 1) * 2**s + isometry_rs.b(k, s + 1)
200
+ index2 = (2 * isometry_rs.a(k, s + 1) + 1) * 2**s + isometry_rs.b(k, s + 1)
193
201
  target_label = n - s - 1
194
202
  # Check if a MCG is required
195
- if _k_s(k, s) == 0 and _b(k, s + 1) != 0 and np.abs(v[index2, k_prime]) > self._epsilon:
203
+ if (
204
+ isometry_rs.k_s(k, s) == 0
205
+ and isometry_rs.b(k, s + 1) != 0
206
+ and np.abs(v[index2, k_prime]) > self._epsilon
207
+ ):
196
208
  # Find the MCG, decompose it and apply it to the remaining isometry
197
- gate = _reverse_qubit_state([v[index1, k_prime], v[index2, k_prime]], 0, self._epsilon)
209
+ gate = isometry_rs.reverse_qubit_state(
210
+ [v[index1, k_prime], v[index2, k_prime]], 0, self._epsilon
211
+ )
198
212
  control_labels = [
199
213
  i
200
214
  for i, x in enumerate(_get_binary_rep_as_list(k, n))
@@ -204,57 +218,49 @@ class Isometry(Instruction):
204
218
  circuit, q, gate, control_labels, target_label
205
219
  )
206
220
  # apply the MCG to the remaining isometry
207
- _apply_multi_controlled_gate(v, control_labels, target_label, gate)
221
+ v = isometry_rs.apply_multi_controlled_gate(v, control_labels, target_label, gate)
208
222
  # correct for the implementation "up to diagonal"
209
- diag_mcg_inverse = np.conj(diagonal_mcg).tolist()
210
- _apply_diagonal_gate(v, control_labels + [target_label], diag_mcg_inverse)
223
+ diag_mcg_inverse = np.conj(diagonal_mcg).astype(complex, copy=False)
224
+ v = isometry_rs.apply_diagonal_gate(
225
+ v, control_labels + [target_label], diag_mcg_inverse
226
+ )
211
227
  # update the diag according to the applied diagonal gate
212
- _apply_diagonal_gate_to_diag(diag, control_labels + [target_label], diag_mcg_inverse, n)
228
+ diag = isometry_rs.apply_diagonal_gate_to_diag(
229
+ diag, control_labels + [target_label], diag_mcg_inverse, n
230
+ )
213
231
 
214
232
  # UCGate to disentangle a qubit:
215
233
  # Find the UCGate, decompose it and apply it to the remaining isometry
216
234
  single_qubit_gates = self._find_squs_for_disentangling(v, k, s)
217
- if not _ucg_is_identity_up_to_global_phase(single_qubit_gates, self._epsilon):
235
+ if not isometry_rs.ucg_is_identity_up_to_global_phase(single_qubit_gates, self._epsilon):
218
236
  control_labels = list(range(target_label))
219
237
  diagonal_ucg = self._append_ucg_up_to_diagonal(
220
238
  circuit, q, single_qubit_gates, control_labels, target_label
221
239
  )
222
240
  # merge the diagonal into the UCGate for efficient application of both together
223
- diagonal_ucg_inverse = np.conj(diagonal_ucg).tolist()
224
- single_qubit_gates = _merge_UCGate_and_diag(single_qubit_gates, diagonal_ucg_inverse)
241
+ diagonal_ucg_inverse = np.conj(diagonal_ucg).astype(complex, copy=False)
242
+ single_qubit_gates = isometry_rs.merge_ucgate_and_diag(
243
+ single_qubit_gates, diagonal_ucg_inverse
244
+ )
225
245
  # apply the UCGate (with the merged diagonal gate) to the remaining isometry
226
- _apply_ucg(v, len(control_labels), single_qubit_gates)
246
+ v = isometry_rs.apply_ucg(v, len(control_labels), single_qubit_gates)
227
247
  # update the diag according to the applied diagonal gate
228
- _apply_diagonal_gate_to_diag(
248
+ diag = isometry_rs.apply_diagonal_gate_to_diag(
229
249
  diag, control_labels + [target_label], diagonal_ucg_inverse, n
230
250
  )
231
251
  # # correct for the implementation "up to diagonal"
232
252
  # diag_inv = np.conj(diag).tolist()
233
253
  # _apply_diagonal_gate(v, control_labels + [target_label], diag_inv)
254
+ return v, diag
234
255
 
235
256
  # This method finds the single-qubit gates for a UCGate to disentangle a qubit:
236
257
  # we consider the n-qubit state v[:,0] starting with k zeros (in the computational basis).
237
258
  # The qubit with label n-s-1 is disentangled into the basis state k_s(k,s).
238
259
  def _find_squs_for_disentangling(self, v, k, s):
239
- k_prime = 0
240
- n = int(np.log2(self.iso_data.shape[0]))
241
- if _b(k, s + 1) == 0:
242
- i_start = _a(k, s + 1)
243
- else:
244
- i_start = _a(k, s + 1) + 1
245
- id_list = [np.eye(2, 2) for _ in range(i_start)]
246
- squs = [
247
- _reverse_qubit_state(
248
- [
249
- v[2 * i * 2**s + _b(k, s), k_prime],
250
- v[(2 * i + 1) * 2**s + _b(k, s), k_prime],
251
- ],
252
- _k_s(k, s),
253
- self._epsilon,
254
- )
255
- for i in range(i_start, 2 ** (n - s - 1))
256
- ]
257
- return id_list + squs
260
+ res = isometry_rs.find_squs_for_disentangling(
261
+ v, k, s, self._epsilon, n=int(math.log2(self.iso_data.shape[0]))
262
+ )
263
+ return res
258
264
 
259
265
  # Append a UCGate up to diagonal to the circuit circ.
260
266
  def _append_ucg_up_to_diagonal(self, circ, q, single_qubit_gates, control_labels, target_label):
@@ -264,7 +270,7 @@ class Isometry(Instruction):
264
270
  q_ancillas_zero,
265
271
  q_ancillas_dirty,
266
272
  ) = self._define_qubit_role(q)
267
- n = int(np.log2(self.iso_data.shape[0]))
273
+ n = int(math.log2(self.iso_data.shape[0]))
268
274
  qubits = q_input + q_ancillas_for_output
269
275
  # Note that we have to reverse the control labels, since controls are provided by
270
276
  # increasing qubit number toa UCGate by convention
@@ -286,7 +292,7 @@ class Isometry(Instruction):
286
292
  q_ancillas_zero,
287
293
  q_ancillas_dirty,
288
294
  ) = self._define_qubit_role(q)
289
- n = int(np.log2(self.iso_data.shape[0]))
295
+ n = int(math.log2(self.iso_data.shape[0]))
290
296
  qubits = q_input + q_ancillas_for_output
291
297
  control_qubits = _reverse_qubit_oder(_get_qubits_by_label(control_labels, qubits, n))
292
298
  target_qubit = _get_qubits_by_label([target_label], qubits, n)[0]
@@ -307,8 +313,8 @@ class Isometry(Instruction):
307
313
 
308
314
  def _define_qubit_role(self, q):
309
315
 
310
- n = int(np.log2(self.iso_data.shape[0]))
311
- m = int(np.log2(self.iso_data.shape[1]))
316
+ n = int(math.log2(self.iso_data.shape[0]))
317
+ m = int(math.log2(self.iso_data.shape[1]))
312
318
 
313
319
  # Define the role of the qubits
314
320
  q_input = q[:m]
@@ -337,146 +343,6 @@ class Isometry(Instruction):
337
343
  return self._inverse
338
344
 
339
345
 
340
- # Find special unitary matrix that maps [c0,c1] to [r,0] or [0,r] if basis_state=0 or
341
- # basis_state=1 respectively
342
- def _reverse_qubit_state(state, basis_state, epsilon):
343
- state = np.array(state)
344
- r = np.linalg.norm(state)
345
- if r < epsilon:
346
- return np.eye(2, 2)
347
- if basis_state == 0:
348
- m = np.array([[np.conj(state[0]), np.conj(state[1])], [-state[1], state[0]]]) / r
349
- else:
350
- m = np.array([[-state[1], state[0]], [np.conj(state[0]), np.conj(state[1])]]) / r
351
- return m
352
-
353
-
354
- # Methods for applying gates to matrices (should be moved to Qiskit AER)
355
-
356
- # Input: matrix m with 2^n rows (and arbitrary many columns). Think of the columns as states
357
- # on n qubits. The method applies a uniformly controlled gate (UCGate) to all the columns, where
358
- # the UCGate is specified by the inputs k and single_qubit_gates:
359
-
360
- # k = number of controls. We assume that the controls are on the k most significant qubits
361
- # (and the target is on the (k+1)th significant qubit)
362
- # single_qubit_gates = [u_0,...,u_{2^k-1}], where the u_i's are 2*2 unitaries
363
- # (provided as numpy arrays)
364
-
365
- # The order of the single-qubit unitaries is such that the first unitary u_0 is applied to the
366
- # (k+1)th significant qubit if the control qubits are in the state ket(0...00), the gate u_1 is
367
- # applied if the control qubits are in the state ket(0...01), and so on.
368
-
369
- # The input matrix m and the single-qubit gates have to be of dtype=complex.
370
-
371
-
372
- def _apply_ucg(m, k, single_qubit_gates):
373
- # ToDo: Improve efficiency by parallelizing the gate application. A generalized version of
374
- # ToDo: this method should be implemented by the state vector simulator in Qiskit AER.
375
- num_qubits = int(np.log2(m.shape[0]))
376
- num_col = m.shape[1]
377
- spacing = 2 ** (num_qubits - k - 1)
378
- for j in range(2 ** (num_qubits - 1)):
379
- i = (j // spacing) * spacing + j
380
- gate_index = i // (2 ** (num_qubits - k))
381
- for col in range(num_col):
382
- m[np.array([i, i + spacing]), np.array([col, col])] = np.ndarray.flatten(
383
- single_qubit_gates[gate_index].dot(np.array([[m[i, col]], [m[i + spacing, col]]]))
384
- ).tolist()
385
- return m
386
-
387
-
388
- # Apply a diagonal gate with diagonal entries liste in diag and acting on qubits with labels
389
- # action_qubit_labels to a matrix m.
390
- # The input matrix m has to be of dtype=complex
391
- # The qubit labels are such that label 0 corresponds to the most significant qubit, label 1 to
392
- # the second most significant qubit, and so on ...
393
-
394
-
395
- def _apply_diagonal_gate(m, action_qubit_labels, diag):
396
- # ToDo: Improve efficiency by parallelizing the gate application. A generalized version of
397
- # ToDo: this method should be implemented by the state vector simulator in Qiskit AER.
398
- num_qubits = int(np.log2(m.shape[0]))
399
- num_cols = m.shape[1]
400
- basis_states = list(itertools.product([0, 1], repeat=num_qubits))
401
- for state in basis_states:
402
- state_on_action_qubits = [state[i] for i in action_qubit_labels]
403
- diag_index = _bin_to_int(state_on_action_qubits)
404
- i = _bin_to_int(state)
405
- for j in range(num_cols):
406
- m[i, j] = diag[diag_index] * m[i, j]
407
- return m
408
-
409
-
410
- # Special case of the method _apply_diagonal_gate, where the input m is a diagonal matrix on the
411
- # log2(len(m_diagonal)) least significant qubits (this method is more efficient in this case
412
- # than _apply_diagonal_gate). The input m_diagonal is provided as a list of diagonal entries.
413
- # The diagonal diag is applied on the qubits with labels listed in action_qubit_labels. The input
414
- # num_qubits gives the total number of considered qubits (this input is required to interpret the
415
- # action_qubit_labels in relation to the least significant qubits).
416
-
417
-
418
- def _apply_diagonal_gate_to_diag(m_diagonal, action_qubit_labels, diag, num_qubits):
419
- if not m_diagonal:
420
- return m_diagonal
421
- basis_states = list(itertools.product([0, 1], repeat=num_qubits))
422
- for state in basis_states[: len(m_diagonal)]:
423
- state_on_action_qubits = [state[i] for i in action_qubit_labels]
424
- diag_index = _bin_to_int(state_on_action_qubits)
425
- i = _bin_to_int(state)
426
- m_diagonal[i] *= diag[diag_index]
427
- return m_diagonal
428
-
429
-
430
- # Apply a MC single-qubit gate (given by the 2*2 unitary input: gate) with controlling on
431
- # the qubits with label control_labels and acting on the qubit with label target_label
432
- # to a matrix m. The input matrix m and the gate have to be of dtype=complex. The qubit labels are
433
- # such that label 0 corresponds to the most significant qubit, label 1 to the second most
434
- # significant qubit, and so on ...
435
-
436
-
437
- def _apply_multi_controlled_gate(m, control_labels, target_label, gate):
438
- # ToDo: This method should be integrated into the state vector simulator in Qiskit AER.
439
- num_qubits = int(np.log2(m.shape[0]))
440
- num_cols = m.shape[1]
441
- control_labels.sort()
442
- free_qubits = num_qubits - len(control_labels) - 1
443
- basis_states_free = list(itertools.product([0, 1], repeat=free_qubits))
444
- for state_free in basis_states_free:
445
- (e1, e2) = _construct_basis_states(state_free, control_labels, target_label)
446
- for i in range(num_cols):
447
- m[np.array([e1, e2]), np.array([i, i])] = np.ndarray.flatten(
448
- gate.dot(np.array([[m[e1, i]], [m[e2, i]]]))
449
- ).tolist()
450
- return m
451
-
452
-
453
- # Helper method for _apply_multi_controlled_gate. This constructs the basis states the MG gate
454
- # is acting on for a specific state state_free of the qubits we neither control nor act on.
455
-
456
-
457
- def _construct_basis_states(state_free, control_labels, target_label):
458
- e1 = []
459
- e2 = []
460
- j = 0
461
- for i in range(len(state_free) + len(control_labels) + 1):
462
- if i in control_labels:
463
- e1.append(1)
464
- e2.append(1)
465
- elif i == target_label:
466
- e1.append(0)
467
- e2.append(1)
468
- else:
469
- e1.append(state_free[j])
470
- e2.append(state_free[j])
471
- j += 1
472
- out1 = _bin_to_int(e1)
473
- out2 = _bin_to_int(e2)
474
- return out1, out2
475
-
476
-
477
- # Some helper methods:
478
-
479
-
480
346
  # Get the qubits in the list qubits corresponding to the labels listed in labels. The total number
481
347
  # of qubits is given by num_qubits (and determines the convention for the qubit labeling)
482
348
 
@@ -495,14 +361,6 @@ def _reverse_qubit_oder(qubits):
495
361
  # Convert list of binary digits to integer
496
362
 
497
363
 
498
- def _bin_to_int(binary_digits_as_list):
499
- return int("".join(str(x) for x in binary_digits_as_list), 2)
500
-
501
-
502
- def _ct(m):
503
- return np.transpose(np.conjugate(m))
504
-
505
-
506
364
  def _get_binary_rep_as_list(n, num_digits):
507
365
  binary_string = np.binary_repr(n).zfill(num_digits)
508
366
  binary = []
@@ -510,64 +368,3 @@ def _get_binary_rep_as_list(n, num_digits):
510
368
  for c in line:
511
369
  binary.append(int(c))
512
370
  return binary[-num_digits:]
513
-
514
-
515
- # absorb a diagonal gate into a UCGate
516
-
517
-
518
- def _merge_UCGate_and_diag(single_qubit_gates, diag):
519
- for i, gate in enumerate(single_qubit_gates):
520
- single_qubit_gates[i] = np.array([[diag[2 * i], 0.0], [0.0, diag[2 * i + 1]]]).dot(gate)
521
- return single_qubit_gates
522
-
523
-
524
- # Helper variables/functions for the column-by-column decomposition
525
-
526
-
527
- # a(k,s) and b(k,s) are positive integers such that k = a(k,s)2^s + b(k,s)
528
- # (with the maximal choice of a(k,s))
529
-
530
-
531
- def _a(k, s):
532
- return k // 2**s
533
-
534
-
535
- def _b(k, s):
536
- return k - (_a(k, s) * 2**s)
537
-
538
-
539
- # given a binary representation of k with binary digits [k_{n-1},..,k_1,k_0],
540
- # the method k_s(k, s) returns k_s
541
-
542
-
543
- def _k_s(k, s):
544
- if k == 0:
545
- return 0
546
- else:
547
- num_digits = s + 1
548
- return _get_binary_rep_as_list(k, num_digits)[0]
549
-
550
-
551
- # Check if a gate of a special form is equal to the identity gate up to global phase
552
-
553
-
554
- def _ucg_is_identity_up_to_global_phase(single_qubit_gates, epsilon):
555
- if not np.abs(single_qubit_gates[0][0, 0]) < epsilon:
556
- global_phase = 1.0 / (single_qubit_gates[0][0, 0])
557
- else:
558
- return False
559
- for gate in single_qubit_gates:
560
- if not np.allclose(global_phase * gate, np.eye(2, 2)):
561
- return False
562
- return True
563
-
564
-
565
- def _diag_is_identity_up_to_global_phase(diag, epsilon):
566
- if not np.abs(diag[0]) < epsilon:
567
- global_phase = 1.0 / (diag[0])
568
- else:
569
- return False
570
- for d in diag:
571
- if not np.abs(global_phase * d - 1) < epsilon:
572
- return False
573
- return True
@@ -63,13 +63,13 @@ class PauliGate(Gate):
63
63
  r"""Return inverted pauli gate (itself)."""
64
64
  return PauliGate(self.params[0]) # self-inverse
65
65
 
66
- def __array__(self, dtype=None):
66
+ def __array__(self, dtype=None, copy=None):
67
67
  """Return a Numpy.array for the pauli gate.
68
68
  i.e. tensor product of the paulis"""
69
69
  # pylint: disable=cyclic-import
70
70
  from qiskit.quantum_info.operators import Pauli
71
71
 
72
- return Pauli(self.params[0]).__array__(dtype=dtype)
72
+ return Pauli(self.params[0]).__array__(dtype=dtype, copy=copy)
73
73
 
74
74
  def validate_parameter(self, parameter):
75
75
  if isinstance(parameter, str):
@@ -147,8 +147,11 @@ class PermutationGate(Gate):
147
147
 
148
148
  super().__init__(name="permutation", num_qubits=num_qubits, params=[pattern])
149
149
 
150
- def __array__(self, dtype=None):
150
+ def __array__(self, dtype=None, copy=None):
151
151
  """Return a numpy.array for the Permutation gate."""
152
+ if copy is False:
153
+ raise ValueError("unable to avoid copy while creating an array as requested")
154
+
152
155
  nq = len(self.pattern)
153
156
  mat = np.zeros((2**nq, 2**nq), dtype=dtype)
154
157
 
@@ -12,13 +12,14 @@
12
12
 
13
13
  """Rotation around an arbitrary axis on the Bloch sphere."""
14
14
 
15
+ import math
15
16
  import numpy
16
17
  from qiskit.circuit.gate import Gate
17
18
  from qiskit.circuit.exceptions import CircuitError
18
19
 
19
20
 
20
21
  class RVGate(Gate):
21
- r"""Rotation around arbitrary rotation axis :math:`v` where :math:`|v|` is
22
+ r"""Rotation around arbitrary rotation axis :math:`\vec{v}` where :math:`\|\vec{v}\|_2` is
22
23
  angle of rotation in radians.
23
24
 
24
25
  Can be applied to a :class:`~qiskit.circuit.QuantumCircuit`
@@ -36,14 +37,17 @@ class RVGate(Gate):
36
37
 
37
38
  .. math::
38
39
 
39
- \newcommand{\rotationangle}{|\vec{v}|}
40
- \newcommand{\sinc}{\text{sinc}}
41
- R(\vec{v}) = e^{-i \vec{v}\cdot\vec{\sigma}} =
40
+ \newcommand{\rotationangle}{\frac{\|\vec{v}\|_2}{2}}
41
+ R(\vec{v}) = e^{-i \vec{v}\cdot\vec{\sigma} / 2} =
42
42
  \begin{pmatrix}
43
- \cos\left(\rotationangle\right) -i v_z \sinc\left(\rotationangle\right)
44
- & -(i v_x + v_y) \sinc\left(\rotationangle\right) \\
45
- -(i v_x - v_y) \sinc\left(\rotationangle\right)
46
- & \cos\left(\rotationangle\right) + i v_z \sinc\left(\rotationangle\right)
43
+ \cos\left(\rotationangle\right)
44
+ -i \frac{v_z}{\|\vec{v}\|_2} \sin\left(\rotationangle\right)
45
+ & -(i \frac{v_x}{\|\vec{v}\|_2}
46
+ + \frac{v_y}{\|\vec{v}\|_2}) \sin\left(\rotationangle\right) \\
47
+ -(i \frac{v_x}{\|\vec{v}\|_2}
48
+ - \frac{v_y}{\|\vec{v}\|_2}) \sin\left(\rotationangle\right)
49
+ & \cos\left(\rotationangle\right)
50
+ + i \frac{v_z}{\|\vec{v}\|_2} \sin\left(\rotationangle\right)
47
51
  \end{pmatrix}
48
52
  """
49
53
 
@@ -79,12 +83,12 @@ class RVGate(Gate):
79
83
  def to_matrix(self):
80
84
  """Return a numpy.array for the R(v) gate."""
81
85
  v = numpy.asarray(self.params, dtype=float)
82
- angle = numpy.sqrt(v.dot(v))
86
+ angle = math.sqrt(v.dot(v))
83
87
  if angle == 0:
84
88
  return numpy.array([[1, 0], [0, 1]])
85
89
  nx, ny, nz = v / angle
86
- sin = numpy.sin(angle / 2)
87
- cos = numpy.cos(angle / 2)
90
+ sin = math.sin(angle / 2)
91
+ cos = math.cos(angle / 2)
88
92
  return numpy.array(
89
93
  [
90
94
  [cos - 1j * nz * sin, (-ny - 1j * nx) * sin],
@@ -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):