pyqrack-cpu 1.61.2__py3-none-manylinux_2_39_x86_64.whl → 1.61.3__py3-none-manylinux_2_39_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 +51 -348
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.61.3.dist-info}/METADATA +1 -1
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.61.3.dist-info}/RECORD +6 -6
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.61.3.dist-info}/WHEEL +0 -0
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.61.3.dist-info}/licenses/LICENSE +0 -0
- {pyqrack_cpu-1.61.2.dist-info → pyqrack_cpu-1.61.3.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
|
|
|
@@ -287,14 +130,6 @@ class QrackAceBackend:
|
|
|
287
130
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
288
131
|
sim_counts[t_sim_id] += 1
|
|
289
132
|
|
|
290
|
-
qubit.append(
|
|
291
|
-
LHVQubit(
|
|
292
|
-
toClone=(
|
|
293
|
-
toClone._qubit_dict[tot_qubits][2] if toClone else None
|
|
294
|
-
)
|
|
295
|
-
)
|
|
296
|
-
)
|
|
297
|
-
|
|
298
133
|
if (not c) and (not r):
|
|
299
134
|
t_sim_id = (sim_id + col_patch_count) % sim_count
|
|
300
135
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
@@ -426,34 +261,16 @@ class QrackAceBackend:
|
|
|
426
261
|
def _unpack(self, lq):
|
|
427
262
|
return self._qubit_dict[lq]
|
|
428
263
|
|
|
429
|
-
def
|
|
264
|
+
def _get_qb_indices(self, hq):
|
|
430
265
|
qb = []
|
|
431
266
|
if len(hq) < 2:
|
|
432
267
|
qb = [0]
|
|
433
|
-
lhv = -1
|
|
434
268
|
elif len(hq) < 4:
|
|
435
269
|
qb = [0, 1]
|
|
436
|
-
lhv = 2
|
|
437
270
|
else:
|
|
438
|
-
qb = [0, 1,
|
|
439
|
-
lhv = 2
|
|
440
|
-
|
|
441
|
-
return qb, lhv
|
|
442
|
-
|
|
443
|
-
def _get_lhv_bloch_angles(self, sim):
|
|
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)
|
|
271
|
+
qb = [0, 1, 2, 3]
|
|
452
272
|
|
|
453
|
-
|
|
454
|
-
azimuth = math.atan2(y, x)
|
|
455
|
-
|
|
456
|
-
return azimuth, inclination
|
|
273
|
+
return qb
|
|
457
274
|
|
|
458
275
|
def _get_bloch_angles(self, hq):
|
|
459
276
|
sim = self.sim[hq[0]].clone()
|
|
@@ -480,9 +297,7 @@ class QrackAceBackend:
|
|
|
480
297
|
|
|
481
298
|
return azimuth, inclination
|
|
482
299
|
|
|
483
|
-
def _rotate_to_bloch(
|
|
484
|
-
self, hq, delta_azimuth, delta_inclination
|
|
485
|
-
):
|
|
300
|
+
def _rotate_to_bloch(self, hq, delta_azimuth, delta_inclination):
|
|
486
301
|
sim = self.sim[hq[0]]
|
|
487
302
|
q = hq[1]
|
|
488
303
|
|
|
@@ -499,142 +314,96 @@ class QrackAceBackend:
|
|
|
499
314
|
|
|
500
315
|
sim.mtrx([m00, m01, m10, m11], q)
|
|
501
316
|
|
|
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
317
|
def _correct(self, lq, phase=False, skip_rotation=False):
|
|
521
318
|
hq = self._unpack(lq)
|
|
522
319
|
|
|
523
320
|
if len(hq) == 1:
|
|
524
321
|
return
|
|
525
322
|
|
|
526
|
-
qb
|
|
323
|
+
qb = self._get_qb_indices(hq)
|
|
527
324
|
|
|
528
325
|
if phase:
|
|
529
326
|
for q in qb:
|
|
530
327
|
b = hq[q]
|
|
531
328
|
self.sim[b[0]].h(b[1])
|
|
532
|
-
b = hq[lhv]
|
|
533
|
-
b.h()
|
|
534
329
|
|
|
535
330
|
if len(hq) == 5:
|
|
536
331
|
# RMS
|
|
537
332
|
p = [
|
|
538
333
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
539
334
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
540
|
-
hq[2].prob(),
|
|
335
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
541
336
|
self.sim[hq[3][0]].prob(hq[3][1]),
|
|
542
|
-
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
543
337
|
]
|
|
544
338
|
# 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
|
-
)
|
|
339
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
|
|
548
340
|
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
|
|
341
|
+
((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
|
|
342
|
+
/ 4
|
|
557
343
|
)
|
|
558
344
|
result = ((prms + (1 - qrms)) / 2) >= 0.5
|
|
559
345
|
syndrome = (
|
|
560
|
-
[1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3]
|
|
346
|
+
[1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3]]
|
|
561
347
|
if result
|
|
562
|
-
else [p[0], p[1], p[2], p[3]
|
|
348
|
+
else [p[0], p[1], p[2], p[3]]
|
|
563
349
|
)
|
|
564
|
-
for q in range(
|
|
350
|
+
for q in range(4):
|
|
565
351
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
566
|
-
|
|
567
|
-
hq[q].x()
|
|
568
|
-
else:
|
|
569
|
-
self.sim[hq[q][0]].x(hq[q][1])
|
|
352
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
570
353
|
|
|
571
354
|
if not skip_rotation:
|
|
572
355
|
a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
|
|
573
356
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
574
357
|
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])
|
|
358
|
+
a[2], i[2] = self._get_bloch_angles(hq[3])
|
|
359
|
+
a[3], i[3] = self._get_bloch_angles(hq[4])
|
|
578
360
|
|
|
579
361
|
a_target = 0
|
|
580
362
|
i_target = 0
|
|
581
|
-
for x in range(
|
|
363
|
+
for x in range(4):
|
|
582
364
|
a_target += a[x]
|
|
583
365
|
i_target += i[x]
|
|
584
366
|
|
|
585
|
-
a_target /=
|
|
586
|
-
i_target /=
|
|
587
|
-
for x in range(
|
|
588
|
-
|
|
589
|
-
self._rotate_lhv_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
590
|
-
else:
|
|
591
|
-
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
367
|
+
a_target /= 4
|
|
368
|
+
i_target /= 4
|
|
369
|
+
for x in range(4):
|
|
370
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
592
371
|
|
|
593
372
|
else:
|
|
594
373
|
# RMS
|
|
595
374
|
p = [
|
|
596
375
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
597
376
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
598
|
-
hq[2].prob(),
|
|
599
377
|
]
|
|
600
378
|
# 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
|
|
379
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
|
|
380
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
|
|
603
381
|
result = ((prms + (1 - qrms)) / 2) >= 0.5
|
|
604
|
-
syndrome = [1 - p[0], 1 - p[1]
|
|
605
|
-
for q in range(
|
|
382
|
+
syndrome = [1 - p[0], 1 - p[1]] if result else [p[0], p[1]]
|
|
383
|
+
for q in range(2):
|
|
606
384
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
607
|
-
|
|
608
|
-
hq[q].x()
|
|
609
|
-
else:
|
|
610
|
-
self.sim[hq[q][0]].x(hq[q][1])
|
|
385
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
611
386
|
|
|
612
387
|
if not skip_rotation:
|
|
613
388
|
a, i = [0, 0, 0], [0, 0, 0]
|
|
614
389
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
615
390
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
616
|
-
a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
|
|
617
391
|
|
|
618
392
|
a_target = 0
|
|
619
393
|
i_target = 0
|
|
620
|
-
for x in range(
|
|
394
|
+
for x in range(2):
|
|
621
395
|
a_target += a[x]
|
|
622
396
|
i_target += i[x]
|
|
623
397
|
|
|
624
|
-
a_target /=
|
|
625
|
-
i_target /=
|
|
626
|
-
for x in range(
|
|
627
|
-
|
|
628
|
-
self._rotate_lhv_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
629
|
-
else:
|
|
630
|
-
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
398
|
+
a_target /= 2
|
|
399
|
+
i_target /= 2
|
|
400
|
+
for x in range(2):
|
|
401
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
631
402
|
|
|
632
403
|
if phase:
|
|
633
404
|
for q in qb:
|
|
634
405
|
b = hq[q]
|
|
635
406
|
self.sim[b[0]].h(b[1])
|
|
636
|
-
b = hq[lhv]
|
|
637
|
-
b.h()
|
|
638
407
|
|
|
639
408
|
def u(self, lq, th, ph, lm):
|
|
640
409
|
hq = self._unpack(lq)
|
|
@@ -643,15 +412,12 @@ class QrackAceBackend:
|
|
|
643
412
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
644
413
|
return
|
|
645
414
|
|
|
646
|
-
qb
|
|
415
|
+
qb = self._get_qb_indices(hq)
|
|
647
416
|
|
|
648
417
|
for q in qb:
|
|
649
418
|
b = hq[q]
|
|
650
419
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
651
420
|
|
|
652
|
-
b = hq[lhv]
|
|
653
|
-
b.u(th, ph, lm)
|
|
654
|
-
|
|
655
421
|
self._correct(lq, False, True)
|
|
656
422
|
self._correct(lq, True, False)
|
|
657
423
|
|
|
@@ -662,20 +428,12 @@ class QrackAceBackend:
|
|
|
662
428
|
self.sim[b[0]].r(p, th, b[1])
|
|
663
429
|
return
|
|
664
430
|
|
|
665
|
-
qb
|
|
431
|
+
qb = self._get_qb_indices(hq)
|
|
666
432
|
|
|
667
433
|
for q in qb:
|
|
668
434
|
b = hq[q]
|
|
669
435
|
self.sim[b[0]].r(p, th, b[1])
|
|
670
436
|
|
|
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
437
|
if p != Pauli.PauliZ:
|
|
680
438
|
self._correct(lq, False, p != Pauli.PauliX)
|
|
681
439
|
if p != Pauli.PauliX:
|
|
@@ -690,15 +448,12 @@ class QrackAceBackend:
|
|
|
690
448
|
|
|
691
449
|
self._correct(lq)
|
|
692
450
|
|
|
693
|
-
qb
|
|
451
|
+
qb = self._get_qb_indices(hq)
|
|
694
452
|
|
|
695
453
|
for q in qb:
|
|
696
454
|
b = hq[q]
|
|
697
455
|
self.sim[b[0]].h(b[1])
|
|
698
456
|
|
|
699
|
-
b = hq[lhv]
|
|
700
|
-
b.h()
|
|
701
|
-
|
|
702
457
|
self._correct(lq)
|
|
703
458
|
|
|
704
459
|
def s(self, lq):
|
|
@@ -708,15 +463,12 @@ class QrackAceBackend:
|
|
|
708
463
|
self.sim[b[0]].s(b[1])
|
|
709
464
|
return
|
|
710
465
|
|
|
711
|
-
qb
|
|
466
|
+
qb = self._get_qb_indices(hq)
|
|
712
467
|
|
|
713
468
|
for q in qb:
|
|
714
469
|
b = hq[q]
|
|
715
470
|
self.sim[b[0]].s(b[1])
|
|
716
471
|
|
|
717
|
-
b = hq[lhv]
|
|
718
|
-
b.s()
|
|
719
|
-
|
|
720
472
|
def adjs(self, lq):
|
|
721
473
|
hq = self._unpack(lq)
|
|
722
474
|
if len(hq) < 2:
|
|
@@ -724,15 +476,12 @@ class QrackAceBackend:
|
|
|
724
476
|
self.sim[b[0]].adjs(b[1])
|
|
725
477
|
return
|
|
726
478
|
|
|
727
|
-
qb
|
|
479
|
+
qb = self._get_qb_indices(hq)
|
|
728
480
|
|
|
729
481
|
for q in qb:
|
|
730
482
|
b = hq[q]
|
|
731
483
|
self.sim[b[0]].adjs(b[1])
|
|
732
484
|
|
|
733
|
-
b = hq[lhv]
|
|
734
|
-
b.adjs()
|
|
735
|
-
|
|
736
485
|
def x(self, lq):
|
|
737
486
|
hq = self._unpack(lq)
|
|
738
487
|
if len(hq) < 2:
|
|
@@ -740,15 +489,12 @@ class QrackAceBackend:
|
|
|
740
489
|
self.sim[b[0]].x(b[1])
|
|
741
490
|
return
|
|
742
491
|
|
|
743
|
-
qb
|
|
492
|
+
qb = self._get_qb_indices(hq)
|
|
744
493
|
|
|
745
494
|
for q in qb:
|
|
746
495
|
b = hq[q]
|
|
747
496
|
self.sim[b[0]].x(b[1])
|
|
748
497
|
|
|
749
|
-
b = hq[lhv]
|
|
750
|
-
b.x()
|
|
751
|
-
|
|
752
498
|
def y(self, lq):
|
|
753
499
|
hq = self._unpack(lq)
|
|
754
500
|
if len(hq) < 2:
|
|
@@ -756,15 +502,12 @@ class QrackAceBackend:
|
|
|
756
502
|
self.sim[b[0]].y(b[1])
|
|
757
503
|
return
|
|
758
504
|
|
|
759
|
-
qb
|
|
505
|
+
qb = self._get_qb_indices(hq)
|
|
760
506
|
|
|
761
507
|
for q in qb:
|
|
762
508
|
b = hq[q]
|
|
763
509
|
self.sim[b[0]].y(b[1])
|
|
764
510
|
|
|
765
|
-
b = hq[lhv]
|
|
766
|
-
b.y()
|
|
767
|
-
|
|
768
511
|
def z(self, lq):
|
|
769
512
|
hq = self._unpack(lq)
|
|
770
513
|
if len(hq) < 2:
|
|
@@ -772,15 +515,12 @@ class QrackAceBackend:
|
|
|
772
515
|
self.sim[b[0]].z(b[1])
|
|
773
516
|
return
|
|
774
517
|
|
|
775
|
-
qb
|
|
518
|
+
qb = self._get_qb_indices(hq)
|
|
776
519
|
|
|
777
520
|
for q in qb:
|
|
778
521
|
b = hq[q]
|
|
779
522
|
self.sim[b[0]].z(b[1])
|
|
780
523
|
|
|
781
|
-
b = hq[lhv]
|
|
782
|
-
b.z()
|
|
783
|
-
|
|
784
524
|
def t(self, lq):
|
|
785
525
|
hq = self._unpack(lq)
|
|
786
526
|
if len(hq) < 2:
|
|
@@ -788,15 +528,12 @@ class QrackAceBackend:
|
|
|
788
528
|
self.sim[b[0]].t(b[1])
|
|
789
529
|
return
|
|
790
530
|
|
|
791
|
-
qb
|
|
531
|
+
qb = self._get_qb_indices(hq)
|
|
792
532
|
|
|
793
533
|
for q in qb:
|
|
794
534
|
b = hq[q]
|
|
795
535
|
self.sim[b[0]].t(b[1])
|
|
796
536
|
|
|
797
|
-
b = hq[lhv]
|
|
798
|
-
b.t()
|
|
799
|
-
|
|
800
537
|
def adjt(self, lq):
|
|
801
538
|
hq = self._unpack(lq)
|
|
802
539
|
if len(hq) < 2:
|
|
@@ -804,15 +541,12 @@ class QrackAceBackend:
|
|
|
804
541
|
self.sim[b[0]].adjt(b[1])
|
|
805
542
|
return
|
|
806
543
|
|
|
807
|
-
qb
|
|
544
|
+
qb = self._get_qb_indices(hq)
|
|
808
545
|
|
|
809
546
|
for q in qb:
|
|
810
547
|
b = hq[q]
|
|
811
548
|
self.sim[b[0]].adjt(b[1])
|
|
812
549
|
|
|
813
|
-
b = hq[lhv]
|
|
814
|
-
b.adjt()
|
|
815
|
-
|
|
816
550
|
def _get_gate(self, pauli, anti, sim_id):
|
|
817
551
|
gate = None
|
|
818
552
|
shadow = None
|
|
@@ -853,15 +587,11 @@ class QrackAceBackend:
|
|
|
853
587
|
|
|
854
588
|
return connected, boundary
|
|
855
589
|
|
|
856
|
-
def _apply_coupling(self, pauli, anti, qb1,
|
|
590
|
+
def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr):
|
|
857
591
|
for q1 in qb1:
|
|
858
|
-
if q1 == lhv1:
|
|
859
|
-
continue
|
|
860
592
|
b1 = hq1[q1]
|
|
861
593
|
gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
|
|
862
594
|
for q2 in qb2:
|
|
863
|
-
if q2 == lhv2:
|
|
864
|
-
continue
|
|
865
595
|
b2 = hq2[q2]
|
|
866
596
|
if b1[0] == b2[0]:
|
|
867
597
|
gate_fn([b1[1]], b2[1])
|
|
@@ -886,18 +616,10 @@ class QrackAceBackend:
|
|
|
886
616
|
|
|
887
617
|
self._correct(lq1)
|
|
888
618
|
|
|
889
|
-
qb1
|
|
890
|
-
qb2
|
|
619
|
+
qb1 = self._get_qb_indices(hq1)
|
|
620
|
+
qb2 = self._get_qb_indices(hq2)
|
|
891
621
|
# 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
|
-
)
|
|
622
|
+
self._apply_coupling(pauli, anti, qb1, hq1, qb2, hq2, lq1_lr)
|
|
901
623
|
|
|
902
624
|
self._correct(lq1, True)
|
|
903
625
|
if pauli != Pauli.PauliZ:
|
|
@@ -999,29 +721,20 @@ class QrackAceBackend:
|
|
|
999
721
|
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
1000
722
|
]
|
|
1001
723
|
# 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
|
-
)
|
|
724
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
|
|
1005
725
|
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
|
|
726
|
+
((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
|
|
727
|
+
/ 4
|
|
1014
728
|
)
|
|
1015
729
|
else:
|
|
1016
730
|
# RMS
|
|
1017
731
|
p = [
|
|
1018
732
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
1019
733
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
1020
|
-
hq[2].prob(),
|
|
1021
734
|
]
|
|
1022
735
|
# 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
|
|
736
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
|
|
737
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
|
|
1025
738
|
|
|
1026
739
|
return (prms + (1 - qrms)) / 2
|
|
1027
740
|
|
|
@@ -1034,7 +747,7 @@ class QrackAceBackend:
|
|
|
1034
747
|
p = self.prob(lq)
|
|
1035
748
|
result = ((p + self._epsilon) >= 1) or (random.random() < p)
|
|
1036
749
|
|
|
1037
|
-
qb
|
|
750
|
+
qb = self._get_qb_indices(hq)
|
|
1038
751
|
|
|
1039
752
|
for q in qb:
|
|
1040
753
|
b = hq[q]
|
|
@@ -1045,11 +758,6 @@ class QrackAceBackend:
|
|
|
1045
758
|
else:
|
|
1046
759
|
self.sim[b[0]].force_m(b[1], result)
|
|
1047
760
|
|
|
1048
|
-
b = hq[lhv]
|
|
1049
|
-
b.reset()
|
|
1050
|
-
if result:
|
|
1051
|
-
b.x()
|
|
1052
|
-
|
|
1053
761
|
return result
|
|
1054
762
|
|
|
1055
763
|
def force_m(self, lq, result):
|
|
@@ -1060,7 +768,7 @@ class QrackAceBackend:
|
|
|
1060
768
|
|
|
1061
769
|
self._correct(lq)
|
|
1062
770
|
|
|
1063
|
-
qb
|
|
771
|
+
qb = self._get_qb_indices(hq)
|
|
1064
772
|
|
|
1065
773
|
for q in qb:
|
|
1066
774
|
b = hq[q]
|
|
@@ -1071,11 +779,6 @@ class QrackAceBackend:
|
|
|
1071
779
|
else:
|
|
1072
780
|
self.sim[b[0]].force_m(b[1], result)
|
|
1073
781
|
|
|
1074
|
-
b = hq[1]
|
|
1075
|
-
b.reset()
|
|
1076
|
-
if result:
|
|
1077
|
-
b.x()
|
|
1078
|
-
|
|
1079
782
|
return c
|
|
1080
783
|
|
|
1081
784
|
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=1ibcuK68O2hwW8AzzxHLURXcjuQ13HKU-nIVZPLYJIg,39752
|
|
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=uoM5svDGvpgOZ3-
|
|
|
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.61.
|
|
20
|
-
pyqrack_cpu-1.61.
|
|
21
|
-
pyqrack_cpu-1.61.
|
|
22
|
-
pyqrack_cpu-1.61.
|
|
23
|
-
pyqrack_cpu-1.61.
|
|
19
|
+
pyqrack_cpu-1.61.3.dist-info/licenses/LICENSE,sha256=HxB-7SaWTuewAk1nz-3_3FUD6QhgX73kNT_taKVUTq8,1069
|
|
20
|
+
pyqrack_cpu-1.61.3.dist-info/METADATA,sha256=Dhg78xsy5KDjjqgltkFb8r8yEZM-g3FlM8kRwqzGAis,6181
|
|
21
|
+
pyqrack_cpu-1.61.3.dist-info/WHEEL,sha256=k8EuOMBHdXsN9XSTE5LrpwS4FtdLkoSlyO_7W-lE_zg,109
|
|
22
|
+
pyqrack_cpu-1.61.3.dist-info/top_level.txt,sha256=YE_3q9JTGRLMilNg2tGP1y7uU-Dx8PDao2OhwoIbv8E,8
|
|
23
|
+
pyqrack_cpu-1.61.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|