pyqrack-cpu 2.1.2__tar.gz → 2.2.1__tar.gz
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.
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/Makefile +1 -1
- {pyqrack_cpu-2.1.2/pyqrack_cpu.egg-info → pyqrack_cpu-2.2.1}/PKG-INFO +1 -1
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_ace_backend.py +83 -346
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_simulator.py +19 -6
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_system/qrack_system.py +2 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1/pyqrack_cpu.egg-info}/PKG-INFO +1 -1
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/setup.py +1 -1
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/LICENSE +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/MANIFEST.in +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/README.md +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyproject.toml +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/__init__.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/pauli.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack_cpu.egg-info/SOURCES.txt +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack_cpu.egg-info/dependency_links.txt +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack_cpu.egg-info/not-zip-safe +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack_cpu.egg-info/requires.txt +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/pyqrack_cpu.egg-info/top_level.txt +0 -0
- {pyqrack_cpu-2.1.2 → pyqrack_cpu-2.2.1}/setup.cfg +0 -0
|
@@ -30,7 +30,7 @@ build-deps:
|
|
|
30
30
|
rm -rf pyqrack/qrack_system/qrack_cl_precompile
|
|
31
31
|
ifneq ($(OS),Windows_NT)
|
|
32
32
|
ifeq ($(QRACK_PRESENT),)
|
|
33
|
-
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout
|
|
33
|
+
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout ccb9cca0726e48c598696b51a66fb984ff8ab0f1; cd ..
|
|
34
34
|
endif
|
|
35
35
|
mkdir -p qrack/build
|
|
36
36
|
ifeq ($(UNAME_S),Linux)
|
|
@@ -29,169 +29,6 @@ except ImportError:
|
|
|
29
29
|
_IS_QISKIT_AER_AVAILABLE = False
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
# Initial stub and concept produced through conversation with Elara
|
|
33
|
-
# (the custom OpenAI GPT)
|
|
34
|
-
class LHVQubit:
|
|
35
|
-
def __init__(self, to_clone=None):
|
|
36
|
-
# Initial state in "Bloch vector" terms, defaults to |0⟩
|
|
37
|
-
if to_clone:
|
|
38
|
-
self.bloch = to_clone.bloch.copy()
|
|
39
|
-
else:
|
|
40
|
-
self.reset()
|
|
41
|
-
|
|
42
|
-
def reset(self):
|
|
43
|
-
self.bloch = [0.0, 0.0, 1.0]
|
|
44
|
-
|
|
45
|
-
def h(self):
|
|
46
|
-
# Hadamard: rotate around Y-axis then X-axis (simplified for LHV)
|
|
47
|
-
x, y, z = self.bloch
|
|
48
|
-
self.bloch = [(x + z) / math.sqrt(2), y, (z - x) / math.sqrt(2)]
|
|
49
|
-
|
|
50
|
-
def x(self):
|
|
51
|
-
x, y, z = self.bloch
|
|
52
|
-
self.bloch = [x, y, -z]
|
|
53
|
-
|
|
54
|
-
def y(self):
|
|
55
|
-
x, y, z = self.bloch
|
|
56
|
-
self.bloch = [-x, y, z]
|
|
57
|
-
|
|
58
|
-
def z(self):
|
|
59
|
-
x, y, z = self.bloch
|
|
60
|
-
self.bloch = [x, -y, z]
|
|
61
|
-
|
|
62
|
-
def rx(self, theta):
|
|
63
|
-
# Rotate Bloch vector around X-axis by angle theta
|
|
64
|
-
x, y, z = self.bloch
|
|
65
|
-
cos_theta = math.cos(theta)
|
|
66
|
-
sin_theta = math.sin(theta)
|
|
67
|
-
new_y = cos_theta * y - sin_theta * z
|
|
68
|
-
new_z = sin_theta * y + cos_theta * z
|
|
69
|
-
self.bloch = [x, new_y, new_z]
|
|
70
|
-
|
|
71
|
-
def ry(self, theta):
|
|
72
|
-
# Rotate Bloch vector around Y-axis by angle theta
|
|
73
|
-
x, y, z = self.bloch
|
|
74
|
-
cos_theta = math.cos(theta)
|
|
75
|
-
sin_theta = math.sin(theta)
|
|
76
|
-
new_x = cos_theta * x + sin_theta * z
|
|
77
|
-
new_z = -sin_theta * x + cos_theta * z
|
|
78
|
-
self.bloch = [new_x, y, new_z]
|
|
79
|
-
|
|
80
|
-
def rz(self, theta):
|
|
81
|
-
# Rotate Bloch vector around Z-axis by angle theta (in radians)
|
|
82
|
-
x, y, z = self.bloch
|
|
83
|
-
cos_theta = math.cos(theta)
|
|
84
|
-
sin_theta = math.sin(theta)
|
|
85
|
-
new_x = cos_theta * x - sin_theta * y
|
|
86
|
-
new_y = sin_theta * x + cos_theta * y
|
|
87
|
-
self.bloch = [new_x, new_y, z]
|
|
88
|
-
|
|
89
|
-
def s(self):
|
|
90
|
-
self.rz(math.pi / 2)
|
|
91
|
-
|
|
92
|
-
def adjs(self):
|
|
93
|
-
self.rz(-math.pi / 2)
|
|
94
|
-
|
|
95
|
-
def t(self):
|
|
96
|
-
self.rz(math.pi / 4)
|
|
97
|
-
|
|
98
|
-
def adjt(self):
|
|
99
|
-
self.rz(-math.pi / 4)
|
|
100
|
-
|
|
101
|
-
def u(self, theta, phi, lam):
|
|
102
|
-
# Apply general single-qubit unitary gate
|
|
103
|
-
self.rz(lam)
|
|
104
|
-
self.ry(theta)
|
|
105
|
-
self.rz(phi)
|
|
106
|
-
|
|
107
|
-
# Provided verbatim by Elara (the custom OpenAI GPT):
|
|
108
|
-
def mtrx(self, matrix):
|
|
109
|
-
"""
|
|
110
|
-
Apply a 2x2 unitary matrix to the LHV Bloch vector using only standard math/cmath.
|
|
111
|
-
Matrix format: [a, b, c, d] for [[a, b], [c, d]]
|
|
112
|
-
"""
|
|
113
|
-
a, b, c, d = matrix
|
|
114
|
-
|
|
115
|
-
# Current Bloch vector
|
|
116
|
-
x, y, z = self.bloch
|
|
117
|
-
|
|
118
|
-
# Convert to density matrix ρ = ½ (I + xσx + yσy + zσz)
|
|
119
|
-
rho = [[(1 + z) / 2, (x - 1j * y) / 2], [(x + 1j * y) / 2, (1 - z) / 2]]
|
|
120
|
-
|
|
121
|
-
# Compute U * ρ
|
|
122
|
-
u_rho = [
|
|
123
|
-
[a * rho[0][0] + b * rho[1][0], a * rho[0][1] + b * rho[1][1]],
|
|
124
|
-
[c * rho[0][0] + d * rho[1][0], c * rho[0][1] + d * rho[1][1]],
|
|
125
|
-
]
|
|
126
|
-
|
|
127
|
-
# Compute (U * ρ) * U†
|
|
128
|
-
rho_prime = [
|
|
129
|
-
[
|
|
130
|
-
u_rho[0][0] * a.conjugate() + u_rho[0][1] * b.conjugate(),
|
|
131
|
-
u_rho[0][0] * c.conjugate() + u_rho[0][1] * d.conjugate(),
|
|
132
|
-
],
|
|
133
|
-
[
|
|
134
|
-
u_rho[1][0] * a.conjugate() + u_rho[1][1] * b.conjugate(),
|
|
135
|
-
u_rho[1][0] * c.conjugate() + u_rho[1][1] * d.conjugate(),
|
|
136
|
-
],
|
|
137
|
-
]
|
|
138
|
-
|
|
139
|
-
# Extract Bloch components: Tr(ρ'σi) = 2 * Re[...]
|
|
140
|
-
new_x = 2 * rho_prime[0][1].real + 2 * rho_prime[1][0].real
|
|
141
|
-
new_y = 2 * (rho_prime[0][1].imag - rho_prime[1][0].imag)
|
|
142
|
-
new_z = 2 * rho_prime[0][0].real - 1 # since Tr(ρ') = 1
|
|
143
|
-
|
|
144
|
-
p = math.sqrt(new_x**2 + new_y**2 + new_z**2)
|
|
145
|
-
|
|
146
|
-
new_x /= p
|
|
147
|
-
new_y /= p
|
|
148
|
-
new_z /= p
|
|
149
|
-
|
|
150
|
-
self.bloch = [new_x, new_y, new_z]
|
|
151
|
-
|
|
152
|
-
def prob(self, basis=Pauli.PauliZ):
|
|
153
|
-
"""Sample a classical outcome from the current 'quantum' state"""
|
|
154
|
-
if basis == Pauli.PauliZ:
|
|
155
|
-
prob_1 = (1 - self.bloch[2]) / 2
|
|
156
|
-
elif basis == Pauli.PauliX:
|
|
157
|
-
prob_1 = (1 - self.bloch[0]) / 2
|
|
158
|
-
elif basis == Pauli.PauliY:
|
|
159
|
-
prob_1 = (1 - self.bloch[1]) / 2
|
|
160
|
-
else:
|
|
161
|
-
raise ValueError(f"Unsupported basis: {basis}")
|
|
162
|
-
return prob_1
|
|
163
|
-
|
|
164
|
-
def m(self):
|
|
165
|
-
result = random.random() < self.prob()
|
|
166
|
-
self.reset()
|
|
167
|
-
if result:
|
|
168
|
-
self.x()
|
|
169
|
-
return result
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
# Provided by Elara (the custom OpenAI GPT)
|
|
173
|
-
def _cpauli_lhv(prob, targ, axis, anti, theta=math.pi):
|
|
174
|
-
"""
|
|
175
|
-
Apply a 'soft' controlled-Pauli gate: rotate target qubit
|
|
176
|
-
proportionally to control's Z expectation value.
|
|
177
|
-
|
|
178
|
-
theta: full rotation angle if control in |1⟩
|
|
179
|
-
"""
|
|
180
|
-
# Control influence is (1 - ctrl.bloch[2]) / 2 = P(|1⟩)
|
|
181
|
-
# BUT we avoid collapse by using the expectation value:
|
|
182
|
-
control_influence = (1 - prob) if anti else prob
|
|
183
|
-
|
|
184
|
-
effective_theta = control_influence * theta
|
|
185
|
-
|
|
186
|
-
# Apply partial rotation to target qubit:
|
|
187
|
-
if axis == Pauli.PauliX:
|
|
188
|
-
targ.rx(effective_theta)
|
|
189
|
-
elif axis == Pauli.PauliY:
|
|
190
|
-
targ.ry(effective_theta)
|
|
191
|
-
elif axis == Pauli.PauliZ:
|
|
192
|
-
targ.rz(effective_theta)
|
|
193
|
-
|
|
194
|
-
|
|
195
32
|
class QrackAceBackend:
|
|
196
33
|
"""A back end for elided quantum error correction
|
|
197
34
|
|
|
@@ -276,6 +113,18 @@ class QrackAceBackend:
|
|
|
276
113
|
self._is_row_long_range[-1] = False
|
|
277
114
|
sim_count = col_patch_count * row_patch_count
|
|
278
115
|
|
|
116
|
+
# Boundary qubits no longer carry a private classical LHV proxy.
|
|
117
|
+
# Instead, every boundary site (row- and/or column-boundary alike)
|
|
118
|
+
# gets a real qubit in one single, shared "crossbar" QrackSimulator.
|
|
119
|
+
# That simulator's own greedy elision (set_sdrp) is trusted to
|
|
120
|
+
# automatically factor apart whatever boundary sites turn out to be
|
|
121
|
+
# separable (e.g. disjoint rails, rail intersections), exactly the
|
|
122
|
+
# same way it already factors apart unentangled subspaces within
|
|
123
|
+
# any other single QrackSimulator instance. We don't need to special
|
|
124
|
+
# -case "crossbar intersections" by hand; the elision does it for us.
|
|
125
|
+
boundary_sim_id = sim_count
|
|
126
|
+
boundary_count = 0
|
|
127
|
+
|
|
279
128
|
self._qubits = []
|
|
280
129
|
sim_counts = [0] * sim_count
|
|
281
130
|
sim_id = 0
|
|
@@ -290,9 +139,8 @@ class QrackAceBackend:
|
|
|
290
139
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
291
140
|
sim_counts[t_sim_id] += 1
|
|
292
141
|
|
|
293
|
-
qubit.append(
|
|
294
|
-
|
|
295
|
-
)
|
|
142
|
+
qubit.append((boundary_sim_id, boundary_count))
|
|
143
|
+
boundary_count += 1
|
|
296
144
|
|
|
297
145
|
if (not c) and (not r):
|
|
298
146
|
t_sim_id = (sim_id + col_patch_count) % sim_count
|
|
@@ -309,8 +157,23 @@ class QrackAceBackend:
|
|
|
309
157
|
self._qubits.append(qubit)
|
|
310
158
|
tot_qubits += 1
|
|
311
159
|
|
|
160
|
+
# The crossbar's size is fixed by how many boundary sites exist.
|
|
161
|
+
# When there are none (e.g. a grid small enough, relative to
|
|
162
|
+
# long_range_rows/columns, that the whole thing is "fully
|
|
163
|
+
# connected" with no QEC boundary at all), we must NOT allocate a
|
|
164
|
+
# 0-qubit QrackSimulator for the crossbar: a 0-qubit QrackSimulator
|
|
165
|
+
# can be constructed, but calling .clone() on one crashes the
|
|
166
|
+
# native Qrack core (segfault), and clone() is called routinely by
|
|
167
|
+
# measure_shots()/clone(). So the boundary sim is only created when
|
|
168
|
+
# boundary_count > 0, exactly mirroring how the original LHV-based
|
|
169
|
+
# code never instantiated anything for the boundary case when
|
|
170
|
+
# there were no boundary sites.
|
|
171
|
+
has_boundary = boundary_count > 0
|
|
172
|
+
if has_boundary:
|
|
173
|
+
sim_counts.append(boundary_count)
|
|
174
|
+
|
|
312
175
|
self.sim = []
|
|
313
|
-
for i in range(sim_count):
|
|
176
|
+
for i in range(sim_count + (1 if has_boundary else 0)):
|
|
314
177
|
self.sim.append(
|
|
315
178
|
to_clone.sim[i].clone()
|
|
316
179
|
if to_clone
|
|
@@ -331,6 +194,8 @@ class QrackAceBackend:
|
|
|
331
194
|
# (1 - 1 / sqrt(2)) / 4 (but empirically tuned)
|
|
332
195
|
self.sim[i].set_sdrp(0.073223304703363119)
|
|
333
196
|
|
|
197
|
+
self._boundary_sim_id = boundary_sim_id if has_boundary else None
|
|
198
|
+
|
|
334
199
|
def clone(self):
|
|
335
200
|
return QrackAceBackend(to_clone=self)
|
|
336
201
|
|
|
@@ -468,35 +333,23 @@ class QrackAceBackend:
|
|
|
468
333
|
|
|
469
334
|
@staticmethod
|
|
470
335
|
def _get_qb_lhv_indices(hq):
|
|
471
|
-
|
|
336
|
+
# Historically, index 2 (when present) pointed at a private
|
|
337
|
+
# classical LHVQubit proxy and had to be special-cased everywhere.
|
|
338
|
+
# It is now an ordinary (sim_id, idx) tuple into the shared
|
|
339
|
+
# boundary "crossbar" QrackSimulator, so it is just one more
|
|
340
|
+
# coupling target like every other index. We keep this helper's
|
|
341
|
+
# name and signature for minimal call-site churn; "lhv" is now
|
|
342
|
+
# always -1 (no index needs special-casing any more).
|
|
472
343
|
if len(hq) < 2:
|
|
473
344
|
qb = [0]
|
|
474
|
-
lhv = -1
|
|
475
345
|
elif len(hq) < 4:
|
|
476
|
-
qb = [0, 1]
|
|
477
|
-
lhv = 2
|
|
346
|
+
qb = [0, 1, 2]
|
|
478
347
|
else:
|
|
479
|
-
qb = [0, 1, 3, 4]
|
|
480
|
-
|
|
348
|
+
qb = [0, 1, 2, 3, 4]
|
|
349
|
+
lhv = -1
|
|
481
350
|
|
|
482
351
|
return qb, lhv
|
|
483
352
|
|
|
484
|
-
@staticmethod
|
|
485
|
-
def _get_lhv_bloch_angles(sim):
|
|
486
|
-
# Z axis
|
|
487
|
-
z = sim.bloch[2]
|
|
488
|
-
|
|
489
|
-
# X axis
|
|
490
|
-
x = sim.bloch[0]
|
|
491
|
-
|
|
492
|
-
# Y axis
|
|
493
|
-
y = sim.bloch[1]
|
|
494
|
-
|
|
495
|
-
inclination = math.atan2(math.sqrt(x**2 + y**2), z)
|
|
496
|
-
azimuth = math.atan2(y, x)
|
|
497
|
-
|
|
498
|
-
return azimuth, inclination
|
|
499
|
-
|
|
500
353
|
def _get_bloch_angles(self, hq):
|
|
501
354
|
sim = self.sim[hq[0]].clone()
|
|
502
355
|
q = hq[1]
|
|
@@ -539,42 +392,25 @@ class QrackAceBackend:
|
|
|
539
392
|
|
|
540
393
|
sim.mtrx([m00, m01, m10, m11], q)
|
|
541
394
|
|
|
542
|
-
@staticmethod
|
|
543
|
-
def _rotate_lhv_to_bloch(sim, delta_azimuth, delta_inclination):
|
|
544
|
-
# Apply rotation as "Azimuth, Inclination" (AI)
|
|
545
|
-
cosA = math.cos(delta_azimuth)
|
|
546
|
-
sinA = math.sin(delta_azimuth)
|
|
547
|
-
cosI = math.cos(delta_inclination / 2)
|
|
548
|
-
sinI = math.sin(delta_inclination / 2)
|
|
549
|
-
|
|
550
|
-
m00 = complex(cosI, 0)
|
|
551
|
-
m01 = complex(-cosA, sinA) * sinI
|
|
552
|
-
m10 = complex(cosA, sinA) * sinI
|
|
553
|
-
m11 = complex(cosI, 0)
|
|
554
|
-
|
|
555
|
-
sim.mtrx([m00, m01, m10, m11])
|
|
556
|
-
|
|
557
395
|
def _correct(self, lq, phase=False, skip_rotation=False):
|
|
558
396
|
hq = self._unpack(lq)
|
|
559
397
|
|
|
560
398
|
if len(hq) == 1:
|
|
561
399
|
return
|
|
562
400
|
|
|
563
|
-
qb,
|
|
401
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
564
402
|
|
|
565
403
|
if phase:
|
|
566
404
|
for q in qb:
|
|
567
405
|
b = hq[q]
|
|
568
406
|
self.sim[b[0]].h(b[1])
|
|
569
|
-
b = hq[lhv]
|
|
570
|
-
b.h()
|
|
571
407
|
|
|
572
408
|
if len(hq) == 5:
|
|
573
409
|
# RMS
|
|
574
410
|
p = [
|
|
575
411
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
576
412
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
577
|
-
hq[2].prob(),
|
|
413
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
578
414
|
self.sim[hq[3][0]].prob(hq[3][1]),
|
|
579
415
|
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
580
416
|
]
|
|
@@ -598,43 +434,27 @@ class QrackAceBackend:
|
|
|
598
434
|
)
|
|
599
435
|
for q in range(5):
|
|
600
436
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
601
|
-
|
|
602
|
-
hq[q].x()
|
|
603
|
-
else:
|
|
604
|
-
self.sim[hq[q][0]].x(hq[q][1])
|
|
437
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
605
438
|
|
|
606
439
|
if not skip_rotation:
|
|
607
440
|
a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
|
|
608
441
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
609
442
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
610
|
-
a[2], i[2] =
|
|
443
|
+
a[2], i[2] = self._get_bloch_angles(hq[2])
|
|
611
444
|
a[3], i[3] = self._get_bloch_angles(hq[3])
|
|
612
445
|
a[4], i[4] = self._get_bloch_angles(hq[4])
|
|
613
446
|
|
|
614
|
-
a_target =
|
|
615
|
-
i_target =
|
|
616
|
-
for x in range(5):
|
|
617
|
-
if x == 2:
|
|
618
|
-
continue
|
|
619
|
-
a_target += a[x]
|
|
620
|
-
i_target += i[x]
|
|
621
|
-
|
|
622
|
-
a_target /= 5
|
|
623
|
-
i_target /= 5
|
|
447
|
+
a_target = sum(a) / 5
|
|
448
|
+
i_target = sum(i) / 5
|
|
624
449
|
for x in range(5):
|
|
625
|
-
|
|
626
|
-
QrackAceBackend._rotate_lhv_to_bloch(
|
|
627
|
-
hq[x], a_target - a[x], i_target - i[x]
|
|
628
|
-
)
|
|
629
|
-
else:
|
|
630
|
-
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
450
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
631
451
|
|
|
632
452
|
else:
|
|
633
453
|
# RMS
|
|
634
454
|
p = [
|
|
635
455
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
636
456
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
637
|
-
hq[2].prob(),
|
|
457
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
638
458
|
]
|
|
639
459
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
640
460
|
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
|
|
@@ -643,41 +463,23 @@ class QrackAceBackend:
|
|
|
643
463
|
syndrome = [1 - p[0], 1 - p[1], 1 - p[2]] if result else [p[0], p[1], p[2]]
|
|
644
464
|
for q in range(3):
|
|
645
465
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
646
|
-
|
|
647
|
-
hq[q].x()
|
|
648
|
-
else:
|
|
649
|
-
self.sim[hq[q][0]].x(hq[q][1])
|
|
466
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
650
467
|
|
|
651
468
|
if not skip_rotation:
|
|
652
469
|
a, i = [0, 0, 0], [0, 0, 0]
|
|
653
470
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
654
471
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
655
|
-
a[2], i[2] =
|
|
656
|
-
|
|
657
|
-
a_target = 0
|
|
658
|
-
i_target = 0
|
|
659
|
-
for x in range(3):
|
|
660
|
-
if x == 2:
|
|
661
|
-
continue
|
|
662
|
-
a_target += a[x]
|
|
663
|
-
i_target += i[x]
|
|
472
|
+
a[2], i[2] = self._get_bloch_angles(hq[2])
|
|
664
473
|
|
|
665
|
-
a_target
|
|
666
|
-
i_target
|
|
474
|
+
a_target = sum(a) / 3
|
|
475
|
+
i_target = sum(i) / 3
|
|
667
476
|
for x in range(3):
|
|
668
|
-
|
|
669
|
-
QrackAceBackend._rotate_lhv_to_bloch(
|
|
670
|
-
hq[x], a_target - a[x], i_target - i[x]
|
|
671
|
-
)
|
|
672
|
-
else:
|
|
673
|
-
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
477
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
674
478
|
|
|
675
479
|
if phase:
|
|
676
480
|
for q in qb:
|
|
677
481
|
b = hq[q]
|
|
678
482
|
self.sim[b[0]].h(b[1])
|
|
679
|
-
b = hq[lhv]
|
|
680
|
-
b.h()
|
|
681
483
|
|
|
682
484
|
def apply_magnetic_bias(self, q, b):
|
|
683
485
|
if b == 0:
|
|
@@ -685,22 +487,13 @@ class QrackAceBackend:
|
|
|
685
487
|
b = math.exp(b)
|
|
686
488
|
for x in q:
|
|
687
489
|
hq = self._unpack(x)
|
|
688
|
-
for
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
math.atan(math.tan(i) * b) - i,
|
|
696
|
-
)
|
|
697
|
-
else:
|
|
698
|
-
a, i = self._get_bloch_angles(h)
|
|
699
|
-
self._rotate_to_bloch(
|
|
700
|
-
h,
|
|
701
|
-
math.atan(math.tan(a) * b) - a,
|
|
702
|
-
math.atan(math.tan(i) * b) - i,
|
|
703
|
-
)
|
|
490
|
+
for h in hq:
|
|
491
|
+
a, i = self._get_bloch_angles(h)
|
|
492
|
+
self._rotate_to_bloch(
|
|
493
|
+
h,
|
|
494
|
+
math.atan(math.tan(a) * b) - a,
|
|
495
|
+
math.atan(math.tan(i) * b) - i,
|
|
496
|
+
)
|
|
704
497
|
|
|
705
498
|
def u(self, lq, th, ph, lm):
|
|
706
499
|
hq = self._unpack(lq)
|
|
@@ -709,15 +502,12 @@ class QrackAceBackend:
|
|
|
709
502
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
710
503
|
return
|
|
711
504
|
|
|
712
|
-
qb,
|
|
505
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
713
506
|
|
|
714
507
|
for q in qb:
|
|
715
508
|
b = hq[q]
|
|
716
509
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
717
510
|
|
|
718
|
-
b = hq[lhv]
|
|
719
|
-
b.u(th, ph, lm)
|
|
720
|
-
|
|
721
511
|
# Correction deferred to next 2-qubit gate (_cpauli calls _correct)
|
|
722
512
|
|
|
723
513
|
def r(self, p, th, lq):
|
|
@@ -727,20 +517,12 @@ class QrackAceBackend:
|
|
|
727
517
|
self.sim[b[0]].r(p, th, b[1])
|
|
728
518
|
return
|
|
729
519
|
|
|
730
|
-
qb,
|
|
520
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
731
521
|
|
|
732
522
|
for q in qb:
|
|
733
523
|
b = hq[q]
|
|
734
524
|
self.sim[b[0]].r(p, th, b[1])
|
|
735
525
|
|
|
736
|
-
b = hq[lhv]
|
|
737
|
-
if p == Pauli.PauliX:
|
|
738
|
-
b.rx(th)
|
|
739
|
-
elif p == Pauli.PauliY:
|
|
740
|
-
b.ry(th)
|
|
741
|
-
elif p == Pauli.PauliZ:
|
|
742
|
-
b.rz(th)
|
|
743
|
-
|
|
744
526
|
# Correction deferred to next 2-qubit gate (_cpauli calls _correct)
|
|
745
527
|
|
|
746
528
|
def h(self, lq):
|
|
@@ -752,15 +534,12 @@ class QrackAceBackend:
|
|
|
752
534
|
|
|
753
535
|
self._correct(lq)
|
|
754
536
|
|
|
755
|
-
qb,
|
|
537
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
756
538
|
|
|
757
539
|
for q in qb:
|
|
758
540
|
b = hq[q]
|
|
759
541
|
self.sim[b[0]].h(b[1])
|
|
760
542
|
|
|
761
|
-
b = hq[lhv]
|
|
762
|
-
b.h()
|
|
763
|
-
|
|
764
543
|
# Correction deferred to next 2-qubit gate (_cpauli calls _correct)
|
|
765
544
|
|
|
766
545
|
def s(self, lq):
|
|
@@ -770,15 +549,12 @@ class QrackAceBackend:
|
|
|
770
549
|
self.sim[b[0]].s(b[1])
|
|
771
550
|
return
|
|
772
551
|
|
|
773
|
-
qb,
|
|
552
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
774
553
|
|
|
775
554
|
for q in qb:
|
|
776
555
|
b = hq[q]
|
|
777
556
|
self.sim[b[0]].s(b[1])
|
|
778
557
|
|
|
779
|
-
b = hq[lhv]
|
|
780
|
-
b.s()
|
|
781
|
-
|
|
782
558
|
def adjs(self, lq):
|
|
783
559
|
hq = self._unpack(lq)
|
|
784
560
|
if len(hq) < 2:
|
|
@@ -786,15 +562,12 @@ class QrackAceBackend:
|
|
|
786
562
|
self.sim[b[0]].adjs(b[1])
|
|
787
563
|
return
|
|
788
564
|
|
|
789
|
-
qb,
|
|
565
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
790
566
|
|
|
791
567
|
for q in qb:
|
|
792
568
|
b = hq[q]
|
|
793
569
|
self.sim[b[0]].adjs(b[1])
|
|
794
570
|
|
|
795
|
-
b = hq[lhv]
|
|
796
|
-
b.adjs()
|
|
797
|
-
|
|
798
571
|
def x(self, lq):
|
|
799
572
|
hq = self._unpack(lq)
|
|
800
573
|
if len(hq) < 2:
|
|
@@ -802,15 +575,12 @@ class QrackAceBackend:
|
|
|
802
575
|
self.sim[b[0]].x(b[1])
|
|
803
576
|
return
|
|
804
577
|
|
|
805
|
-
qb,
|
|
578
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
806
579
|
|
|
807
580
|
for q in qb:
|
|
808
581
|
b = hq[q]
|
|
809
582
|
self.sim[b[0]].x(b[1])
|
|
810
583
|
|
|
811
|
-
b = hq[lhv]
|
|
812
|
-
b.x()
|
|
813
|
-
|
|
814
584
|
def y(self, lq):
|
|
815
585
|
hq = self._unpack(lq)
|
|
816
586
|
if len(hq) < 2:
|
|
@@ -818,15 +588,12 @@ class QrackAceBackend:
|
|
|
818
588
|
self.sim[b[0]].y(b[1])
|
|
819
589
|
return
|
|
820
590
|
|
|
821
|
-
qb,
|
|
591
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
822
592
|
|
|
823
593
|
for q in qb:
|
|
824
594
|
b = hq[q]
|
|
825
595
|
self.sim[b[0]].y(b[1])
|
|
826
596
|
|
|
827
|
-
b = hq[lhv]
|
|
828
|
-
b.y()
|
|
829
|
-
|
|
830
597
|
def z(self, lq):
|
|
831
598
|
hq = self._unpack(lq)
|
|
832
599
|
if len(hq) < 2:
|
|
@@ -834,15 +601,12 @@ class QrackAceBackend:
|
|
|
834
601
|
self.sim[b[0]].z(b[1])
|
|
835
602
|
return
|
|
836
603
|
|
|
837
|
-
qb,
|
|
604
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
838
605
|
|
|
839
606
|
for q in qb:
|
|
840
607
|
b = hq[q]
|
|
841
608
|
self.sim[b[0]].z(b[1])
|
|
842
609
|
|
|
843
|
-
b = hq[lhv]
|
|
844
|
-
b.z()
|
|
845
|
-
|
|
846
610
|
def t(self, lq):
|
|
847
611
|
hq = self._unpack(lq)
|
|
848
612
|
if len(hq) < 2:
|
|
@@ -850,15 +614,12 @@ class QrackAceBackend:
|
|
|
850
614
|
self.sim[b[0]].t(b[1])
|
|
851
615
|
return
|
|
852
616
|
|
|
853
|
-
qb,
|
|
617
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
854
618
|
|
|
855
619
|
for q in qb:
|
|
856
620
|
b = hq[q]
|
|
857
621
|
self.sim[b[0]].t(b[1])
|
|
858
622
|
|
|
859
|
-
b = hq[lhv]
|
|
860
|
-
b.t()
|
|
861
|
-
|
|
862
623
|
def adjt(self, lq):
|
|
863
624
|
hq = self._unpack(lq)
|
|
864
625
|
if len(hq) < 2:
|
|
@@ -866,15 +627,12 @@ class QrackAceBackend:
|
|
|
866
627
|
self.sim[b[0]].adjt(b[1])
|
|
867
628
|
return
|
|
868
629
|
|
|
869
|
-
qb,
|
|
630
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
870
631
|
|
|
871
632
|
for q in qb:
|
|
872
633
|
b = hq[q]
|
|
873
634
|
self.sim[b[0]].adjt(b[1])
|
|
874
635
|
|
|
875
|
-
b = hq[lhv]
|
|
876
|
-
b.adjt()
|
|
877
|
-
|
|
878
636
|
def _get_gate(self, pauli, anti, sim_id):
|
|
879
637
|
gate = None
|
|
880
638
|
shadow = None
|
|
@@ -913,15 +671,11 @@ class QrackAceBackend:
|
|
|
913
671
|
|
|
914
672
|
return connected, boundary
|
|
915
673
|
|
|
916
|
-
def _apply_coupling(self, pauli, anti, qb1,
|
|
674
|
+
def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr):
|
|
917
675
|
for q1 in qb1:
|
|
918
|
-
if q1 == lhv1:
|
|
919
|
-
continue
|
|
920
676
|
b1 = hq1[q1]
|
|
921
677
|
gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
|
|
922
678
|
for q2 in qb2:
|
|
923
|
-
if q2 == lhv2:
|
|
924
|
-
continue
|
|
925
679
|
b2 = hq2[q2]
|
|
926
680
|
if b1[0] == b2[0]:
|
|
927
681
|
gate_fn([b1[1]], b2[1])
|
|
@@ -942,18 +696,11 @@ class QrackAceBackend:
|
|
|
942
696
|
|
|
943
697
|
self._correct(lq1)
|
|
944
698
|
|
|
945
|
-
qb1,
|
|
946
|
-
qb2,
|
|
947
|
-
# Apply cross coupling on
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
if lhv2 >= 0:
|
|
951
|
-
_cpauli_lhv(
|
|
952
|
-
hq1[lhv1].prob() if lhv1 >= 0 else self.sim[hq1[0][0]].prob(hq1[0][1]),
|
|
953
|
-
hq2[lhv2],
|
|
954
|
-
pauli,
|
|
955
|
-
anti,
|
|
956
|
-
)
|
|
699
|
+
qb1, _ = QrackAceBackend._get_qb_lhv_indices(hq1)
|
|
700
|
+
qb2, _ = QrackAceBackend._get_qb_lhv_indices(hq2)
|
|
701
|
+
# Apply cross coupling on every qubit, including former-LHV boundary
|
|
702
|
+
# qubits, which now live as real qubits in the shared boundary sim.
|
|
703
|
+
self._apply_coupling(pauli, anti, qb1, hq1, qb2, hq2, lq1_lr)
|
|
957
704
|
|
|
958
705
|
self._correct(lq1, True)
|
|
959
706
|
if pauli != Pauli.PauliZ:
|
|
@@ -1050,7 +797,7 @@ class QrackAceBackend:
|
|
|
1050
797
|
p = [
|
|
1051
798
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
1052
799
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
1053
|
-
hq[2].prob(),
|
|
800
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
1054
801
|
self.sim[hq[3][0]].prob(hq[3][1]),
|
|
1055
802
|
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
1056
803
|
]
|
|
@@ -1071,7 +818,7 @@ class QrackAceBackend:
|
|
|
1071
818
|
p = [
|
|
1072
819
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
1073
820
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
1074
|
-
hq[2].prob(),
|
|
821
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
1075
822
|
]
|
|
1076
823
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
1077
824
|
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
|
|
@@ -1088,7 +835,7 @@ class QrackAceBackend:
|
|
|
1088
835
|
p = self.prob(lq)
|
|
1089
836
|
result = ((p + self._epsilon) >= 1) or (random.random() < p)
|
|
1090
837
|
|
|
1091
|
-
qb,
|
|
838
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1092
839
|
|
|
1093
840
|
for q in qb:
|
|
1094
841
|
b = hq[q]
|
|
@@ -1099,11 +846,6 @@ class QrackAceBackend:
|
|
|
1099
846
|
else:
|
|
1100
847
|
self.sim[b[0]].force_m(b[1], result)
|
|
1101
848
|
|
|
1102
|
-
b = hq[lhv]
|
|
1103
|
-
b.reset()
|
|
1104
|
-
if result:
|
|
1105
|
-
b.x()
|
|
1106
|
-
|
|
1107
849
|
return result
|
|
1108
850
|
|
|
1109
851
|
def force_m(self, lq, result):
|
|
@@ -1114,7 +856,7 @@ class QrackAceBackend:
|
|
|
1114
856
|
|
|
1115
857
|
self._correct(lq)
|
|
1116
858
|
|
|
1117
|
-
qb,
|
|
859
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1118
860
|
|
|
1119
861
|
for q in qb:
|
|
1120
862
|
b = hq[q]
|
|
@@ -1125,12 +867,7 @@ class QrackAceBackend:
|
|
|
1125
867
|
else:
|
|
1126
868
|
self.sim[b[0]].force_m(b[1], result)
|
|
1127
869
|
|
|
1128
|
-
|
|
1129
|
-
b.reset()
|
|
1130
|
-
if result:
|
|
1131
|
-
b.x()
|
|
1132
|
-
|
|
1133
|
-
return c
|
|
870
|
+
return result
|
|
1134
871
|
|
|
1135
872
|
def m_all(self):
|
|
1136
873
|
# Randomize the order of measurement to amortize error.
|
|
@@ -554,8 +554,8 @@ class QrackSimulator:
|
|
|
554
554
|
Qrack.qrack_lib.MCAdjT(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
|
|
555
555
|
self._throw_if_error()
|
|
556
556
|
|
|
557
|
-
def mcu(self, c, q, th, ph, la):
|
|
558
|
-
"""Multi-controlled
|
|
557
|
+
def mcu(self, c, q, th, ph, la, gm=0.0):
|
|
558
|
+
"""Multi-controlled arbitrary unitary
|
|
559
559
|
|
|
560
560
|
If all controlled qubits are `|1>` then the unitary gate described by
|
|
561
561
|
parameters is applied to the target qubit.
|
|
@@ -566,6 +566,7 @@ class QrackSimulator:
|
|
|
566
566
|
th: theta
|
|
567
567
|
ph: phi
|
|
568
568
|
la: lambda
|
|
569
|
+
gm: gamma
|
|
569
570
|
|
|
570
571
|
Raises:
|
|
571
572
|
RuntimeError: QrackSimulator raised an exception.
|
|
@@ -578,6 +579,7 @@ class QrackSimulator:
|
|
|
578
579
|
ctypes.c_double(th),
|
|
579
580
|
ctypes.c_double(ph),
|
|
580
581
|
ctypes.c_double(la),
|
|
582
|
+
ctypes.c_double(gm),
|
|
581
583
|
)
|
|
582
584
|
self._throw_if_error()
|
|
583
585
|
|
|
@@ -736,8 +738,8 @@ class QrackSimulator:
|
|
|
736
738
|
Qrack.qrack_lib.MACAdjT(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
|
|
737
739
|
self._throw_if_error()
|
|
738
740
|
|
|
739
|
-
def macu(self, c, q, th, ph, la):
|
|
740
|
-
"""Anti multi-controlled
|
|
741
|
+
def macu(self, c, q, th, ph, la, gm=0.0):
|
|
742
|
+
"""Anti multi-controlled arbitrary unitary
|
|
741
743
|
|
|
742
744
|
If all controlled qubits are `|0>` then the unitary gate described by
|
|
743
745
|
parameters is applied to the target qubit.
|
|
@@ -748,6 +750,7 @@ class QrackSimulator:
|
|
|
748
750
|
th: theta
|
|
749
751
|
ph: phi
|
|
750
752
|
la: lambda
|
|
753
|
+
gm: gamma
|
|
751
754
|
|
|
752
755
|
Raises:
|
|
753
756
|
RuntimeError: QrackSimulator raised an exception.
|
|
@@ -760,11 +763,12 @@ class QrackSimulator:
|
|
|
760
763
|
ctypes.c_double(th),
|
|
761
764
|
ctypes.c_double(ph),
|
|
762
765
|
ctypes.c_double(la),
|
|
766
|
+
ctypes.c_double(gm),
|
|
763
767
|
)
|
|
764
768
|
self._throw_if_error()
|
|
765
769
|
|
|
766
770
|
def macmtrx(self, c, m, q):
|
|
767
|
-
"""Anti multi-controlled
|
|
771
|
+
"""Anti multi-controlled arbitrary operator
|
|
768
772
|
|
|
769
773
|
If all controlled qubits are `|0>` then the arbitrary operation by
|
|
770
774
|
parameters is applied to the target qubit.
|
|
@@ -4194,7 +4198,7 @@ class QrackSimulator:
|
|
|
4194
4198
|
float(operation.params[0]),
|
|
4195
4199
|
float(operation.params[1]),
|
|
4196
4200
|
)
|
|
4197
|
-
elif
|
|
4201
|
+
elif name == "cu3":
|
|
4198
4202
|
self._sim.mcu(
|
|
4199
4203
|
[q._index for q in operation.qubits[0:1]],
|
|
4200
4204
|
operation.qubits[1]._index,
|
|
@@ -4202,6 +4206,15 @@ class QrackSimulator:
|
|
|
4202
4206
|
float(operation.params[1]),
|
|
4203
4207
|
float(operation.params[2]),
|
|
4204
4208
|
)
|
|
4209
|
+
elif name == "cu":
|
|
4210
|
+
self._sim.mcu(
|
|
4211
|
+
[q._index for q in operation.qubits[0:1]],
|
|
4212
|
+
operation.qubits[1]._index,
|
|
4213
|
+
float(operation.params[0]),
|
|
4214
|
+
float(operation.params[1]),
|
|
4215
|
+
float(operation.params[2]),
|
|
4216
|
+
float(operation.params[3]),
|
|
4217
|
+
)
|
|
4205
4218
|
elif name == "cx":
|
|
4206
4219
|
self._sim.mcx([q._index for q in operation.qubits[0:1]], operation.qubits[1]._index)
|
|
4207
4220
|
elif name == "cy":
|
|
@@ -629,6 +629,7 @@ class QrackSystem:
|
|
|
629
629
|
c_double,
|
|
630
630
|
c_double,
|
|
631
631
|
c_double,
|
|
632
|
+
c_double,
|
|
632
633
|
]
|
|
633
634
|
|
|
634
635
|
self.qrack_lib.MCMtrx.restype = None
|
|
@@ -715,6 +716,7 @@ class QrackSystem:
|
|
|
715
716
|
c_double,
|
|
716
717
|
c_double,
|
|
717
718
|
c_double,
|
|
719
|
+
c_double,
|
|
718
720
|
]
|
|
719
721
|
|
|
720
722
|
self.qrack_lib.MACMtrx.restype = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|