pyqrack-complex128 1.62.0__py3-none-macosx_13_0_x86_64.whl → 1.71.1__py3-none-macosx_13_0_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-complex128 might be problematic. Click here for more details.
- pyqrack/qrack_ace_backend.py +375 -64
- pyqrack/qrack_simulator.py +81 -13
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.9.30.1.dylib +0 -0
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.dylib +0 -0
- pyqrack/qrack_system/qrack_system.py +16 -3
- {pyqrack_complex128-1.62.0.dist-info → pyqrack_complex128-1.71.1.dist-info}/METADATA +2 -2
- {pyqrack_complex128-1.62.0.dist-info → pyqrack_complex128-1.71.1.dist-info}/RECORD +10 -10
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.9.22.0.dylib +0 -0
- {pyqrack_complex128-1.62.0.dist-info → pyqrack_complex128-1.71.1.dist-info}/LICENSE +0 -0
- {pyqrack_complex128-1.62.0.dist-info → pyqrack_complex128-1.71.1.dist-info}/WHEEL +0 -0
- {pyqrack_complex128-1.62.0.dist-info → pyqrack_complex128-1.71.1.dist-info}/top_level.txt +0 -0
pyqrack/qrack_ace_backend.py
CHANGED
|
@@ -27,6 +27,169 @@ 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
|
+
p = math.sqrt(new_x**2 + new_y**2 + new_z**2)
|
|
143
|
+
|
|
144
|
+
new_x /= p
|
|
145
|
+
new_y /= p
|
|
146
|
+
new_z /= p
|
|
147
|
+
|
|
148
|
+
self.bloch = [new_x, new_y, new_z]
|
|
149
|
+
|
|
150
|
+
def prob(self, basis=Pauli.PauliZ):
|
|
151
|
+
"""Sample a classical outcome from the current 'quantum' state"""
|
|
152
|
+
if basis == Pauli.PauliZ:
|
|
153
|
+
prob_1 = (1 - self.bloch[2]) / 2
|
|
154
|
+
elif basis == Pauli.PauliX:
|
|
155
|
+
prob_1 = (1 - self.bloch[0]) / 2
|
|
156
|
+
elif basis == Pauli.PauliY:
|
|
157
|
+
prob_1 = (1 - self.bloch[1]) / 2
|
|
158
|
+
else:
|
|
159
|
+
raise ValueError(f"Unsupported basis: {basis}")
|
|
160
|
+
return prob_1
|
|
161
|
+
|
|
162
|
+
def m(self):
|
|
163
|
+
result = random.random() < self.prob()
|
|
164
|
+
self.reset()
|
|
165
|
+
if result:
|
|
166
|
+
self.x()
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# Provided by Elara (the custom OpenAI GPT)
|
|
171
|
+
def _cpauli_lhv(prob, targ, axis, anti, theta=math.pi):
|
|
172
|
+
"""
|
|
173
|
+
Apply a 'soft' controlled-Pauli gate: rotate target qubit
|
|
174
|
+
proportionally to control's Z expectation value.
|
|
175
|
+
|
|
176
|
+
theta: full rotation angle if control in |1⟩
|
|
177
|
+
"""
|
|
178
|
+
# Control influence is (1 - ctrl.bloch[2]) / 2 = P(|1⟩)
|
|
179
|
+
# BUT we avoid collapse by using the expectation value:
|
|
180
|
+
control_influence = (1 - prob) if anti else prob
|
|
181
|
+
|
|
182
|
+
effective_theta = control_influence * theta
|
|
183
|
+
|
|
184
|
+
# Apply partial rotation to target qubit:
|
|
185
|
+
if axis == Pauli.PauliX:
|
|
186
|
+
targ.rx(effective_theta)
|
|
187
|
+
elif axis == Pauli.PauliY:
|
|
188
|
+
targ.ry(effective_theta)
|
|
189
|
+
elif axis == Pauli.PauliZ:
|
|
190
|
+
targ.rz(effective_theta)
|
|
191
|
+
|
|
192
|
+
|
|
30
193
|
class QrackAceBackend:
|
|
31
194
|
"""A back end for elided quantum error correction
|
|
32
195
|
|
|
@@ -45,7 +208,6 @@ class QrackAceBackend:
|
|
|
45
208
|
sim(QrackSimulator): Array of simulators corresponding to "patches" between boundary rows.
|
|
46
209
|
long_range_columns(int): How many ideal rows between QEC boundary rows?
|
|
47
210
|
is_transpose(bool): Rows are long if False, columns are long if True
|
|
48
|
-
correction_bias(float): Bias magnitude and direction during pseudo-QEC
|
|
49
211
|
"""
|
|
50
212
|
|
|
51
213
|
def __init__(
|
|
@@ -54,7 +216,6 @@ class QrackAceBackend:
|
|
|
54
216
|
long_range_columns=4,
|
|
55
217
|
long_range_rows=4,
|
|
56
218
|
is_transpose=False,
|
|
57
|
-
correction_bias=0,
|
|
58
219
|
isTensorNetwork=False,
|
|
59
220
|
isSchmidtDecomposeMulti=False,
|
|
60
221
|
isSchmidtDecompose=True,
|
|
@@ -83,7 +244,6 @@ class QrackAceBackend:
|
|
|
83
244
|
self.long_range_columns = long_range_columns
|
|
84
245
|
self.long_range_rows = long_range_rows
|
|
85
246
|
self.is_transpose = is_transpose
|
|
86
|
-
self.correction_bias = correction_bias
|
|
87
247
|
|
|
88
248
|
fppow = 5
|
|
89
249
|
if "QRACK_FPPOW" in os.environ:
|
|
@@ -122,6 +282,7 @@ class QrackAceBackend:
|
|
|
122
282
|
self._qubits = []
|
|
123
283
|
sim_counts = [0] * sim_count
|
|
124
284
|
sim_id = 0
|
|
285
|
+
tot_qubits = 0
|
|
125
286
|
for r in self._is_row_long_range:
|
|
126
287
|
for c in self._is_col_long_range:
|
|
127
288
|
qubit = [(sim_id, sim_counts[sim_id])]
|
|
@@ -132,6 +293,14 @@ class QrackAceBackend:
|
|
|
132
293
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
133
294
|
sim_counts[t_sim_id] += 1
|
|
134
295
|
|
|
296
|
+
qubit.append(
|
|
297
|
+
LHVQubit(
|
|
298
|
+
toClone=(
|
|
299
|
+
toClone._qubits[tot_qubits][2] if toClone else None
|
|
300
|
+
)
|
|
301
|
+
)
|
|
302
|
+
)
|
|
303
|
+
|
|
135
304
|
if (not c) and (not r):
|
|
136
305
|
t_sim_id = (sim_id + col_patch_count) % sim_count
|
|
137
306
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
@@ -145,6 +314,7 @@ class QrackAceBackend:
|
|
|
145
314
|
sim_id = (sim_id + 1) % sim_count
|
|
146
315
|
|
|
147
316
|
self._qubits.append(qubit)
|
|
317
|
+
tot_qubits += 1
|
|
148
318
|
|
|
149
319
|
self.sim = []
|
|
150
320
|
for i in range(sim_count):
|
|
@@ -262,16 +432,34 @@ class QrackAceBackend:
|
|
|
262
432
|
def _unpack(self, lq):
|
|
263
433
|
return self._qubits[lq]
|
|
264
434
|
|
|
265
|
-
def
|
|
435
|
+
def _get_qb_lhv_indices(self, hq):
|
|
266
436
|
qb = []
|
|
267
437
|
if len(hq) < 2:
|
|
268
438
|
qb = [0]
|
|
439
|
+
lhv = -1
|
|
269
440
|
elif len(hq) < 4:
|
|
270
441
|
qb = [0, 1]
|
|
442
|
+
lhv = 2
|
|
271
443
|
else:
|
|
272
|
-
qb = [0, 1,
|
|
444
|
+
qb = [0, 1, 3, 4]
|
|
445
|
+
lhv = 2
|
|
273
446
|
|
|
274
|
-
return qb
|
|
447
|
+
return qb, lhv
|
|
448
|
+
|
|
449
|
+
def _get_lhv_bloch_angles(self, sim):
|
|
450
|
+
# Z axis
|
|
451
|
+
z = sim.bloch[2]
|
|
452
|
+
|
|
453
|
+
# X axis
|
|
454
|
+
x = sim.bloch[0]
|
|
455
|
+
|
|
456
|
+
# Y axis
|
|
457
|
+
y = sim.bloch[1]
|
|
458
|
+
|
|
459
|
+
inclination = math.atan2(math.sqrt(x**2 + y**2), z)
|
|
460
|
+
azimuth = math.atan2(y, x)
|
|
461
|
+
|
|
462
|
+
return azimuth, inclination
|
|
275
463
|
|
|
276
464
|
def _get_bloch_angles(self, hq):
|
|
277
465
|
sim = self.sim[hq[0]].clone()
|
|
@@ -315,100 +503,146 @@ class QrackAceBackend:
|
|
|
315
503
|
|
|
316
504
|
sim.mtrx([m00, m01, m10, m11], q)
|
|
317
505
|
|
|
506
|
+
def _rotate_lhv_to_bloch(self, sim, delta_azimuth, delta_inclination):
|
|
507
|
+
# Apply rotation as "Azimuth, Inclination" (AI)
|
|
508
|
+
cosA = math.cos(delta_azimuth)
|
|
509
|
+
sinA = math.sin(delta_azimuth)
|
|
510
|
+
cosI = math.cos(delta_inclination / 2)
|
|
511
|
+
sinI = math.sin(delta_inclination / 2)
|
|
512
|
+
|
|
513
|
+
m00 = complex(cosI, 0)
|
|
514
|
+
m01 = complex(-cosA, sinA) * sinI
|
|
515
|
+
m10 = complex(cosA, sinA) * sinI
|
|
516
|
+
m11 = complex(cosI, 0)
|
|
517
|
+
|
|
518
|
+
sim.mtrx([m00, m01, m10, m11])
|
|
519
|
+
|
|
318
520
|
def _correct(self, lq, phase=False, skip_rotation=False):
|
|
319
521
|
hq = self._unpack(lq)
|
|
320
522
|
|
|
321
523
|
if len(hq) == 1:
|
|
322
524
|
return
|
|
323
525
|
|
|
324
|
-
qb = self.
|
|
526
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
325
527
|
|
|
326
528
|
if phase:
|
|
327
529
|
for q in qb:
|
|
328
530
|
b = hq[q]
|
|
329
531
|
self.sim[b[0]].h(b[1])
|
|
532
|
+
b = hq[lhv]
|
|
533
|
+
b.h()
|
|
330
534
|
|
|
331
535
|
if len(hq) == 5:
|
|
332
536
|
# RMS
|
|
333
537
|
p = [
|
|
334
538
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
335
539
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
336
|
-
|
|
540
|
+
hq[2].prob(),
|
|
337
541
|
self.sim[hq[3][0]].prob(hq[3][1]),
|
|
542
|
+
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
338
543
|
]
|
|
339
544
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
340
|
-
prms = math.sqrt(
|
|
545
|
+
prms = math.sqrt(
|
|
546
|
+
(p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
|
|
547
|
+
)
|
|
341
548
|
qrms = math.sqrt(
|
|
342
|
-
(
|
|
343
|
-
|
|
549
|
+
(
|
|
550
|
+
(1 - p[0]) ** 2
|
|
551
|
+
+ (1 - p[1]) ** 2
|
|
552
|
+
+ 3 * ((1 - p[2]) ** 2)
|
|
553
|
+
+ (1 - p[3]) ** 2
|
|
554
|
+
+ (1 - p[4]) ** 2
|
|
555
|
+
)
|
|
556
|
+
/ 7
|
|
344
557
|
)
|
|
345
558
|
result = ((prms + (1 - qrms)) / 2) >= 0.5
|
|
346
559
|
syndrome = (
|
|
347
|
-
[1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3]]
|
|
560
|
+
[1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3], 1 - p[4]]
|
|
348
561
|
if result
|
|
349
|
-
else [p[0], p[1], p[2], p[3]]
|
|
562
|
+
else [p[0], p[1], p[2], p[3], p[4]]
|
|
350
563
|
)
|
|
351
|
-
for q in range(
|
|
564
|
+
for q in range(5):
|
|
352
565
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
353
|
-
|
|
566
|
+
if q == 2:
|
|
567
|
+
hq[q].x()
|
|
568
|
+
else:
|
|
569
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
354
570
|
|
|
355
571
|
if not skip_rotation:
|
|
356
|
-
a, i = [0, 0, 0, 0], [0, 0, 0, 0]
|
|
572
|
+
a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
|
|
357
573
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
358
574
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
359
|
-
a[2], i[2] = self.
|
|
360
|
-
a[3], i[3] = self._get_bloch_angles(hq[
|
|
575
|
+
a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
|
|
576
|
+
a[3], i[3] = self._get_bloch_angles(hq[3])
|
|
577
|
+
a[4], i[4] = self._get_bloch_angles(hq[4])
|
|
361
578
|
|
|
362
579
|
a_target = 0
|
|
363
580
|
i_target = 0
|
|
364
|
-
for x in range(
|
|
581
|
+
for x in range(5):
|
|
582
|
+
if x == 2:
|
|
583
|
+
continue
|
|
365
584
|
a_target += a[x]
|
|
366
585
|
i_target += i[x]
|
|
367
586
|
|
|
368
|
-
a_target /=
|
|
369
|
-
i_target /=
|
|
370
|
-
for x in range(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
587
|
+
a_target /= 5
|
|
588
|
+
i_target /= 5
|
|
589
|
+
for x in range(5):
|
|
590
|
+
if x == 2:
|
|
591
|
+
self._rotate_lhv_to_bloch(
|
|
592
|
+
hq[x], a_target - a[x], i_target - i[x]
|
|
593
|
+
)
|
|
594
|
+
else:
|
|
595
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
374
596
|
|
|
375
597
|
else:
|
|
376
598
|
# RMS
|
|
377
599
|
p = [
|
|
378
600
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
379
601
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
602
|
+
hq[2].prob(),
|
|
380
603
|
]
|
|
381
604
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
382
|
-
prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
|
|
383
|
-
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
|
|
605
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
|
|
606
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
|
|
384
607
|
result = ((prms + (1 - qrms)) / 2) >= 0.5
|
|
385
|
-
syndrome = [1 - p[0], 1 - p[1]] if result else [p[0], p[1]]
|
|
386
|
-
for q in range(
|
|
608
|
+
syndrome = [1 - p[0], 1 - p[1], 1 - p[2]] if result else [p[0], p[1], p[2]]
|
|
609
|
+
for q in range(3):
|
|
387
610
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
388
|
-
|
|
611
|
+
if q == 2:
|
|
612
|
+
hq[q].x()
|
|
613
|
+
else:
|
|
614
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
389
615
|
|
|
390
616
|
if not skip_rotation:
|
|
391
|
-
a, i = [0, 0], [0, 0]
|
|
617
|
+
a, i = [0, 0, 0], [0, 0, 0]
|
|
392
618
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
393
619
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
620
|
+
a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
|
|
394
621
|
|
|
395
622
|
a_target = 0
|
|
396
623
|
i_target = 0
|
|
397
|
-
for x in range(
|
|
624
|
+
for x in range(3):
|
|
625
|
+
if x == 2:
|
|
626
|
+
continue
|
|
398
627
|
a_target += a[x]
|
|
399
628
|
i_target += i[x]
|
|
400
629
|
|
|
401
|
-
a_target /=
|
|
402
|
-
i_target /=
|
|
403
|
-
for x in range(
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
630
|
+
a_target /= 3
|
|
631
|
+
i_target /= 3
|
|
632
|
+
for x in range(3):
|
|
633
|
+
if x == 2:
|
|
634
|
+
self._rotate_lhv_to_bloch(
|
|
635
|
+
hq[x], a_target - a[x], i_target - i[x]
|
|
636
|
+
)
|
|
637
|
+
else:
|
|
638
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
407
639
|
|
|
408
640
|
if phase:
|
|
409
641
|
for q in qb:
|
|
410
642
|
b = hq[q]
|
|
411
643
|
self.sim[b[0]].h(b[1])
|
|
644
|
+
b = hq[lhv]
|
|
645
|
+
b.h()
|
|
412
646
|
|
|
413
647
|
def apply_magnetic_bias(self, q, b):
|
|
414
648
|
if b == 0:
|
|
@@ -416,11 +650,22 @@ class QrackAceBackend:
|
|
|
416
650
|
b = math.exp(b)
|
|
417
651
|
for x in q:
|
|
418
652
|
hq = self._unpack(x)
|
|
419
|
-
for
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
653
|
+
for c in range(len(hq)):
|
|
654
|
+
h = hq[c]
|
|
655
|
+
if c == 2:
|
|
656
|
+
a, i = self._get_lhv_bloch_angles(h)
|
|
657
|
+
self._rotate_lhv_to_bloch(
|
|
658
|
+
h,
|
|
659
|
+
math.atan(math.tan(a) * b) - a,
|
|
660
|
+
math.atan(math.tan(i) * b) - i,
|
|
661
|
+
)
|
|
662
|
+
else:
|
|
663
|
+
a, i = self._get_bloch_angles(h)
|
|
664
|
+
self._rotate_to_bloch(
|
|
665
|
+
h,
|
|
666
|
+
math.atan(math.tan(a) * b) - a,
|
|
667
|
+
math.atan(math.tan(i) * b) - i,
|
|
668
|
+
)
|
|
424
669
|
|
|
425
670
|
def u(self, lq, th, ph, lm):
|
|
426
671
|
hq = self._unpack(lq)
|
|
@@ -429,12 +674,15 @@ class QrackAceBackend:
|
|
|
429
674
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
430
675
|
return
|
|
431
676
|
|
|
432
|
-
qb = self.
|
|
677
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
433
678
|
|
|
434
679
|
for q in qb:
|
|
435
680
|
b = hq[q]
|
|
436
681
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
437
682
|
|
|
683
|
+
b = hq[lhv]
|
|
684
|
+
b.u(th, ph, lm)
|
|
685
|
+
|
|
438
686
|
self._correct(lq, False, True)
|
|
439
687
|
self._correct(lq, True, False)
|
|
440
688
|
|
|
@@ -445,12 +693,20 @@ class QrackAceBackend:
|
|
|
445
693
|
self.sim[b[0]].r(p, th, b[1])
|
|
446
694
|
return
|
|
447
695
|
|
|
448
|
-
qb = self.
|
|
696
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
449
697
|
|
|
450
698
|
for q in qb:
|
|
451
699
|
b = hq[q]
|
|
452
700
|
self.sim[b[0]].r(p, th, b[1])
|
|
453
701
|
|
|
702
|
+
b = hq[lhv]
|
|
703
|
+
if p == Pauli.PauliX:
|
|
704
|
+
b.rx(th)
|
|
705
|
+
elif p == Pauli.PauliY:
|
|
706
|
+
b.ry(th)
|
|
707
|
+
elif p == Pauli.PauliZ:
|
|
708
|
+
b.rz(th)
|
|
709
|
+
|
|
454
710
|
if p != Pauli.PauliZ:
|
|
455
711
|
self._correct(lq, False, p != Pauli.PauliX)
|
|
456
712
|
if p != Pauli.PauliX:
|
|
@@ -465,12 +721,15 @@ class QrackAceBackend:
|
|
|
465
721
|
|
|
466
722
|
self._correct(lq)
|
|
467
723
|
|
|
468
|
-
qb = self.
|
|
724
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
469
725
|
|
|
470
726
|
for q in qb:
|
|
471
727
|
b = hq[q]
|
|
472
728
|
self.sim[b[0]].h(b[1])
|
|
473
729
|
|
|
730
|
+
b = hq[lhv]
|
|
731
|
+
b.h()
|
|
732
|
+
|
|
474
733
|
self._correct(lq)
|
|
475
734
|
|
|
476
735
|
def s(self, lq):
|
|
@@ -480,12 +739,15 @@ class QrackAceBackend:
|
|
|
480
739
|
self.sim[b[0]].s(b[1])
|
|
481
740
|
return
|
|
482
741
|
|
|
483
|
-
qb = self.
|
|
742
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
484
743
|
|
|
485
744
|
for q in qb:
|
|
486
745
|
b = hq[q]
|
|
487
746
|
self.sim[b[0]].s(b[1])
|
|
488
747
|
|
|
748
|
+
b = hq[lhv]
|
|
749
|
+
b.s()
|
|
750
|
+
|
|
489
751
|
def adjs(self, lq):
|
|
490
752
|
hq = self._unpack(lq)
|
|
491
753
|
if len(hq) < 2:
|
|
@@ -493,12 +755,15 @@ class QrackAceBackend:
|
|
|
493
755
|
self.sim[b[0]].adjs(b[1])
|
|
494
756
|
return
|
|
495
757
|
|
|
496
|
-
qb = self.
|
|
758
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
497
759
|
|
|
498
760
|
for q in qb:
|
|
499
761
|
b = hq[q]
|
|
500
762
|
self.sim[b[0]].adjs(b[1])
|
|
501
763
|
|
|
764
|
+
b = hq[lhv]
|
|
765
|
+
b.adjs()
|
|
766
|
+
|
|
502
767
|
def x(self, lq):
|
|
503
768
|
hq = self._unpack(lq)
|
|
504
769
|
if len(hq) < 2:
|
|
@@ -506,12 +771,15 @@ class QrackAceBackend:
|
|
|
506
771
|
self.sim[b[0]].x(b[1])
|
|
507
772
|
return
|
|
508
773
|
|
|
509
|
-
qb = self.
|
|
774
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
510
775
|
|
|
511
776
|
for q in qb:
|
|
512
777
|
b = hq[q]
|
|
513
778
|
self.sim[b[0]].x(b[1])
|
|
514
779
|
|
|
780
|
+
b = hq[lhv]
|
|
781
|
+
b.x()
|
|
782
|
+
|
|
515
783
|
def y(self, lq):
|
|
516
784
|
hq = self._unpack(lq)
|
|
517
785
|
if len(hq) < 2:
|
|
@@ -519,12 +787,15 @@ class QrackAceBackend:
|
|
|
519
787
|
self.sim[b[0]].y(b[1])
|
|
520
788
|
return
|
|
521
789
|
|
|
522
|
-
qb = self.
|
|
790
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
523
791
|
|
|
524
792
|
for q in qb:
|
|
525
793
|
b = hq[q]
|
|
526
794
|
self.sim[b[0]].y(b[1])
|
|
527
795
|
|
|
796
|
+
b = hq[lhv]
|
|
797
|
+
b.y()
|
|
798
|
+
|
|
528
799
|
def z(self, lq):
|
|
529
800
|
hq = self._unpack(lq)
|
|
530
801
|
if len(hq) < 2:
|
|
@@ -532,12 +803,15 @@ class QrackAceBackend:
|
|
|
532
803
|
self.sim[b[0]].z(b[1])
|
|
533
804
|
return
|
|
534
805
|
|
|
535
|
-
qb = self.
|
|
806
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
536
807
|
|
|
537
808
|
for q in qb:
|
|
538
809
|
b = hq[q]
|
|
539
810
|
self.sim[b[0]].z(b[1])
|
|
540
811
|
|
|
812
|
+
b = hq[lhv]
|
|
813
|
+
b.z()
|
|
814
|
+
|
|
541
815
|
def t(self, lq):
|
|
542
816
|
hq = self._unpack(lq)
|
|
543
817
|
if len(hq) < 2:
|
|
@@ -545,12 +819,15 @@ class QrackAceBackend:
|
|
|
545
819
|
self.sim[b[0]].t(b[1])
|
|
546
820
|
return
|
|
547
821
|
|
|
548
|
-
qb = self.
|
|
822
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
549
823
|
|
|
550
824
|
for q in qb:
|
|
551
825
|
b = hq[q]
|
|
552
826
|
self.sim[b[0]].t(b[1])
|
|
553
827
|
|
|
828
|
+
b = hq[lhv]
|
|
829
|
+
b.t()
|
|
830
|
+
|
|
554
831
|
def adjt(self, lq):
|
|
555
832
|
hq = self._unpack(lq)
|
|
556
833
|
if len(hq) < 2:
|
|
@@ -558,12 +835,15 @@ class QrackAceBackend:
|
|
|
558
835
|
self.sim[b[0]].adjt(b[1])
|
|
559
836
|
return
|
|
560
837
|
|
|
561
|
-
qb = self.
|
|
838
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
562
839
|
|
|
563
840
|
for q in qb:
|
|
564
841
|
b = hq[q]
|
|
565
842
|
self.sim[b[0]].adjt(b[1])
|
|
566
843
|
|
|
844
|
+
b = hq[lhv]
|
|
845
|
+
b.adjt()
|
|
846
|
+
|
|
567
847
|
def _get_gate(self, pauli, anti, sim_id):
|
|
568
848
|
gate = None
|
|
569
849
|
shadow = None
|
|
@@ -604,11 +884,15 @@ class QrackAceBackend:
|
|
|
604
884
|
|
|
605
885
|
return connected, boundary
|
|
606
886
|
|
|
607
|
-
def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr):
|
|
887
|
+
def _apply_coupling(self, pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr):
|
|
608
888
|
for q1 in qb1:
|
|
889
|
+
if q1 == lhv1:
|
|
890
|
+
continue
|
|
609
891
|
b1 = hq1[q1]
|
|
610
892
|
gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
|
|
611
893
|
for q2 in qb2:
|
|
894
|
+
if q2 == lhv2:
|
|
895
|
+
continue
|
|
612
896
|
b2 = hq2[q2]
|
|
613
897
|
if b1[0] == b2[0]:
|
|
614
898
|
gate_fn([b1[1]], b2[1])
|
|
@@ -633,10 +917,18 @@ class QrackAceBackend:
|
|
|
633
917
|
|
|
634
918
|
self._correct(lq1)
|
|
635
919
|
|
|
636
|
-
qb1 = self.
|
|
637
|
-
qb2 = self.
|
|
920
|
+
qb1, lhv1 = self._get_qb_lhv_indices(hq1)
|
|
921
|
+
qb2, lhv2 = self._get_qb_lhv_indices(hq2)
|
|
638
922
|
# Apply cross coupling on hardware qubits first
|
|
639
|
-
self._apply_coupling(pauli, anti, qb1, hq1, qb2, hq2, lq1_lr)
|
|
923
|
+
self._apply_coupling(pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr)
|
|
924
|
+
# Apply coupling to the local-hidden-variable target
|
|
925
|
+
if lhv2 >= 0:
|
|
926
|
+
_cpauli_lhv(
|
|
927
|
+
hq1[lhv1].prob() if lhv1 >= 0 else self.sim[hq1[0][0]].prob(hq1[0][1]),
|
|
928
|
+
hq2[lhv2],
|
|
929
|
+
pauli,
|
|
930
|
+
anti,
|
|
931
|
+
)
|
|
640
932
|
|
|
641
933
|
self._correct(lq1, True)
|
|
642
934
|
if pauli != Pauli.PauliZ:
|
|
@@ -738,20 +1030,29 @@ class QrackAceBackend:
|
|
|
738
1030
|
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
739
1031
|
]
|
|
740
1032
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
741
|
-
prms = math.sqrt(
|
|
1033
|
+
prms = math.sqrt(
|
|
1034
|
+
(p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
|
|
1035
|
+
)
|
|
742
1036
|
qrms = math.sqrt(
|
|
743
|
-
(
|
|
744
|
-
|
|
1037
|
+
(
|
|
1038
|
+
(1 - p[0]) ** 2
|
|
1039
|
+
+ (1 - p[1]) ** 2
|
|
1040
|
+
+ 3 * ((1 - p[2]) ** 2)
|
|
1041
|
+
+ (1 - p[3]) ** 2
|
|
1042
|
+
+ (1 - p[4]) ** 2
|
|
1043
|
+
)
|
|
1044
|
+
/ 7
|
|
745
1045
|
)
|
|
746
1046
|
else:
|
|
747
1047
|
# RMS
|
|
748
1048
|
p = [
|
|
749
1049
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
750
1050
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
1051
|
+
hq[2].prob(),
|
|
751
1052
|
]
|
|
752
1053
|
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
753
|
-
prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
|
|
754
|
-
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
|
|
1054
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
|
|
1055
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
|
|
755
1056
|
|
|
756
1057
|
return (prms + (1 - qrms)) / 2
|
|
757
1058
|
|
|
@@ -764,7 +1065,7 @@ class QrackAceBackend:
|
|
|
764
1065
|
p = self.prob(lq)
|
|
765
1066
|
result = ((p + self._epsilon) >= 1) or (random.random() < p)
|
|
766
1067
|
|
|
767
|
-
qb = self.
|
|
1068
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
768
1069
|
|
|
769
1070
|
for q in qb:
|
|
770
1071
|
b = hq[q]
|
|
@@ -775,6 +1076,11 @@ class QrackAceBackend:
|
|
|
775
1076
|
else:
|
|
776
1077
|
self.sim[b[0]].force_m(b[1], result)
|
|
777
1078
|
|
|
1079
|
+
b = hq[lhv]
|
|
1080
|
+
b.reset()
|
|
1081
|
+
if result:
|
|
1082
|
+
b.x()
|
|
1083
|
+
|
|
778
1084
|
return result
|
|
779
1085
|
|
|
780
1086
|
def force_m(self, lq, result):
|
|
@@ -785,7 +1091,7 @@ class QrackAceBackend:
|
|
|
785
1091
|
|
|
786
1092
|
self._correct(lq)
|
|
787
1093
|
|
|
788
|
-
qb = self.
|
|
1094
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
|
789
1095
|
|
|
790
1096
|
for q in qb:
|
|
791
1097
|
b = hq[q]
|
|
@@ -796,6 +1102,11 @@ class QrackAceBackend:
|
|
|
796
1102
|
else:
|
|
797
1103
|
self.sim[b[0]].force_m(b[1], result)
|
|
798
1104
|
|
|
1105
|
+
b = hq[1]
|
|
1106
|
+
b.reset()
|
|
1107
|
+
if result:
|
|
1108
|
+
b.x()
|
|
1109
|
+
|
|
799
1110
|
return c
|
|
800
1111
|
|
|
801
1112
|
def m_all(self):
|
pyqrack/qrack_simulator.py
CHANGED
|
@@ -60,6 +60,7 @@ class QrackSimulator:
|
|
|
60
60
|
isHostPointer=(
|
|
61
61
|
True if os.environ.get("PYQRACK_HOST_POINTER_DEFAULT_ON") else False
|
|
62
62
|
),
|
|
63
|
+
isSparse=False,
|
|
63
64
|
noise=0,
|
|
64
65
|
pyzxCircuit=None,
|
|
65
66
|
qiskitCircuit=None,
|
|
@@ -99,6 +100,7 @@ class QrackSimulator:
|
|
|
99
100
|
isCpuGpuHybrid,
|
|
100
101
|
isOpenCL,
|
|
101
102
|
isHostPointer,
|
|
103
|
+
isSparse
|
|
102
104
|
)
|
|
103
105
|
|
|
104
106
|
self._throw_if_error()
|
|
@@ -1053,9 +1055,16 @@ class QrackSimulator:
|
|
|
1053
1055
|
Returns:
|
|
1054
1056
|
Measurement result of all qubits.
|
|
1055
1057
|
"""
|
|
1056
|
-
|
|
1058
|
+
num_q = self.num_qubits()
|
|
1059
|
+
num_words = (num_q + 63) // 64
|
|
1060
|
+
_r = (ctypes.c_ulonglong * num_words)()
|
|
1061
|
+
Qrack.qrack_lib.MAllLong(self.sid, _r)
|
|
1057
1062
|
self._throw_if_error()
|
|
1058
|
-
|
|
1063
|
+
r = 0
|
|
1064
|
+
for w in range(num_words):
|
|
1065
|
+
r <<= 64
|
|
1066
|
+
r |= _r[w]
|
|
1067
|
+
return r
|
|
1059
1068
|
|
|
1060
1069
|
def measure_pauli(self, b, q):
|
|
1061
1070
|
"""Pauli Measurement gate
|
|
@@ -2125,9 +2134,7 @@ class QrackSimulator:
|
|
|
2125
2134
|
def decompose(self, q):
|
|
2126
2135
|
"""Decompose system
|
|
2127
2136
|
|
|
2128
|
-
|
|
2129
|
-
Warning: The qubit subsystem state must be separable, or the behavior
|
|
2130
|
-
of this method is undefined.
|
|
2137
|
+
Factorize a set of contiguous bits with minimal fidelity loss.
|
|
2131
2138
|
|
|
2132
2139
|
Args:
|
|
2133
2140
|
q: qubit id
|
|
@@ -2137,7 +2144,7 @@ class QrackSimulator:
|
|
|
2137
2144
|
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot decompose()! (Turn off just this option, in the constructor.)
|
|
2138
2145
|
|
|
2139
2146
|
Returns:
|
|
2140
|
-
|
|
2147
|
+
Decomposed subsystem simulator.
|
|
2141
2148
|
"""
|
|
2142
2149
|
if self.is_tensor_network:
|
|
2143
2150
|
raise RuntimeError(
|
|
@@ -2154,10 +2161,8 @@ class QrackSimulator:
|
|
|
2154
2161
|
def dispose(self, q):
|
|
2155
2162
|
"""Dispose qubits
|
|
2156
2163
|
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
Warning: The qubit subsystem state must be separable, or the behavior
|
|
2160
|
-
of this method is undefined.
|
|
2164
|
+
Factorize a set of contiguous bits with minimal fidelity loss,
|
|
2165
|
+
and discard the separable bits.
|
|
2161
2166
|
|
|
2162
2167
|
Args:
|
|
2163
2168
|
q: qubit
|
|
@@ -2165,9 +2170,6 @@ class QrackSimulator:
|
|
|
2165
2170
|
Raises:
|
|
2166
2171
|
RuntimeError: QrackSimulator raised an exception.
|
|
2167
2172
|
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot dispose()! (Turn off just this option, in the constructor.)
|
|
2168
|
-
|
|
2169
|
-
Returns:
|
|
2170
|
-
State of the systems.
|
|
2171
2173
|
"""
|
|
2172
2174
|
if self.is_tensor_network:
|
|
2173
2175
|
raise RuntimeError(
|
|
@@ -2285,6 +2287,72 @@ class QrackSimulator:
|
|
|
2285
2287
|
self._throw_if_error()
|
|
2286
2288
|
return list(probs)
|
|
2287
2289
|
|
|
2290
|
+
def out_rdm(self, q):
|
|
2291
|
+
"""Get reduced density matrix
|
|
2292
|
+
|
|
2293
|
+
Returns the raw reduced density matrix of the simulator, for the qubit list.
|
|
2294
|
+
Warning: State vector or is not always the internal representation leading
|
|
2295
|
+
to sub-optimal performance of the method.
|
|
2296
|
+
|
|
2297
|
+
Raises:
|
|
2298
|
+
RuntimeError: QrackSimulator raised an exception.
|
|
2299
|
+
|
|
2300
|
+
Returns:
|
|
2301
|
+
flat list structure representing the reduced density matrix.
|
|
2302
|
+
"""
|
|
2303
|
+
amp_count = 1 << len(q)
|
|
2304
|
+
sqr_amp_count = amp_count * amp_count
|
|
2305
|
+
flat_rdm = self._qrack_complex_byref([complex(0, 0)] * sqr_amp_count)
|
|
2306
|
+
Qrack.qrack_lib.OutReducedDensityMatrix(self.sid, len(q), self._ulonglong_byref(q), flat_rdm)
|
|
2307
|
+
self._throw_if_error()
|
|
2308
|
+
return [complex(r, i) for r, i in self._pairwise(flat_rdm)]
|
|
2309
|
+
|
|
2310
|
+
def highest_prob_perm(self):
|
|
2311
|
+
"""Get the permutation (bit string) with the highest probability
|
|
2312
|
+
|
|
2313
|
+
Returns the single highest-probability bit string in the Hilbert space
|
|
2314
|
+
|
|
2315
|
+
Raises:
|
|
2316
|
+
RuntimeError: QrackSimulator raised an exception.
|
|
2317
|
+
|
|
2318
|
+
Returns:
|
|
2319
|
+
Highest probability dimension index
|
|
2320
|
+
"""
|
|
2321
|
+
num_q = self.num_qubits()
|
|
2322
|
+
num_words = (num_q + 63) // 64
|
|
2323
|
+
_r = (ctypes.c_ulonglong * num_words)()
|
|
2324
|
+
Qrack.qrack_lib.HighestProbAll(self.sid, _r)
|
|
2325
|
+
self._throw_if_error()
|
|
2326
|
+
r = 0
|
|
2327
|
+
for w in range(num_words):
|
|
2328
|
+
r <<= 64
|
|
2329
|
+
r |= _r[w]
|
|
2330
|
+
return r
|
|
2331
|
+
|
|
2332
|
+
def highest_n_prob_perm(self, n):
|
|
2333
|
+
"""Get the top n permutations (bit strings) with the highest probability
|
|
2334
|
+
|
|
2335
|
+
Returns the top n highest-probability bit strings in the Hilbert space
|
|
2336
|
+
|
|
2337
|
+
Raises:
|
|
2338
|
+
RuntimeError: QrackSimulator raised an exception.
|
|
2339
|
+
|
|
2340
|
+
Returns:
|
|
2341
|
+
Top n highest probability dimension indices
|
|
2342
|
+
"""
|
|
2343
|
+
num_q = self.num_qubits()
|
|
2344
|
+
num_words = (num_q + 63) // 64
|
|
2345
|
+
_r = (ctypes.c_ulonglong * (num_words * n))()
|
|
2346
|
+
Qrack.qrack_lib.HighestProbAllN(self.sid, n, _r)
|
|
2347
|
+
self._throw_if_error()
|
|
2348
|
+
r = [0] * n
|
|
2349
|
+
for i in range(n):
|
|
2350
|
+
r[i] = 0
|
|
2351
|
+
for w in range(num_words):
|
|
2352
|
+
r[i] <<= 64
|
|
2353
|
+
r[i] |= _r[(i * num_words) + w]
|
|
2354
|
+
return r
|
|
2355
|
+
|
|
2288
2356
|
def prob_all(self, q):
|
|
2289
2357
|
"""Probabilities of all subset permutations
|
|
2290
2358
|
|
|
Binary file
|
|
Binary file
|
|
@@ -87,19 +87,22 @@ class QrackSystem:
|
|
|
87
87
|
CFUNCTYPE(c_ulonglong, c_double, c_double),
|
|
88
88
|
]
|
|
89
89
|
|
|
90
|
-
# These next
|
|
90
|
+
# These next few methods need to have c_double pointers, if PyQrack is built with fp64.
|
|
91
91
|
self.qrack_lib.InKet.restype = None
|
|
92
92
|
self.qrack_lib.OutKet.restype = None
|
|
93
93
|
self.qrack_lib.OutProbs.restype = None
|
|
94
|
+
self.qrack_lib.OutReducedDensityMatrix.restype = None
|
|
94
95
|
|
|
95
96
|
if self.fppow < 6:
|
|
96
97
|
self.qrack_lib.InKet.argtypes = [c_ulonglong, POINTER(c_float)]
|
|
97
98
|
self.qrack_lib.OutKet.argtypes = [c_ulonglong, POINTER(c_float)]
|
|
98
99
|
self.qrack_lib.OutProbs.argtypes = [c_ulonglong, POINTER(c_float)]
|
|
100
|
+
self.qrack_lib.OutReducedDensityMatrix.argtypes = [c_ulonglong, c_ulonglong, POINTER(c_ulonglong), POINTER(c_float)]
|
|
99
101
|
else:
|
|
100
102
|
self.qrack_lib.InKet.argtypes = [c_ulonglong, POINTER(c_double)]
|
|
101
103
|
self.qrack_lib.OutKet.argtypes = [c_ulonglong, POINTER(c_double)]
|
|
102
104
|
self.qrack_lib.OutProbs.argtypes = [c_ulonglong, POINTER(c_double)]
|
|
105
|
+
self.qrack_lib.OutReducedDensityMatrix.argtypes = [c_ulonglong, c_ulonglong, POINTER(c_ulonglong), POINTER(c_double)]
|
|
103
106
|
|
|
104
107
|
self.qrack_lib.init.restype = c_ulonglong
|
|
105
108
|
self.qrack_lib.init.argtypes = []
|
|
@@ -108,10 +111,10 @@ class QrackSystem:
|
|
|
108
111
|
self.qrack_lib.get_error.argtypes = [c_ulonglong]
|
|
109
112
|
|
|
110
113
|
self.qrack_lib.init_count.restype = c_ulonglong
|
|
111
|
-
self.qrack_lib.init_count.argtypes = [c_ulonglong, c_bool]
|
|
114
|
+
self.qrack_lib.init_count.argtypes = [c_ulonglong, c_bool, c_bool]
|
|
112
115
|
|
|
113
116
|
self.qrack_lib.init_count_pager.restype = c_ulonglong
|
|
114
|
-
self.qrack_lib.init_count_pager.argtypes = [c_ulonglong, c_bool]
|
|
117
|
+
self.qrack_lib.init_count_pager.argtypes = [c_ulonglong, c_bool, c_bool]
|
|
115
118
|
|
|
116
119
|
self.qrack_lib.init_count_type.restype = c_ulonglong
|
|
117
120
|
self.qrack_lib.init_count_type.argtypes = [
|
|
@@ -126,6 +129,7 @@ class QrackSystem:
|
|
|
126
129
|
c_bool,
|
|
127
130
|
c_bool,
|
|
128
131
|
c_bool,
|
|
132
|
+
c_bool
|
|
129
133
|
]
|
|
130
134
|
|
|
131
135
|
self.qrack_lib.init_count_stabilizer.restype = c_ulonglong
|
|
@@ -155,6 +159,12 @@ class QrackSystem:
|
|
|
155
159
|
|
|
156
160
|
# pseudo-quantum
|
|
157
161
|
|
|
162
|
+
self.qrack_lib.HighestProbAll.restype = None
|
|
163
|
+
self.qrack_lib.HighestProbAll.argtypes = [c_ulonglong, POINTER(c_ulonglong)]
|
|
164
|
+
|
|
165
|
+
self.qrack_lib.HighestProbAllN.restype = None
|
|
166
|
+
self.qrack_lib.HighestProbAllN.argtypes = [c_ulonglong, c_ulonglong, POINTER(c_ulonglong)]
|
|
167
|
+
|
|
158
168
|
self.qrack_lib.ProbAll.restype = None
|
|
159
169
|
if self.fppow == 5:
|
|
160
170
|
self.qrack_lib.ProbAll.argtypes = [
|
|
@@ -790,6 +800,9 @@ class QrackSystem:
|
|
|
790
800
|
self.qrack_lib.MAll.restype = c_ulonglong
|
|
791
801
|
self.qrack_lib.MAll.argtypes = [c_ulonglong]
|
|
792
802
|
|
|
803
|
+
self.qrack_lib.MAllLong.restype = None
|
|
804
|
+
self.qrack_lib.MAllLong.argtypes = [c_ulonglong, POINTER(c_ulonglong)]
|
|
805
|
+
|
|
793
806
|
self.qrack_lib.Measure.restype = c_ulonglong
|
|
794
807
|
self.qrack_lib.Measure.argtypes = [
|
|
795
808
|
c_ulonglong,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyqrack-complex128
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.71.1
|
|
4
4
|
Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
|
|
5
5
|
Home-page: https://github.com/vm6502q/pyqrack
|
|
6
6
|
Author: Daniel Strano
|
|
@@ -41,7 +41,7 @@ Provides-Extra: dev
|
|
|
41
41
|
Requires-Dist: pytest>=7.3.1; extra == "dev"
|
|
42
42
|
|
|
43
43
|
# pyqrack
|
|
44
|
-
[](https://pepy.tech/project/pyqrack) [](https://pepy.tech/project/pyqrack) [](https://pepy.tech/project/pyqrack)
|
|
44
|
+
[](https://pepy.tech/project/pyqrack-complex128) [](https://pepy.tech/project/pyqrack-complex128) [](https://pepy.tech/project/pyqrack-complex128)
|
|
45
45
|
|
|
46
46
|
Pure Python bindings for the pure C++11/OpenCL Qrack quantum computer simulator library
|
|
47
47
|
|
|
@@ -1,23 +1,23 @@
|
|
|
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=Prw1NhVVt0csbHiJeW8MJI9rl1P1YS63sXM5quoNPrI,49392
|
|
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
|
|
8
|
-
pyqrack/qrack_simulator.py,sha256=
|
|
8
|
+
pyqrack/qrack_simulator.py,sha256=PSrcEIlzCt33WXjoEo5dZdmzx9zR90QI_Dw9LTphjMg,146030
|
|
9
9
|
pyqrack/qrack_stabilizer.py,sha256=O-7VJ9Vw4h25PK_kesSjIqHXGSo8lLrQLIyGgmzG7Co,2124
|
|
10
10
|
pyqrack/quimb_circuit_type.py,sha256=Sk-Tmn38kUYmAkJJ75btWuhYZyTXOOezmowFhfdiGDc,621
|
|
11
11
|
pyqrack/qrack_system/__init__.py,sha256=-oZ9dsb1hixsnrkUJRY_C5DzQ_l6MtifF_Z465BgqV4,334
|
|
12
|
-
pyqrack/qrack_system/qrack_system.py,sha256=
|
|
12
|
+
pyqrack/qrack_system/qrack_system.py,sha256=3NFejSMePILaND-h3bdwRrX-WuhdZj-Uzt-8i90_xQE,43719
|
|
13
13
|
pyqrack/qrack_system/qrack_cl_precompile/qrack_cl_precompile,sha256=8xQYqoFTKIl-5v6ZkqmbWp14Eowkl8ty2vNF2shC5hU,35040
|
|
14
|
-
pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.9.
|
|
15
|
-
pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.dylib,sha256=
|
|
14
|
+
pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.9.30.1.dylib,sha256=dFn-CqdTw3R3k08t-5zDqZRKbjMgyvSUAXk8mugjkds,3941720
|
|
15
|
+
pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.dylib,sha256=dFn-CqdTw3R3k08t-5zDqZRKbjMgyvSUAXk8mugjkds,3941720
|
|
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_complex128-1.
|
|
20
|
-
pyqrack_complex128-1.
|
|
21
|
-
pyqrack_complex128-1.
|
|
22
|
-
pyqrack_complex128-1.
|
|
23
|
-
pyqrack_complex128-1.
|
|
19
|
+
pyqrack_complex128-1.71.1.dist-info/LICENSE,sha256=HxB-7SaWTuewAk1nz-3_3FUD6QhgX73kNT_taKVUTq8,1069
|
|
20
|
+
pyqrack_complex128-1.71.1.dist-info/METADATA,sha256=Xci4A4ZRU7BKKqNPv_UQmR1qyV8m8w1xl4qwnbqetUo,5969
|
|
21
|
+
pyqrack_complex128-1.71.1.dist-info/WHEEL,sha256=nZx8s83OrgdDmpcWX-8FgI0sEAjdQimt4SdYsdcCaC8,107
|
|
22
|
+
pyqrack_complex128-1.71.1.dist-info/top_level.txt,sha256=YE_3q9JTGRLMilNg2tGP1y7uU-Dx8PDao2OhwoIbv8E,8
|
|
23
|
+
pyqrack_complex128-1.71.1.dist-info/RECORD,,
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|