qiskit 2.0.3__cp39-abi3-macosx_11_0_arm64.whl → 2.1.0__cp39-abi3-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +19 -1
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/circuit/__init__.py +104 -20
- qiskit/circuit/_add_control.py +57 -31
- qiskit/circuit/_classical_resource_map.py +4 -0
- qiskit/circuit/annotation.py +504 -0
- qiskit/circuit/classical/expr/__init__.py +1 -1
- qiskit/circuit/classical/expr/expr.py +104 -446
- qiskit/circuit/classical/expr/visitors.py +6 -0
- qiskit/circuit/classical/types/types.py +7 -130
- qiskit/circuit/controlflow/box.py +32 -7
- qiskit/circuit/delay.py +11 -9
- qiskit/circuit/library/arithmetic/adders/adder.py +4 -4
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +2 -2
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +8 -4
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +23 -15
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +22 -14
- qiskit/circuit/library/arithmetic/quadratic_form.py +6 -0
- qiskit/circuit/library/arithmetic/weighted_adder.py +43 -24
- qiskit/circuit/library/basis_change/qft.py +2 -2
- qiskit/circuit/library/blueprintcircuit.py +6 -0
- qiskit/circuit/library/boolean_logic/inner_product.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_and.py +2 -2
- qiskit/circuit/library/boolean_logic/quantum_or.py +3 -3
- qiskit/circuit/library/boolean_logic/quantum_xor.py +2 -2
- qiskit/circuit/library/data_preparation/_z_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/_zz_feature_map.py +2 -2
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +2 -2
- qiskit/circuit/library/fourier_checking.py +2 -2
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -1
- qiskit/circuit/library/generalized_gates/gms.py +5 -1
- qiskit/circuit/library/generalized_gates/linear_function.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +5 -1
- qiskit/circuit/library/generalized_gates/uc.py +1 -1
- qiskit/circuit/library/generalized_gates/unitary.py +21 -2
- qiskit/circuit/library/graph_state.py +2 -2
- qiskit/circuit/library/grover_operator.py +2 -2
- qiskit/circuit/library/hidden_linear_function.py +2 -2
- qiskit/circuit/library/iqp.py +2 -2
- qiskit/circuit/library/n_local/efficient_su2.py +2 -2
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
- qiskit/circuit/library/n_local/excitation_preserving.py +7 -9
- qiskit/circuit/library/n_local/n_local.py +4 -3
- qiskit/circuit/library/n_local/pauli_two_design.py +2 -2
- qiskit/circuit/library/n_local/real_amplitudes.py +2 -2
- qiskit/circuit/library/n_local/two_local.py +2 -2
- qiskit/circuit/library/overlap.py +2 -2
- qiskit/circuit/library/pauli_evolution.py +3 -2
- qiskit/circuit/library/phase_estimation.py +2 -2
- qiskit/circuit/library/standard_gates/dcx.py +11 -12
- qiskit/circuit/library/standard_gates/ecr.py +21 -24
- qiskit/circuit/library/standard_gates/equivalence_library.py +232 -96
- qiskit/circuit/library/standard_gates/global_phase.py +5 -6
- qiskit/circuit/library/standard_gates/h.py +22 -45
- qiskit/circuit/library/standard_gates/i.py +1 -1
- qiskit/circuit/library/standard_gates/iswap.py +13 -31
- qiskit/circuit/library/standard_gates/p.py +19 -26
- qiskit/circuit/library/standard_gates/r.py +11 -17
- qiskit/circuit/library/standard_gates/rx.py +21 -45
- qiskit/circuit/library/standard_gates/rxx.py +7 -22
- qiskit/circuit/library/standard_gates/ry.py +21 -39
- qiskit/circuit/library/standard_gates/ryy.py +13 -28
- qiskit/circuit/library/standard_gates/rz.py +18 -35
- qiskit/circuit/library/standard_gates/rzx.py +7 -22
- qiskit/circuit/library/standard_gates/rzz.py +7 -19
- qiskit/circuit/library/standard_gates/s.py +44 -39
- qiskit/circuit/library/standard_gates/swap.py +25 -38
- qiskit/circuit/library/standard_gates/sx.py +34 -41
- qiskit/circuit/library/standard_gates/t.py +18 -27
- qiskit/circuit/library/standard_gates/u.py +8 -24
- qiskit/circuit/library/standard_gates/u1.py +28 -52
- qiskit/circuit/library/standard_gates/u2.py +9 -9
- qiskit/circuit/library/standard_gates/u3.py +24 -40
- qiskit/circuit/library/standard_gates/x.py +190 -336
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +12 -50
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +13 -52
- qiskit/circuit/library/standard_gates/y.py +19 -23
- qiskit/circuit/library/standard_gates/z.py +31 -38
- qiskit/circuit/parameter.py +14 -5
- qiskit/circuit/parameterexpression.py +109 -75
- qiskit/circuit/quantumcircuit.py +172 -99
- qiskit/circuit/quantumcircuitdata.py +1 -0
- qiskit/circuit/random/__init__.py +37 -2
- qiskit/circuit/random/utils.py +445 -56
- qiskit/circuit/tools/pi_check.py +5 -13
- qiskit/compiler/transpiler.py +1 -1
- qiskit/converters/circuit_to_instruction.py +2 -2
- qiskit/dagcircuit/dagnode.py +8 -3
- qiskit/primitives/__init__.py +2 -2
- qiskit/primitives/base/base_estimator.py +2 -2
- qiskit/primitives/containers/data_bin.py +0 -3
- qiskit/primitives/containers/observables_array.py +192 -108
- qiskit/primitives/primitive_job.py +29 -10
- qiskit/providers/fake_provider/generic_backend_v2.py +2 -0
- qiskit/qasm3/__init__.py +106 -12
- qiskit/qasm3/ast.py +15 -1
- qiskit/qasm3/exporter.py +59 -36
- qiskit/qasm3/printer.py +12 -0
- qiskit/qpy/__init__.py +182 -6
- qiskit/qpy/binary_io/circuits.py +256 -24
- qiskit/qpy/binary_io/parse_sympy_repr.py +5 -0
- qiskit/qpy/binary_io/schedules.py +12 -32
- qiskit/qpy/binary_io/value.py +36 -18
- qiskit/qpy/common.py +11 -3
- qiskit/qpy/formats.py +17 -1
- qiskit/qpy/interface.py +52 -12
- qiskit/qpy/type_keys.py +7 -1
- qiskit/quantum_info/__init__.py +10 -0
- qiskit/quantum_info/operators/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/__init__.py +1 -0
- qiskit/quantum_info/operators/symplectic/clifford_circuits.py +26 -0
- qiskit/quantum_info/operators/symplectic/pauli.py +2 -2
- qiskit/result/sampled_expval.py +3 -1
- qiskit/synthesis/__init__.py +10 -0
- qiskit/synthesis/arithmetic/__init__.py +1 -1
- qiskit/synthesis/arithmetic/adders/__init__.py +1 -0
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +6 -2
- qiskit/synthesis/arithmetic/adders/rv_ripple_carry_adder.py +156 -0
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +14 -126
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +161 -121
- qiskit/synthesis/evolution/lie_trotter.py +10 -7
- qiskit/synthesis/evolution/product_formula.py +10 -7
- qiskit/synthesis/evolution/qdrift.py +10 -7
- qiskit/synthesis/evolution/suzuki_trotter.py +10 -7
- qiskit/synthesis/multi_controlled/__init__.py +4 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +402 -178
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +14 -15
- qiskit/synthesis/qft/qft_decompose_lnn.py +7 -25
- qiskit/synthesis/unitary/qsd.py +80 -9
- qiskit/transpiler/__init__.py +10 -3
- qiskit/transpiler/instruction_durations.py +2 -20
- qiskit/transpiler/passes/__init__.py +5 -2
- qiskit/transpiler/passes/layout/dense_layout.py +26 -6
- qiskit/transpiler/passes/layout/disjoint_utils.py +1 -166
- qiskit/transpiler/passes/layout/sabre_layout.py +22 -3
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +1 -1
- qiskit/transpiler/passes/layout/vf2_layout.py +49 -13
- qiskit/transpiler/passes/layout/vf2_utils.py +10 -0
- qiskit/transpiler/passes/optimization/__init__.py +1 -1
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +2 -1
- qiskit/transpiler/passes/optimization/optimize_clifford_t.py +68 -0
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -9
- qiskit/transpiler/passes/routing/sabre_swap.py +4 -2
- qiskit/transpiler/passes/routing/star_prerouting.py +106 -81
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/__init__.py +1 -0
- qiskit/transpiler/passes/scheduling/padding/context_aware_dynamical_decoupling.py +876 -0
- qiskit/transpiler/passes/synthesis/__init__.py +1 -0
- qiskit/transpiler/passes/synthesis/clifford_unitary_synth_plugin.py +123 -0
- qiskit/transpiler/passes/synthesis/hls_plugins.py +494 -93
- qiskit/transpiler/passes/synthesis/plugin.py +4 -0
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +27 -22
- qiskit/transpiler/passmanager_config.py +3 -0
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +149 -28
- qiskit/transpiler/preset_passmanagers/common.py +101 -0
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +6 -0
- qiskit/transpiler/preset_passmanagers/level3.py +2 -2
- qiskit/transpiler/target.py +15 -2
- qiskit/utils/optionals.py +6 -5
- qiskit/visualization/circuit/_utils.py +5 -3
- qiskit/visualization/circuit/latex.py +9 -2
- qiskit/visualization/circuit/matplotlib.py +26 -4
- qiskit/visualization/circuit/qcstyle.py +9 -157
- qiskit/visualization/dag/__init__.py +13 -0
- qiskit/visualization/dag/dagstyle.py +103 -0
- qiskit/visualization/dag/styles/__init__.py +13 -0
- qiskit/visualization/dag/styles/color.json +10 -0
- qiskit/visualization/dag/styles/plain.json +5 -0
- qiskit/visualization/dag_visualization.py +169 -98
- qiskit/visualization/style.py +223 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/METADATA +7 -6
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/RECORD +178 -169
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/entry_points.txt +6 -0
- qiskit/synthesis/discrete_basis/commutator_decompose.py +0 -265
- qiskit/synthesis/discrete_basis/gate_sequence.py +0 -421
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/WHEEL +0 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/licenses/LICENSE.txt +0 -0
- {qiskit-2.0.3.dist-info → qiskit-2.1.0.dist-info}/top_level.txt +0 -0
@@ -1,421 +0,0 @@
|
|
1
|
-
# This code is part of Qiskit.
|
2
|
-
#
|
3
|
-
# (C) Copyright IBM 2017, 2024.
|
4
|
-
#
|
5
|
-
# This code is licensed under the Apache License, Version 2.0. You may
|
6
|
-
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
7
|
-
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
8
|
-
#
|
9
|
-
# Any modifications or derivative works of this code must retain this
|
10
|
-
# copyright notice, and modified files need to carry a notice indicating
|
11
|
-
# that they have been altered from the originals.
|
12
|
-
|
13
|
-
"""Algebra utilities and the ``GateSequence`` class."""
|
14
|
-
|
15
|
-
from __future__ import annotations
|
16
|
-
|
17
|
-
from collections.abc import Sequence
|
18
|
-
import math
|
19
|
-
import numpy as np
|
20
|
-
|
21
|
-
from qiskit.circuit import Gate, QuantumCircuit, Qubit
|
22
|
-
from qiskit.circuit.library.generalized_gates.unitary import UnitaryGate
|
23
|
-
|
24
|
-
|
25
|
-
class GateSequence:
|
26
|
-
"""A class implementing a sequence of gates.
|
27
|
-
|
28
|
-
This class stores the sequence of gates along with the unitary they implement.
|
29
|
-
"""
|
30
|
-
|
31
|
-
def __init__(self, gates: Sequence[Gate] = ()) -> None:
|
32
|
-
"""Create a new sequence of gates.
|
33
|
-
|
34
|
-
Args:
|
35
|
-
gates: The gates in the sequence. The default is [].
|
36
|
-
"""
|
37
|
-
self.gates = list(gates)
|
38
|
-
self.matrices = [np.asarray(gate, dtype=np.complex128) for gate in gates]
|
39
|
-
self.labels = [gate.name for gate in gates]
|
40
|
-
|
41
|
-
# get U(2) representation of the gate sequence
|
42
|
-
u2_matrix = np.identity(2)
|
43
|
-
for matrix in self.matrices:
|
44
|
-
# idea: could this be optimized by a specific numpy operation?
|
45
|
-
u2_matrix = matrix.dot(u2_matrix)
|
46
|
-
|
47
|
-
# convert to SU(2)
|
48
|
-
su2_matrix, global_phase = _convert_u2_to_su2(u2_matrix)
|
49
|
-
|
50
|
-
# convert to SO(3), that's what the Solovay Kitaev algorithm uses
|
51
|
-
so3_matrix = _convert_su2_to_so3(su2_matrix)
|
52
|
-
|
53
|
-
# store the matrix and the global phase
|
54
|
-
self._eulers = None
|
55
|
-
self.name = " ".join(self.labels)
|
56
|
-
self.global_phase = global_phase
|
57
|
-
self.product = so3_matrix
|
58
|
-
|
59
|
-
def remove_cancelling_pair(self, indices: Sequence[int]) -> None:
|
60
|
-
"""Remove a pair of indices that cancel each other and *do not* change the matrices."""
|
61
|
-
for index in list(indices[::-1]):
|
62
|
-
self.gates.pop(index)
|
63
|
-
self.labels.pop(index)
|
64
|
-
|
65
|
-
# restore name
|
66
|
-
self.name = " ".join(self.labels)
|
67
|
-
|
68
|
-
def __eq__(self, other: "GateSequence") -> bool:
|
69
|
-
"""Check if this GateSequence is the same as the other GateSequence.
|
70
|
-
|
71
|
-
Args:
|
72
|
-
other: The GateSequence that will be compared to ``self``.
|
73
|
-
|
74
|
-
Returns:
|
75
|
-
True if ``other`` is equivalent to ``self``, false otherwise.
|
76
|
-
|
77
|
-
"""
|
78
|
-
if not len(self.gates) == len(other.gates):
|
79
|
-
return False
|
80
|
-
|
81
|
-
for gate1, gate2 in zip(self.gates, other.gates):
|
82
|
-
if gate1 != gate2:
|
83
|
-
return False
|
84
|
-
|
85
|
-
if self.global_phase != other.global_phase:
|
86
|
-
return False
|
87
|
-
|
88
|
-
return True
|
89
|
-
|
90
|
-
def to_circuit(self):
|
91
|
-
"""Convert to a circuit.
|
92
|
-
|
93
|
-
If no gates set but the product is not the identity, returns a circuit with a
|
94
|
-
unitary operation to implement the matrix.
|
95
|
-
"""
|
96
|
-
if len(self.gates) == 0 and not np.allclose(self.product, np.identity(3)):
|
97
|
-
circuit = QuantumCircuit(1, global_phase=self.global_phase)
|
98
|
-
su2 = _convert_so3_to_su2(self.product)
|
99
|
-
circuit.unitary(su2, [0])
|
100
|
-
return circuit
|
101
|
-
|
102
|
-
circuit = QuantumCircuit(1, global_phase=self.global_phase)
|
103
|
-
for gate in self.gates:
|
104
|
-
circuit.append(gate, [0])
|
105
|
-
|
106
|
-
return circuit
|
107
|
-
|
108
|
-
def _to_u2(self):
|
109
|
-
"""Creates the U2 matrix corresponding to the stored sequence of gates
|
110
|
-
and the global phase.
|
111
|
-
"""
|
112
|
-
u2 = np.eye(2, dtype=complex)
|
113
|
-
for mat in self.gates:
|
114
|
-
u2 = mat.to_matrix().dot(u2)
|
115
|
-
u2 = np.exp(1j * self.global_phase) * u2
|
116
|
-
return u2
|
117
|
-
|
118
|
-
def to_dag(self):
|
119
|
-
"""Convert to a :class:`.DAGCircuit`.
|
120
|
-
|
121
|
-
If no gates set but the product is not the identity, returns a circuit with a
|
122
|
-
unitary operation to implement the matrix.
|
123
|
-
"""
|
124
|
-
from qiskit.dagcircuit import DAGCircuit
|
125
|
-
|
126
|
-
qreg = (Qubit(),)
|
127
|
-
dag = DAGCircuit()
|
128
|
-
dag.add_qubits(qreg)
|
129
|
-
|
130
|
-
if len(self.gates) == 0 and not np.allclose(self.product, np.identity(3)):
|
131
|
-
su2 = _convert_so3_to_su2(self.product)
|
132
|
-
dag.apply_operation_back(UnitaryGate(su2), qreg, check=False)
|
133
|
-
return dag
|
134
|
-
|
135
|
-
dag.global_phase = self.global_phase
|
136
|
-
for gate in self.gates:
|
137
|
-
dag.apply_operation_back(gate, qreg, check=False)
|
138
|
-
|
139
|
-
return dag
|
140
|
-
|
141
|
-
def append(self, gate: Gate) -> "GateSequence":
|
142
|
-
"""Append gate to the sequence of gates.
|
143
|
-
|
144
|
-
Args:
|
145
|
-
gate: The gate to be appended.
|
146
|
-
|
147
|
-
Returns:
|
148
|
-
GateSequence with ``gate`` appended.
|
149
|
-
"""
|
150
|
-
# invalidate euler angles and name
|
151
|
-
self._eulers = None
|
152
|
-
|
153
|
-
# TODO: this recomputes the product whenever we append something, which could be more
|
154
|
-
# efficient by storing the current matrix and just multiplying the input gate to it
|
155
|
-
# self.product = convert_su2_to_so3(self._compute_product(self.gates))
|
156
|
-
matrix = np.array(gate, dtype=np.complex128)
|
157
|
-
su2, phase = _convert_u2_to_su2(matrix)
|
158
|
-
so3 = _convert_su2_to_so3(su2)
|
159
|
-
|
160
|
-
self.product = so3.dot(self.product)
|
161
|
-
self.global_phase = self.global_phase + phase
|
162
|
-
|
163
|
-
self.gates.append(gate)
|
164
|
-
if len(self.labels) > 0:
|
165
|
-
self.name += f" {gate.name}"
|
166
|
-
else:
|
167
|
-
self.name = gate.name
|
168
|
-
self.labels.append(gate.name)
|
169
|
-
|
170
|
-
self.matrices.append(matrix)
|
171
|
-
|
172
|
-
return self
|
173
|
-
|
174
|
-
def adjoint(self) -> "GateSequence":
|
175
|
-
"""Get the complex conjugate."""
|
176
|
-
# We're initializing an empty GateSequence and set the state manually, as we can
|
177
|
-
# efficiently infer the adjoint values from the current value instead of recomputing them.
|
178
|
-
adjoint = GateSequence()
|
179
|
-
adjoint.gates = [gate.inverse() for gate in reversed(self.gates)]
|
180
|
-
adjoint.labels = [inv.name for inv in adjoint.gates]
|
181
|
-
adjoint.name = " ".join(adjoint.labels)
|
182
|
-
adjoint.product = np.conj(self.product).T
|
183
|
-
adjoint.global_phase = -self.global_phase
|
184
|
-
|
185
|
-
return adjoint
|
186
|
-
|
187
|
-
def copy(self) -> "GateSequence":
|
188
|
-
"""Create copy of the sequence of gates.
|
189
|
-
|
190
|
-
Returns:
|
191
|
-
A new ``GateSequence`` containing copy of list of gates.
|
192
|
-
|
193
|
-
"""
|
194
|
-
out = type(self).__new__(type(self))
|
195
|
-
out.labels = self.labels.copy()
|
196
|
-
out.gates = self.gates.copy()
|
197
|
-
out.matrices = self.matrices.copy()
|
198
|
-
out.global_phase = self.global_phase
|
199
|
-
out.product = self.product.copy()
|
200
|
-
out.name = self.name
|
201
|
-
out._eulers = self._eulers
|
202
|
-
return out
|
203
|
-
|
204
|
-
def __len__(self) -> int:
|
205
|
-
"""Return length of sequence of gates.
|
206
|
-
|
207
|
-
Returns:
|
208
|
-
Length of list containing gates.
|
209
|
-
"""
|
210
|
-
return len(self.gates)
|
211
|
-
|
212
|
-
def __getitem__(self, index: int) -> Gate:
|
213
|
-
"""Returns the gate at ``index`` from the list of gates.
|
214
|
-
|
215
|
-
Args
|
216
|
-
index: Index of gate in list that will be returned.
|
217
|
-
|
218
|
-
Returns:
|
219
|
-
The gate at ``index`` in the list of gates.
|
220
|
-
"""
|
221
|
-
return self.gates[index]
|
222
|
-
|
223
|
-
def __repr__(self) -> str:
|
224
|
-
"""Return string representation of this object.
|
225
|
-
|
226
|
-
Returns:
|
227
|
-
Representation of this sequence of gates.
|
228
|
-
"""
|
229
|
-
out = "["
|
230
|
-
for gate in self.gates:
|
231
|
-
out += gate.name
|
232
|
-
out += ", "
|
233
|
-
out += "]"
|
234
|
-
out += ", product: "
|
235
|
-
out += str(self.product)
|
236
|
-
return out
|
237
|
-
|
238
|
-
def __str__(self) -> str:
|
239
|
-
"""Return string representation of this object.
|
240
|
-
|
241
|
-
Returns:
|
242
|
-
Representation of this sequence of gates.
|
243
|
-
"""
|
244
|
-
out = "["
|
245
|
-
for gate in self.gates:
|
246
|
-
out += gate.name
|
247
|
-
out += ", "
|
248
|
-
out += "]"
|
249
|
-
out += ", product: \n"
|
250
|
-
out += str(self.product)
|
251
|
-
return out
|
252
|
-
|
253
|
-
@classmethod
|
254
|
-
def from_matrix(cls, matrix: np.ndarray) -> "GateSequence":
|
255
|
-
"""Initialize the gate sequence from a matrix, without a gate sequence.
|
256
|
-
|
257
|
-
Args:
|
258
|
-
matrix: The matrix, can be SU(2) or SO(3).
|
259
|
-
|
260
|
-
Returns:
|
261
|
-
A ``GateSequence`` initialized from the input matrix.
|
262
|
-
|
263
|
-
Raises:
|
264
|
-
ValueError: If the matrix has an invalid shape.
|
265
|
-
"""
|
266
|
-
instance = cls()
|
267
|
-
if matrix.shape == (2, 2):
|
268
|
-
instance.product = _convert_su2_to_so3(matrix)
|
269
|
-
elif matrix.shape == (3, 3):
|
270
|
-
instance.product = matrix
|
271
|
-
else:
|
272
|
-
raise ValueError(f"Matrix must have shape (3, 3) or (2, 2) but has {matrix.shape}.")
|
273
|
-
|
274
|
-
instance.gates = []
|
275
|
-
return instance
|
276
|
-
|
277
|
-
def dot(self, other: "GateSequence") -> "GateSequence":
|
278
|
-
"""Compute the dot-product with another gate sequence.
|
279
|
-
|
280
|
-
Args:
|
281
|
-
other: The other gate sequence.
|
282
|
-
|
283
|
-
Returns:
|
284
|
-
The dot-product as gate sequence.
|
285
|
-
"""
|
286
|
-
# We're initializing an empty GateSequence and set the state manually, as we can more
|
287
|
-
# efficiently compute the multiplied values from the already constructed matrices.
|
288
|
-
composed = GateSequence()
|
289
|
-
composed.gates = other.gates + self.gates
|
290
|
-
composed.labels = other.labels + self.labels
|
291
|
-
composed.name = " ".join(composed.labels)
|
292
|
-
composed.product = np.dot(self.product, other.product)
|
293
|
-
composed.global_phase = self.global_phase + other.global_phase
|
294
|
-
|
295
|
-
return composed
|
296
|
-
|
297
|
-
|
298
|
-
def _convert_u2_to_su2(u2_matrix: np.ndarray) -> tuple[np.ndarray, float]:
|
299
|
-
"""Convert a U(2) matrix to SU(2) by adding a global phase."""
|
300
|
-
z = 1 / np.sqrt(np.linalg.det(u2_matrix))
|
301
|
-
su2_matrix = z * u2_matrix
|
302
|
-
phase = np.arctan2(np.imag(z), np.real(z))
|
303
|
-
|
304
|
-
return su2_matrix, phase
|
305
|
-
|
306
|
-
|
307
|
-
def _compute_euler_angles_from_so3(matrix: np.ndarray) -> tuple[float, float, float]:
|
308
|
-
"""Computes the Euler angles from the SO(3)-matrix u.
|
309
|
-
|
310
|
-
Uses the algorithm from Gregory Slabaugh,
|
311
|
-
see `here <https://www.gregslabaugh.net/publications/euler.pdf>`_.
|
312
|
-
|
313
|
-
Args:
|
314
|
-
matrix: The SO(3)-matrix for which the Euler angles need to be computed.
|
315
|
-
|
316
|
-
Returns:
|
317
|
-
Tuple (phi, theta, psi), where phi is rotation about z-axis, theta rotation about y-axis
|
318
|
-
and psi rotation about x-axis.
|
319
|
-
"""
|
320
|
-
matrix = np.round(matrix, decimals=10)
|
321
|
-
if matrix[2][0] != 1 and matrix[2][1] != -1:
|
322
|
-
theta = -math.asin(matrix[2][0])
|
323
|
-
psi = math.atan2(matrix[2][1] / math.cos(theta), matrix[2][2] / math.cos(theta))
|
324
|
-
phi = math.atan2(matrix[1][0] / math.cos(theta), matrix[0][0] / math.cos(theta))
|
325
|
-
return phi, theta, psi
|
326
|
-
else:
|
327
|
-
phi = 0
|
328
|
-
if matrix[2][0] == 1:
|
329
|
-
theta = math.pi / 2
|
330
|
-
psi = phi + math.atan2(matrix[0][1], matrix[0][2])
|
331
|
-
else:
|
332
|
-
theta = -math.pi / 2
|
333
|
-
psi = -phi + math.atan2(-matrix[0][1], -matrix[0][2])
|
334
|
-
return phi, theta, psi
|
335
|
-
|
336
|
-
|
337
|
-
def _compute_su2_from_euler_angles(angles: tuple[float, float, float]) -> np.ndarray:
|
338
|
-
"""Computes SU(2)-matrix from Euler angles.
|
339
|
-
|
340
|
-
Args:
|
341
|
-
angles: The tuple containing the Euler angles for which the corresponding SU(2)-matrix
|
342
|
-
needs to be computed.
|
343
|
-
|
344
|
-
Returns:
|
345
|
-
The SU(2)-matrix corresponding to the Euler angles in angles.
|
346
|
-
"""
|
347
|
-
phi, theta, psi = angles
|
348
|
-
uz_phi = np.array([[np.exp(-0.5j * phi), 0], [0, np.exp(0.5j * phi)]], dtype=complex)
|
349
|
-
uy_theta = np.array(
|
350
|
-
[[math.cos(theta / 2), math.sin(theta / 2)], [-math.sin(theta / 2), math.cos(theta / 2)]],
|
351
|
-
dtype=complex,
|
352
|
-
)
|
353
|
-
ux_psi = np.array(
|
354
|
-
[[math.cos(psi / 2), math.sin(psi / 2) * 1j], [math.sin(psi / 2) * 1j, math.cos(psi / 2)]],
|
355
|
-
dtype=complex,
|
356
|
-
)
|
357
|
-
return np.dot(uz_phi, np.dot(uy_theta, ux_psi))
|
358
|
-
|
359
|
-
|
360
|
-
def _convert_su2_to_so3(matrix: np.ndarray) -> np.ndarray:
|
361
|
-
"""Computes SO(3)-matrix from input SU(2)-matrix.
|
362
|
-
|
363
|
-
Args:
|
364
|
-
matrix: The SU(2)-matrix for which a corresponding SO(3)-matrix needs to be computed.
|
365
|
-
|
366
|
-
Returns:
|
367
|
-
The SO(3)-matrix corresponding to ``matrix``.
|
368
|
-
|
369
|
-
Raises:
|
370
|
-
ValueError: if ``matrix`` is not an SU(2)-matrix.
|
371
|
-
"""
|
372
|
-
_check_is_su2(matrix)
|
373
|
-
|
374
|
-
matrix = matrix.astype(complex)
|
375
|
-
a = np.real(matrix[0][0])
|
376
|
-
b = np.imag(matrix[0][0])
|
377
|
-
c = -np.real(matrix[0][1])
|
378
|
-
d = -np.imag(matrix[0][1])
|
379
|
-
rotation = np.array(
|
380
|
-
[
|
381
|
-
[a**2 - b**2 - c**2 + d**2, 2 * a * b + 2 * c * d, -2 * a * c + 2 * b * d],
|
382
|
-
[-2 * a * b + 2 * c * d, a**2 - b**2 + c**2 - d**2, 2 * a * d + 2 * b * c],
|
383
|
-
[2 * a * c + 2 * b * d, 2 * b * c - 2 * a * d, a**2 + b**2 - c**2 - d**2],
|
384
|
-
],
|
385
|
-
dtype=float,
|
386
|
-
)
|
387
|
-
return rotation
|
388
|
-
|
389
|
-
|
390
|
-
def _convert_so3_to_su2(matrix: np.ndarray) -> np.ndarray:
|
391
|
-
"""Converts an SO(3)-matrix to a corresponding SU(2)-matrix.
|
392
|
-
|
393
|
-
Args:
|
394
|
-
matrix: SO(3)-matrix to convert.
|
395
|
-
|
396
|
-
Returns:
|
397
|
-
SU(2)-matrix corresponding to SO(3)-matrix ``matrix``.
|
398
|
-
|
399
|
-
Raises:
|
400
|
-
ValueError: if ``matrix`` is not an SO(3)-matrix.
|
401
|
-
"""
|
402
|
-
_check_is_so3(matrix)
|
403
|
-
return _compute_su2_from_euler_angles(_compute_euler_angles_from_so3(matrix))
|
404
|
-
|
405
|
-
|
406
|
-
def _check_is_su2(matrix: np.ndarray) -> None:
|
407
|
-
"""Check whether ``matrix`` is SU(2), otherwise raise an error."""
|
408
|
-
if matrix.shape != (2, 2):
|
409
|
-
raise ValueError(f"Matrix must have shape (2, 2) but has {matrix.shape}.")
|
410
|
-
|
411
|
-
if abs(np.linalg.det(matrix) - 1) > 1e-4:
|
412
|
-
raise ValueError(f"Determinant of matrix must be 1, but is {np.linalg.det(matrix)}.")
|
413
|
-
|
414
|
-
|
415
|
-
def _check_is_so3(matrix: np.ndarray) -> None:
|
416
|
-
"""Check whether ``matrix`` is SO(3), otherwise raise an error."""
|
417
|
-
if matrix.shape != (3, 3):
|
418
|
-
raise ValueError(f"Matrix must have shape (3, 3) but has {matrix.shape}.")
|
419
|
-
|
420
|
-
if abs(np.linalg.det(matrix) - 1) > 1e-4:
|
421
|
-
raise ValueError(f"Determinant of matrix must be 1, but is {np.linalg.det(matrix)}.")
|
File without changes
|
File without changes
|
File without changes
|