pyqrack-cpu 1.61.2__py3-none-manylinux_2_35_x86_64.whl → 1.62.0__py3-none-manylinux_2_35_x86_64.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.
Potentially problematic release.
This version of pyqrack-cpu might be problematic. Click here for more details.
- pyqrack/qrack_ace_backend.py +75 -355
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.62.0.dist-info}/METADATA +1 -1
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.62.0.dist-info}/RECORD +6 -6
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.62.0.dist-info}/LICENSE +0 -0
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.62.0.dist-info}/WHEEL +0 -0
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.62.0.dist-info}/top_level.txt +0 -0
pyqrack/qrack_ace_backend.py
CHANGED
|
@@ -27,163 +27,6 @@ except ImportError:
|
|
|
27
27
|
_IS_QISKIT_AER_AVAILABLE = False
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
# Initial stub and concept produced through conversation with Elara
|
|
31
|
-
# (the custom OpenAI GPT)
|
|
32
|
-
class LHVQubit:
|
|
33
|
-
def __init__(self, toClone=None):
|
|
34
|
-
# Initial state in "Bloch vector" terms, defaults to |0⟩
|
|
35
|
-
if toClone:
|
|
36
|
-
self.bloch = toClone.bloch.copy()
|
|
37
|
-
else:
|
|
38
|
-
self.reset()
|
|
39
|
-
|
|
40
|
-
def reset(self):
|
|
41
|
-
self.bloch = [0.0, 0.0, 1.0]
|
|
42
|
-
|
|
43
|
-
def h(self):
|
|
44
|
-
# Hadamard: rotate around Y-axis then X-axis (simplified for LHV)
|
|
45
|
-
x, y, z = self.bloch
|
|
46
|
-
self.bloch = [(x + z) / math.sqrt(2), y, (z - x) / math.sqrt(2)]
|
|
47
|
-
|
|
48
|
-
def x(self):
|
|
49
|
-
x, y, z = self.bloch
|
|
50
|
-
self.bloch = [x, y, -z]
|
|
51
|
-
|
|
52
|
-
def y(self):
|
|
53
|
-
x, y, z = self.bloch
|
|
54
|
-
self.bloch = [-x, y, z]
|
|
55
|
-
|
|
56
|
-
def z(self):
|
|
57
|
-
x, y, z = self.bloch
|
|
58
|
-
self.bloch = [x, -y, z]
|
|
59
|
-
|
|
60
|
-
def rx(self, theta):
|
|
61
|
-
# Rotate Bloch vector around X-axis by angle theta
|
|
62
|
-
x, y, z = self.bloch
|
|
63
|
-
cos_theta = math.cos(theta)
|
|
64
|
-
sin_theta = math.sin(theta)
|
|
65
|
-
new_y = cos_theta * y - sin_theta * z
|
|
66
|
-
new_z = sin_theta * y + cos_theta * z
|
|
67
|
-
self.bloch = [x, new_y, new_z]
|
|
68
|
-
|
|
69
|
-
def ry(self, theta):
|
|
70
|
-
# Rotate Bloch vector around Y-axis by angle theta
|
|
71
|
-
x, y, z = self.bloch
|
|
72
|
-
cos_theta = math.cos(theta)
|
|
73
|
-
sin_theta = math.sin(theta)
|
|
74
|
-
new_x = cos_theta * x + sin_theta * z
|
|
75
|
-
new_z = -sin_theta * x + cos_theta * z
|
|
76
|
-
self.bloch = [new_x, y, new_z]
|
|
77
|
-
|
|
78
|
-
def rz(self, theta):
|
|
79
|
-
# Rotate Bloch vector around Z-axis by angle theta (in radians)
|
|
80
|
-
x, y, z = self.bloch
|
|
81
|
-
cos_theta = math.cos(theta)
|
|
82
|
-
sin_theta = math.sin(theta)
|
|
83
|
-
new_x = cos_theta * x - sin_theta * y
|
|
84
|
-
new_y = sin_theta * x + cos_theta * y
|
|
85
|
-
self.bloch = [new_x, new_y, z]
|
|
86
|
-
|
|
87
|
-
def s(self):
|
|
88
|
-
self.rz(math.pi / 2)
|
|
89
|
-
|
|
90
|
-
def adjs(self):
|
|
91
|
-
self.rz(-math.pi / 2)
|
|
92
|
-
|
|
93
|
-
def t(self):
|
|
94
|
-
self.rz(math.pi / 4)
|
|
95
|
-
|
|
96
|
-
def adjt(self):
|
|
97
|
-
self.rz(-math.pi / 4)
|
|
98
|
-
|
|
99
|
-
def u(self, theta, phi, lam):
|
|
100
|
-
# Apply general single-qubit unitary gate
|
|
101
|
-
self.rz(lam)
|
|
102
|
-
self.ry(theta)
|
|
103
|
-
self.rz(phi)
|
|
104
|
-
|
|
105
|
-
# Provided verbatim by Elara (the custom OpenAI GPT):
|
|
106
|
-
def mtrx(self, matrix):
|
|
107
|
-
"""
|
|
108
|
-
Apply a 2x2 unitary matrix to the LHV Bloch vector using only standard math/cmath.
|
|
109
|
-
Matrix format: [a, b, c, d] for [[a, b], [c, d]]
|
|
110
|
-
"""
|
|
111
|
-
a, b, c, d = matrix
|
|
112
|
-
|
|
113
|
-
# Current Bloch vector
|
|
114
|
-
x, y, z = self.bloch
|
|
115
|
-
|
|
116
|
-
# Convert to density matrix ρ = ½ (I + xσx + yσy + zσz)
|
|
117
|
-
rho = [[(1 + z) / 2, (x - 1j * y) / 2], [(x + 1j * y) / 2, (1 - z) / 2]]
|
|
118
|
-
|
|
119
|
-
# Compute U * ρ
|
|
120
|
-
u_rho = [
|
|
121
|
-
[a * rho[0][0] + b * rho[1][0], a * rho[0][1] + b * rho[1][1]],
|
|
122
|
-
[c * rho[0][0] + d * rho[1][0], c * rho[0][1] + d * rho[1][1]],
|
|
123
|
-
]
|
|
124
|
-
|
|
125
|
-
# Compute (U * ρ) * U†
|
|
126
|
-
rho_prime = [
|
|
127
|
-
[
|
|
128
|
-
u_rho[0][0] * a.conjugate() + u_rho[0][1] * b.conjugate(),
|
|
129
|
-
u_rho[0][0] * c.conjugate() + u_rho[0][1] * d.conjugate(),
|
|
130
|
-
],
|
|
131
|
-
[
|
|
132
|
-
u_rho[1][0] * a.conjugate() + u_rho[1][1] * b.conjugate(),
|
|
133
|
-
u_rho[1][0] * c.conjugate() + u_rho[1][1] * d.conjugate(),
|
|
134
|
-
],
|
|
135
|
-
]
|
|
136
|
-
|
|
137
|
-
# Extract Bloch components: Tr(ρ'σi) = 2 * Re[...]
|
|
138
|
-
new_x = 2 * rho_prime[0][1].real + 2 * rho_prime[1][0].real
|
|
139
|
-
new_y = 2 * (rho_prime[0][1].imag - rho_prime[1][0].imag)
|
|
140
|
-
new_z = 2 * rho_prime[0][0].real - 1 # since Tr(ρ') = 1
|
|
141
|
-
|
|
142
|
-
self.bloch = [new_x, new_y, new_z]
|
|
143
|
-
|
|
144
|
-
def prob(self, basis=Pauli.PauliZ):
|
|
145
|
-
"""Sample a classical outcome from the current 'quantum' state"""
|
|
146
|
-
if basis == Pauli.PauliZ:
|
|
147
|
-
prob_1 = (1 - self.bloch[2]) / 2
|
|
148
|
-
elif basis == Pauli.PauliX:
|
|
149
|
-
prob_1 = (1 - self.bloch[0]) / 2
|
|
150
|
-
elif basis == Pauli.PauliY:
|
|
151
|
-
prob_1 = (1 - self.bloch[1]) / 2
|
|
152
|
-
else:
|
|
153
|
-
raise ValueError(f"Unsupported basis: {basis}")
|
|
154
|
-
return prob_1
|
|
155
|
-
|
|
156
|
-
def m(self):
|
|
157
|
-
result = random.random() < self.prob()
|
|
158
|
-
self.reset()
|
|
159
|
-
if result:
|
|
160
|
-
self.x()
|
|
161
|
-
return result
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
# Provided by Elara (the custom OpenAI GPT)
|
|
165
|
-
def _cpauli_lhv(prob, targ, axis, anti, theta=math.pi):
|
|
166
|
-
"""
|
|
167
|
-
Apply a 'soft' controlled-Pauli gate: rotate target qubit
|
|
168
|
-
proportionally to control's Z expectation value.
|
|
169
|
-
|
|
170
|
-
theta: full rotation angle if control in |1⟩
|
|
171
|
-
"""
|
|
172
|
-
# Control influence is (1 - ctrl.bloch[2]) / 2 = P(|1⟩)
|
|
173
|
-
# BUT we avoid collapse by using the expectation value:
|
|
174
|
-
control_influence = (1 - prob) if anti else prob
|
|
175
|
-
|
|
176
|
-
effective_theta = control_influence * theta
|
|
177
|
-
|
|
178
|
-
# Apply partial rotation to target qubit:
|
|
179
|
-
if axis == Pauli.PauliX:
|
|
180
|
-
targ.rx(effective_theta)
|
|
181
|
-
elif axis == Pauli.PauliY:
|
|
182
|
-
targ.ry(effective_theta)
|
|
183
|
-
elif axis == Pauli.PauliZ:
|
|
184
|
-
targ.rz(effective_theta)
|
|
185
|
-
|
|
186
|
-
|
|
187
30
|
class QrackAceBackend:
|
|
188
31
|
"""A back end for elided quantum error correction
|
|
189
32
|
|
|
@@ -202,6 +45,7 @@ class QrackAceBackend:
|
|
|
202
45
|
sim(QrackSimulator): Array of simulators corresponding to "patches" between boundary rows.
|
|
203
46
|
long_range_columns(int): How many ideal rows between QEC boundary rows?
|
|
204
47
|
is_transpose(bool): Rows are long if False, columns are long if True
|
|
48
|
+
correction_bias(float): Bias magnitude and direction during pseudo-QEC
|
|
205
49
|
"""
|
|
206
50
|
|
|
207
51
|
def __init__(
|
|
@@ -210,6 +54,7 @@ class QrackAceBackend:
|
|
|
210
54
|
long_range_columns=4,
|
|
211
55
|
long_range_rows=4,
|
|
212
56
|
is_transpose=False,
|
|
57
|
+
correction_bias=0,
|
|
213
58
|
isTensorNetwork=False,
|
|
214
59
|
isSchmidtDecomposeMulti=False,
|
|
215
60
|
isSchmidtDecompose=True,
|
|
@@ -238,6 +83,7 @@ class QrackAceBackend:
|
|
|
238
83
|
self.long_range_columns = long_range_columns
|
|
239
84
|
self.long_range_rows = long_range_rows
|
|
240
85
|
self.is_transpose = is_transpose
|
|
86
|
+
self.correction_bias = correction_bias
|
|
241
87
|
|
|
242
88
|
fppow = 5
|
|
243
89
|
if "QRACK_FPPOW" in os.environ:
|
|
@@ -273,10 +119,9 @@ class QrackAceBackend:
|
|
|
273
119
|
self._is_row_long_range[-1] = False
|
|
274
120
|
sim_count = col_patch_count * row_patch_count
|
|
275
121
|
|
|
276
|
-
self.
|
|
122
|
+
self._qubits = []
|
|
277
123
|
sim_counts = [0] * sim_count
|
|
278
124
|
sim_id = 0
|
|
279
|
-
tot_qubits = 0
|
|
280
125
|
for r in self._is_row_long_range:
|
|
281
126
|
for c in self._is_col_long_range:
|
|
282
127
|
qubit = [(sim_id, sim_counts[sim_id])]
|
|
@@ -287,14 +132,6 @@ class QrackAceBackend:
|
|
|
287
132
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
288
133
|
sim_counts[t_sim_id] += 1
|
|
289
134
|
|
|
290
|
-
qubit.append(
|
|
291
|
-
LHVQubit(
|
|
292
|
-
toClone=(
|
|
293
|
-
toClone._qubit_dict[tot_qubits][2] if toClone else None
|
|
294
|
-
)
|
|
295
|
-
)
|
|
296
|
-
)
|
|
297
|
-
|
|
298
135
|
if (not c) and (not r):
|
|
299
136
|
t_sim_id = (sim_id + col_patch_count) % sim_count
|
|
300
137
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
@@ -307,8 +144,7 @@ class QrackAceBackend:
|
|
|
307
144
|
if not c:
|
|
308
145
|
sim_id = (sim_id + 1) % sim_count
|
|
309
146
|
|
|
310
|
-
self.
|
|
311
|
-
tot_qubits += 1
|
|
147
|
+
self._qubits.append(qubit)
|
|
312
148
|
|
|
313
149
|
self.sim = []
|
|
314
150
|
for i in range(sim_count):
|
|
@@ -424,36 +260,18 @@ class QrackAceBackend:
|
|
|
424
260
|
self._qec_x(c)
|
|
425
261
|
|
|
426
262
|
def _unpack(self, lq):
|
|
427
|
-
return self.
|
|
263
|
+
return self._qubits[lq]
|
|
428
264
|
|
|
429
|
-
def
|
|
265
|
+
def _get_qb_indices(self, hq):
|
|
430
266
|
qb = []
|
|
431
267
|
if len(hq) < 2:
|
|
432
268
|
qb = [0]
|
|
433
|
-
lhv = -1
|
|
434
269
|
elif len(hq) < 4:
|
|
435
270
|
qb = [0, 1]
|
|
436
|
-
lhv = 2
|
|
437
271
|
else:
|
|
438
|
-
qb = [0, 1,
|
|
439
|
-
lhv = 2
|
|
440
|
-
|
|
441
|
-
return qb, lhv
|
|
272
|
+
qb = [0, 1, 2, 3]
|
|
442
273
|
|
|
443
|
-
|
|
444
|
-
# Z axis
|
|
445
|
-
z = 1 - 2 * sim.prob(Pauli.PauliZ)
|
|
446
|
-
|
|
447
|
-
# X axis
|
|
448
|
-
x = 1 - 2 * sim.prob(Pauli.PauliX)
|
|
449
|
-
|
|
450
|
-
# Y axis
|
|
451
|
-
y = 1 - 2 * sim.prob(Pauli.PauliY)
|
|
452
|
-
|
|
453
|
-
inclination = math.atan2(math.sqrt(x**2 + y**2), z)
|
|
454
|
-
azimuth = math.atan2(y, x)
|
|
455
|
-
|
|
456
|
-
return azimuth, inclination
|
|
274
|
+
return qb
|
|
457
275
|
|
|
458
276
|
def _get_bloch_angles(self, hq):
|
|
459
277
|
sim = self.sim[hq[0]].clone()
|
|
@@ -480,9 +298,7 @@ class QrackAceBackend:
|
|
|
480
298
|
|
|
481
299
|
return azimuth, inclination
|
|
482
300
|
|
|
483
|
-
def _rotate_to_bloch(
|
|
484
|
-
self, hq, delta_azimuth, delta_inclination
|
|
485
|
-
):
|
|
301
|
+
def _rotate_to_bloch(self, hq, delta_azimuth, delta_inclination):
|
|
486
302
|
sim = self.sim[hq[0]]
|
|
487
303
|
q = hq[1]
|
|
488
304
|
|
|
@@ -499,142 +315,112 @@ class QrackAceBackend:
|
|
|
499
315
|
|
|
500
316
|
sim.mtrx([m00, m01, m10, m11], q)
|
|
501
317
|
|
|
502
|
-
|
|
503
|
-
def _rotate_lhv_to_bloch(
|
|
504
|
-
self, sim, delta_azimuth, delta_inclination
|
|
505
|
-
):
|
|
506
|
-
# Apply rotation as "Azimuth, Inclination" (AI)
|
|
507
|
-
cosA = math.cos(delta_azimuth)
|
|
508
|
-
sinA = math.sin(delta_azimuth)
|
|
509
|
-
cosI = math.cos(delta_inclination / 2)
|
|
510
|
-
sinI = math.sin(delta_inclination / 2)
|
|
511
|
-
|
|
512
|
-
m00 = complex(cosI, 0)
|
|
513
|
-
m01 = complex(-cosA, sinA) * sinI
|
|
514
|
-
m10 = complex(cosA, sinA) * sinI
|
|
515
|
-
m11 = complex(cosI, 0)
|
|
516
|
-
|
|
517
|
-
sim.mtrx([m00, m01, m10, m11])
|
|
518
|
-
|
|
519
|
-
|
|
520
318
|
def _correct(self, lq, phase=False, skip_rotation=False):
|
|
521
319
|
hq = self._unpack(lq)
|
|
522
320
|
|
|
523
321
|
if len(hq) == 1:
|
|
524
322
|
return
|
|
525
323
|
|
|
526
|
-
qb
|
|
324
|
+
qb = self._get_qb_indices(hq)
|
|
527
325
|
|
|
528
326
|
if phase:
|
|
529
327
|
for q in qb:
|
|
530
328
|
b = hq[q]
|
|
531
329
|
self.sim[b[0]].h(b[1])
|
|
532
|
-
b = hq[lhv]
|
|
533
|
-
b.h()
|
|
534
330
|
|
|
535
331
|
if len(hq) == 5:
|
|
536
332
|
# RMS
|
|
537
333
|
p = [
|
|
538
334
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
539
335
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
540
|
-
hq[2].prob(),
|
|
336
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
541
337
|
self.sim[hq[3][0]].prob(hq[3][1]),
|
|
542
|
-
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
543
338
|
]
|
|
544
339
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
545
|
-
prms = math.sqrt(
|
|
546
|
-
(p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
|
|
547
|
-
)
|
|
340
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
|
|
548
341
|
qrms = math.sqrt(
|
|
549
|
-
(
|
|
550
|
-
|
|
551
|
-
+ (1 - p[1]) ** 2
|
|
552
|
-
+ 3 * ((1 - p[2]) ** 2)
|
|
553
|
-
+ (1 - p[3]) ** 2
|
|
554
|
-
+ (1 - p[4]) ** 2
|
|
555
|
-
)
|
|
556
|
-
/ 7
|
|
342
|
+
((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
|
|
343
|
+
/ 4
|
|
557
344
|
)
|
|
558
345
|
result = ((prms + (1 - qrms)) / 2) >= 0.5
|
|
559
346
|
syndrome = (
|
|
560
|
-
[1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3]
|
|
347
|
+
[1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3]]
|
|
561
348
|
if result
|
|
562
|
-
else [p[0], p[1], p[2], p[3]
|
|
349
|
+
else [p[0], p[1], p[2], p[3]]
|
|
563
350
|
)
|
|
564
|
-
for q in range(
|
|
351
|
+
for q in range(4):
|
|
565
352
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
566
|
-
|
|
567
|
-
hq[q].x()
|
|
568
|
-
else:
|
|
569
|
-
self.sim[hq[q][0]].x(hq[q][1])
|
|
353
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
570
354
|
|
|
571
355
|
if not skip_rotation:
|
|
572
|
-
a, i = [0, 0, 0, 0
|
|
356
|
+
a, i = [0, 0, 0, 0], [0, 0, 0, 0]
|
|
573
357
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
574
358
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
575
|
-
a[2], i[2] = self.
|
|
576
|
-
a[3], i[3] = self._get_bloch_angles(hq[
|
|
577
|
-
a[4], i[4] = self._get_bloch_angles(hq[4])
|
|
359
|
+
a[2], i[2] = self._get_bloch_angles(hq[3])
|
|
360
|
+
a[3], i[3] = self._get_bloch_angles(hq[4])
|
|
578
361
|
|
|
579
362
|
a_target = 0
|
|
580
363
|
i_target = 0
|
|
581
|
-
for x in range(
|
|
364
|
+
for x in range(4):
|
|
582
365
|
a_target += a[x]
|
|
583
366
|
i_target += i[x]
|
|
584
367
|
|
|
585
|
-
a_target /=
|
|
586
|
-
i_target /=
|
|
587
|
-
for x in range(
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
368
|
+
a_target /= 4
|
|
369
|
+
i_target /= 4
|
|
370
|
+
for x in range(4):
|
|
371
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
372
|
+
|
|
373
|
+
self.apply_magnetic_bias([lq], self.correction_bias)
|
|
592
374
|
|
|
593
375
|
else:
|
|
594
376
|
# RMS
|
|
595
377
|
p = [
|
|
596
378
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
597
379
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
598
|
-
hq[2].prob(),
|
|
599
380
|
]
|
|
600
381
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
601
|
-
prms = math.sqrt((p[0] ** 2 + p[1] ** 2
|
|
602
|
-
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2
|
|
382
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
|
|
383
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
|
|
603
384
|
result = ((prms + (1 - qrms)) / 2) >= 0.5
|
|
604
|
-
syndrome = [1 - p[0], 1 - p[1]
|
|
605
|
-
for q in range(
|
|
385
|
+
syndrome = [1 - p[0], 1 - p[1]] if result else [p[0], p[1]]
|
|
386
|
+
for q in range(2):
|
|
606
387
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
607
|
-
|
|
608
|
-
hq[q].x()
|
|
609
|
-
else:
|
|
610
|
-
self.sim[hq[q][0]].x(hq[q][1])
|
|
388
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
611
389
|
|
|
612
390
|
if not skip_rotation:
|
|
613
|
-
a, i = [0, 0
|
|
391
|
+
a, i = [0, 0], [0, 0]
|
|
614
392
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
615
393
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
616
|
-
a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
|
|
617
394
|
|
|
618
395
|
a_target = 0
|
|
619
396
|
i_target = 0
|
|
620
|
-
for x in range(
|
|
397
|
+
for x in range(2):
|
|
621
398
|
a_target += a[x]
|
|
622
399
|
i_target += i[x]
|
|
623
400
|
|
|
624
|
-
a_target /=
|
|
625
|
-
i_target /=
|
|
626
|
-
for x in range(
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
401
|
+
a_target /= 2
|
|
402
|
+
i_target /= 2
|
|
403
|
+
for x in range(2):
|
|
404
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
405
|
+
|
|
406
|
+
self.apply_magnetic_bias([lq], self.correction_bias)
|
|
631
407
|
|
|
632
408
|
if phase:
|
|
633
409
|
for q in qb:
|
|
634
410
|
b = hq[q]
|
|
635
411
|
self.sim[b[0]].h(b[1])
|
|
636
|
-
|
|
637
|
-
|
|
412
|
+
|
|
413
|
+
def apply_magnetic_bias(self, q, b):
|
|
414
|
+
if b == 0:
|
|
415
|
+
return
|
|
416
|
+
b = math.exp(b)
|
|
417
|
+
for x in q:
|
|
418
|
+
hq = self._unpack(x)
|
|
419
|
+
for h in hq:
|
|
420
|
+
a, i = self._get_bloch_angles(h)
|
|
421
|
+
self._rotate_to_bloch(
|
|
422
|
+
h, math.atan(math.tan(a) * b) - a, math.atan(math.tan(i) * b) - i
|
|
423
|
+
)
|
|
638
424
|
|
|
639
425
|
def u(self, lq, th, ph, lm):
|
|
640
426
|
hq = self._unpack(lq)
|
|
@@ -643,15 +429,12 @@ class QrackAceBackend:
|
|
|
643
429
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
644
430
|
return
|
|
645
431
|
|
|
646
|
-
qb
|
|
432
|
+
qb = self._get_qb_indices(hq)
|
|
647
433
|
|
|
648
434
|
for q in qb:
|
|
649
435
|
b = hq[q]
|
|
650
436
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
651
437
|
|
|
652
|
-
b = hq[lhv]
|
|
653
|
-
b.u(th, ph, lm)
|
|
654
|
-
|
|
655
438
|
self._correct(lq, False, True)
|
|
656
439
|
self._correct(lq, True, False)
|
|
657
440
|
|
|
@@ -662,20 +445,12 @@ class QrackAceBackend:
|
|
|
662
445
|
self.sim[b[0]].r(p, th, b[1])
|
|
663
446
|
return
|
|
664
447
|
|
|
665
|
-
qb
|
|
448
|
+
qb = self._get_qb_indices(hq)
|
|
666
449
|
|
|
667
450
|
for q in qb:
|
|
668
451
|
b = hq[q]
|
|
669
452
|
self.sim[b[0]].r(p, th, b[1])
|
|
670
453
|
|
|
671
|
-
b = hq[lhv]
|
|
672
|
-
if p == Pauli.PauliX:
|
|
673
|
-
b.rx(th)
|
|
674
|
-
elif p == Pauli.PauliY:
|
|
675
|
-
b.ry(th)
|
|
676
|
-
elif p == Pauli.PauliZ:
|
|
677
|
-
b.rz(th)
|
|
678
|
-
|
|
679
454
|
if p != Pauli.PauliZ:
|
|
680
455
|
self._correct(lq, False, p != Pauli.PauliX)
|
|
681
456
|
if p != Pauli.PauliX:
|
|
@@ -690,15 +465,12 @@ class QrackAceBackend:
|
|
|
690
465
|
|
|
691
466
|
self._correct(lq)
|
|
692
467
|
|
|
693
|
-
qb
|
|
468
|
+
qb = self._get_qb_indices(hq)
|
|
694
469
|
|
|
695
470
|
for q in qb:
|
|
696
471
|
b = hq[q]
|
|
697
472
|
self.sim[b[0]].h(b[1])
|
|
698
473
|
|
|
699
|
-
b = hq[lhv]
|
|
700
|
-
b.h()
|
|
701
|
-
|
|
702
474
|
self._correct(lq)
|
|
703
475
|
|
|
704
476
|
def s(self, lq):
|
|
@@ -708,15 +480,12 @@ class QrackAceBackend:
|
|
|
708
480
|
self.sim[b[0]].s(b[1])
|
|
709
481
|
return
|
|
710
482
|
|
|
711
|
-
qb
|
|
483
|
+
qb = self._get_qb_indices(hq)
|
|
712
484
|
|
|
713
485
|
for q in qb:
|
|
714
486
|
b = hq[q]
|
|
715
487
|
self.sim[b[0]].s(b[1])
|
|
716
488
|
|
|
717
|
-
b = hq[lhv]
|
|
718
|
-
b.s()
|
|
719
|
-
|
|
720
489
|
def adjs(self, lq):
|
|
721
490
|
hq = self._unpack(lq)
|
|
722
491
|
if len(hq) < 2:
|
|
@@ -724,15 +493,12 @@ class QrackAceBackend:
|
|
|
724
493
|
self.sim[b[0]].adjs(b[1])
|
|
725
494
|
return
|
|
726
495
|
|
|
727
|
-
qb
|
|
496
|
+
qb = self._get_qb_indices(hq)
|
|
728
497
|
|
|
729
498
|
for q in qb:
|
|
730
499
|
b = hq[q]
|
|
731
500
|
self.sim[b[0]].adjs(b[1])
|
|
732
501
|
|
|
733
|
-
b = hq[lhv]
|
|
734
|
-
b.adjs()
|
|
735
|
-
|
|
736
502
|
def x(self, lq):
|
|
737
503
|
hq = self._unpack(lq)
|
|
738
504
|
if len(hq) < 2:
|
|
@@ -740,15 +506,12 @@ class QrackAceBackend:
|
|
|
740
506
|
self.sim[b[0]].x(b[1])
|
|
741
507
|
return
|
|
742
508
|
|
|
743
|
-
qb
|
|
509
|
+
qb = self._get_qb_indices(hq)
|
|
744
510
|
|
|
745
511
|
for q in qb:
|
|
746
512
|
b = hq[q]
|
|
747
513
|
self.sim[b[0]].x(b[1])
|
|
748
514
|
|
|
749
|
-
b = hq[lhv]
|
|
750
|
-
b.x()
|
|
751
|
-
|
|
752
515
|
def y(self, lq):
|
|
753
516
|
hq = self._unpack(lq)
|
|
754
517
|
if len(hq) < 2:
|
|
@@ -756,15 +519,12 @@ class QrackAceBackend:
|
|
|
756
519
|
self.sim[b[0]].y(b[1])
|
|
757
520
|
return
|
|
758
521
|
|
|
759
|
-
qb
|
|
522
|
+
qb = self._get_qb_indices(hq)
|
|
760
523
|
|
|
761
524
|
for q in qb:
|
|
762
525
|
b = hq[q]
|
|
763
526
|
self.sim[b[0]].y(b[1])
|
|
764
527
|
|
|
765
|
-
b = hq[lhv]
|
|
766
|
-
b.y()
|
|
767
|
-
|
|
768
528
|
def z(self, lq):
|
|
769
529
|
hq = self._unpack(lq)
|
|
770
530
|
if len(hq) < 2:
|
|
@@ -772,15 +532,12 @@ class QrackAceBackend:
|
|
|
772
532
|
self.sim[b[0]].z(b[1])
|
|
773
533
|
return
|
|
774
534
|
|
|
775
|
-
qb
|
|
535
|
+
qb = self._get_qb_indices(hq)
|
|
776
536
|
|
|
777
537
|
for q in qb:
|
|
778
538
|
b = hq[q]
|
|
779
539
|
self.sim[b[0]].z(b[1])
|
|
780
540
|
|
|
781
|
-
b = hq[lhv]
|
|
782
|
-
b.z()
|
|
783
|
-
|
|
784
541
|
def t(self, lq):
|
|
785
542
|
hq = self._unpack(lq)
|
|
786
543
|
if len(hq) < 2:
|
|
@@ -788,15 +545,12 @@ class QrackAceBackend:
|
|
|
788
545
|
self.sim[b[0]].t(b[1])
|
|
789
546
|
return
|
|
790
547
|
|
|
791
|
-
qb
|
|
548
|
+
qb = self._get_qb_indices(hq)
|
|
792
549
|
|
|
793
550
|
for q in qb:
|
|
794
551
|
b = hq[q]
|
|
795
552
|
self.sim[b[0]].t(b[1])
|
|
796
553
|
|
|
797
|
-
b = hq[lhv]
|
|
798
|
-
b.t()
|
|
799
|
-
|
|
800
554
|
def adjt(self, lq):
|
|
801
555
|
hq = self._unpack(lq)
|
|
802
556
|
if len(hq) < 2:
|
|
@@ -804,15 +558,12 @@ class QrackAceBackend:
|
|
|
804
558
|
self.sim[b[0]].adjt(b[1])
|
|
805
559
|
return
|
|
806
560
|
|
|
807
|
-
qb
|
|
561
|
+
qb = self._get_qb_indices(hq)
|
|
808
562
|
|
|
809
563
|
for q in qb:
|
|
810
564
|
b = hq[q]
|
|
811
565
|
self.sim[b[0]].adjt(b[1])
|
|
812
566
|
|
|
813
|
-
b = hq[lhv]
|
|
814
|
-
b.adjt()
|
|
815
|
-
|
|
816
567
|
def _get_gate(self, pauli, anti, sim_id):
|
|
817
568
|
gate = None
|
|
818
569
|
shadow = None
|
|
@@ -853,15 +604,11 @@ class QrackAceBackend:
|
|
|
853
604
|
|
|
854
605
|
return connected, boundary
|
|
855
606
|
|
|
856
|
-
def _apply_coupling(self, pauli, anti, qb1,
|
|
607
|
+
def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr):
|
|
857
608
|
for q1 in qb1:
|
|
858
|
-
if q1 == lhv1:
|
|
859
|
-
continue
|
|
860
609
|
b1 = hq1[q1]
|
|
861
610
|
gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
|
|
862
611
|
for q2 in qb2:
|
|
863
|
-
if q2 == lhv2:
|
|
864
|
-
continue
|
|
865
612
|
b2 = hq2[q2]
|
|
866
613
|
if b1[0] == b2[0]:
|
|
867
614
|
gate_fn([b1[1]], b2[1])
|
|
@@ -886,18 +633,10 @@ class QrackAceBackend:
|
|
|
886
633
|
|
|
887
634
|
self._correct(lq1)
|
|
888
635
|
|
|
889
|
-
qb1
|
|
890
|
-
qb2
|
|
636
|
+
qb1 = self._get_qb_indices(hq1)
|
|
637
|
+
qb2 = self._get_qb_indices(hq2)
|
|
891
638
|
# Apply cross coupling on hardware qubits first
|
|
892
|
-
self._apply_coupling(pauli, anti, qb1,
|
|
893
|
-
# Apply coupling to the local-hidden-variable target
|
|
894
|
-
if lhv2 >= 0:
|
|
895
|
-
_cpauli_lhv(
|
|
896
|
-
hq1[lhv1].prob() if lhv1 >= 0 else self.sim[hq1[0][0]].prob(hq1[0][1]),
|
|
897
|
-
hq2[lhv2],
|
|
898
|
-
pauli,
|
|
899
|
-
anti,
|
|
900
|
-
)
|
|
639
|
+
self._apply_coupling(pauli, anti, qb1, hq1, qb2, hq2, lq1_lr)
|
|
901
640
|
|
|
902
641
|
self._correct(lq1, True)
|
|
903
642
|
if pauli != Pauli.PauliZ:
|
|
@@ -999,29 +738,20 @@ class QrackAceBackend:
|
|
|
999
738
|
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
1000
739
|
]
|
|
1001
740
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
1002
|
-
prms = math.sqrt(
|
|
1003
|
-
(p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
|
|
1004
|
-
)
|
|
741
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
|
|
1005
742
|
qrms = math.sqrt(
|
|
1006
|
-
(
|
|
1007
|
-
|
|
1008
|
-
+ (1 - p[1]) ** 2
|
|
1009
|
-
+ 3 * ((1 - p[2]) ** 2)
|
|
1010
|
-
+ (1 - p[3]) ** 2
|
|
1011
|
-
+ (1 - p[4]) ** 2
|
|
1012
|
-
)
|
|
1013
|
-
/ 7
|
|
743
|
+
((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
|
|
744
|
+
/ 4
|
|
1014
745
|
)
|
|
1015
746
|
else:
|
|
1016
747
|
# RMS
|
|
1017
748
|
p = [
|
|
1018
749
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
1019
750
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
1020
|
-
hq[2].prob(),
|
|
1021
751
|
]
|
|
1022
752
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
1023
|
-
prms = math.sqrt((p[0] ** 2 + p[1] ** 2
|
|
1024
|
-
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2
|
|
753
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
|
|
754
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
|
|
1025
755
|
|
|
1026
756
|
return (prms + (1 - qrms)) / 2
|
|
1027
757
|
|
|
@@ -1034,7 +764,7 @@ class QrackAceBackend:
|
|
|
1034
764
|
p = self.prob(lq)
|
|
1035
765
|
result = ((p + self._epsilon) >= 1) or (random.random() < p)
|
|
1036
766
|
|
|
1037
|
-
qb
|
|
767
|
+
qb = self._get_qb_indices(hq)
|
|
1038
768
|
|
|
1039
769
|
for q in qb:
|
|
1040
770
|
b = hq[q]
|
|
@@ -1045,11 +775,6 @@ class QrackAceBackend:
|
|
|
1045
775
|
else:
|
|
1046
776
|
self.sim[b[0]].force_m(b[1], result)
|
|
1047
777
|
|
|
1048
|
-
b = hq[lhv]
|
|
1049
|
-
b.reset()
|
|
1050
|
-
if result:
|
|
1051
|
-
b.x()
|
|
1052
|
-
|
|
1053
778
|
return result
|
|
1054
779
|
|
|
1055
780
|
def force_m(self, lq, result):
|
|
@@ -1060,7 +785,7 @@ class QrackAceBackend:
|
|
|
1060
785
|
|
|
1061
786
|
self._correct(lq)
|
|
1062
787
|
|
|
1063
|
-
qb
|
|
788
|
+
qb = self._get_qb_indices(hq)
|
|
1064
789
|
|
|
1065
790
|
for q in qb:
|
|
1066
791
|
b = hq[q]
|
|
@@ -1071,11 +796,6 @@ class QrackAceBackend:
|
|
|
1071
796
|
else:
|
|
1072
797
|
self.sim[b[0]].force_m(b[1], result)
|
|
1073
798
|
|
|
1074
|
-
b = hq[1]
|
|
1075
|
-
b.reset()
|
|
1076
|
-
if result:
|
|
1077
|
-
b.x()
|
|
1078
|
-
|
|
1079
799
|
return c
|
|
1080
800
|
|
|
1081
801
|
def m_all(self):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
pyqrack/__init__.py,sha256=3tBwfCCD-zQjQ2g1EUZdggKdn-3b2uSFTbT7LS0YLaU,785
|
|
2
2
|
pyqrack/neuron_activation_fn.py,sha256=fQTTFfsvwcot_43Vopacot47IV2Rxk8pelUyuzwpXPs,593
|
|
3
3
|
pyqrack/pauli.py,sha256=wg500wDOwdIU4lEVJoMmjtbAdmtakZYzLPjdzC2rwUQ,654
|
|
4
|
-
pyqrack/qrack_ace_backend.py,sha256=
|
|
4
|
+
pyqrack/qrack_ace_backend.py,sha256=SLmRwJmUAzV0BWoZJFskMYl21Kg9VXjQnoaAb4g6eDk,40334
|
|
5
5
|
pyqrack/qrack_circuit.py,sha256=vDCKGbcEHJDFUKprjCpWgit8lXFnMrPimKHURD2_Hj4,19538
|
|
6
6
|
pyqrack/qrack_neuron.py,sha256=UiJdjAGB6usjAGHWSosSFCUUeIkhh3MtZbsaxfsIsNw,9043
|
|
7
7
|
pyqrack/qrack_neuron_torch_layer.py,sha256=Bs5BLC2GFevfSpo_jSJ2AZl-hfDRJmzlGN9pFw1CtoQ,6160
|
|
@@ -16,8 +16,8 @@ pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.so.9.22.0,sha256=uFHqafF8aaXe5tH
|
|
|
16
16
|
pyqrack/stats/__init__.py,sha256=Hla85my2fY_roR9lIjGBVpEG7ySOTMwjWa8D6-kgCnY,276
|
|
17
17
|
pyqrack/stats/load_quantized_data.py,sha256=z12u9F7Nt3P-i44nY1xxvso_klS6WIHS3iqq7R2_lqE,1184
|
|
18
18
|
pyqrack/stats/quantize_by_range.py,sha256=UM0_7jJDdQ7g30cR3UQAxkbzkqrmsy1oUfqg0h11FUY,2270
|
|
19
|
-
pyqrack_cpu-1.
|
|
20
|
-
pyqrack_cpu-1.
|
|
21
|
-
pyqrack_cpu-1.
|
|
22
|
-
pyqrack_cpu-1.
|
|
23
|
-
pyqrack_cpu-1.
|
|
19
|
+
pyqrack_cpu-1.62.0.dist-info/LICENSE,sha256=HxB-7SaWTuewAk1nz-3_3FUD6QhgX73kNT_taKVUTq8,1069
|
|
20
|
+
pyqrack_cpu-1.62.0.dist-info/METADATA,sha256=szlF9V6pWiHUSKtCECt9oJqDxDqS2_rZjjL9Z_ahX_U,5971
|
|
21
|
+
pyqrack_cpu-1.62.0.dist-info/WHEEL,sha256=AMMNaGlKLEICDqgnxZojk7k8N6wUjQQ3X9tPjxJ2sOc,110
|
|
22
|
+
pyqrack_cpu-1.62.0.dist-info/top_level.txt,sha256=YE_3q9JTGRLMilNg2tGP1y7uU-Dx8PDao2OhwoIbv8E,8
|
|
23
|
+
pyqrack_cpu-1.62.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|