pyqrack-cuda 1.57.1__tar.gz → 1.58.5__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_cuda-1.57.1 → pyqrack_cuda-1.58.5}/Makefile +1 -1
- {pyqrack_cuda-1.57.1/pyqrack_cuda.egg-info → pyqrack_cuda-1.58.5}/PKG-INFO +1 -1
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_ace_backend.py +163 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_simulator.py +8 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_system/qrack_system.py +8 -1
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/setup.py +1 -1
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/LICENSE +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/MANIFEST.in +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/README.md +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyproject.toml +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/__init__.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/requires.txt +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/top_level.txt +0 -0
- {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/setup.cfg +0 -0
@@ -18,7 +18,7 @@ help:
|
|
18
18
|
build-deps:
|
19
19
|
ifneq ($(OS),Windows_NT)
|
20
20
|
ifeq ($(QRACK_PRESENT),)
|
21
|
-
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout
|
21
|
+
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout 8c3f33832d334196836b10afe6765bb44326802d; cd ..
|
22
22
|
endif
|
23
23
|
mkdir -p qrack/build
|
24
24
|
ifeq ($(UNAME_S),Linux)
|
@@ -102,6 +102,45 @@ class LHVQubit:
|
|
102
102
|
self.ry(theta)
|
103
103
|
self.rz(phi)
|
104
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
|
+
|
105
144
|
def prob(self, basis=Pauli.PauliZ):
|
106
145
|
"""Sample a classical outcome from the current 'quantum' state"""
|
107
146
|
if basis == Pauli.PauliZ:
|
@@ -404,6 +443,88 @@ class QrackAceBackend:
|
|
404
443
|
|
405
444
|
return qb, lhv
|
406
445
|
|
446
|
+
def get_lhv_bloch_angles(self, q):
|
447
|
+
z = (1 - q.bloch[2]) / 2
|
448
|
+
prob = z**2
|
449
|
+
x = (1 - q.bloch[0]) / 2
|
450
|
+
prob += x**2
|
451
|
+
y = (1 - q.bloch[1]) / 2
|
452
|
+
prob += y**2
|
453
|
+
|
454
|
+
prob = math.sqrt(prob)
|
455
|
+
inclination = math.atan2(math.sqrt(x**2 + y**2), z)
|
456
|
+
azimuth = math.atan2(y, x)
|
457
|
+
|
458
|
+
return prob, azimuth, inclination
|
459
|
+
|
460
|
+
def get_bloch_angles(self, hq):
|
461
|
+
sim = self.sim[hq[0]]
|
462
|
+
q = hq[1]
|
463
|
+
|
464
|
+
# Z axis
|
465
|
+
z = 1 - 2 * sim.prob(q)
|
466
|
+
prob = z**2
|
467
|
+
|
468
|
+
# X axis
|
469
|
+
sim.h(q)
|
470
|
+
x = 1 - 2 * sim.prob(q)
|
471
|
+
prob += x**2
|
472
|
+
sim.h(q)
|
473
|
+
|
474
|
+
# Y axis
|
475
|
+
sim.adjs(q)
|
476
|
+
sim.h(q)
|
477
|
+
y = 1 - 2 * sim.prob(q)
|
478
|
+
prob += y**2
|
479
|
+
sim.h(q)
|
480
|
+
sim.s(q)
|
481
|
+
|
482
|
+
prob = math.sqrt(prob)
|
483
|
+
inclination = math.atan2(math.sqrt(x**2 + y**2), z)
|
484
|
+
azimuth = math.atan2(y, x)
|
485
|
+
|
486
|
+
return prob, azimuth, inclination
|
487
|
+
|
488
|
+
def rotate_lhv_to_bloch(
|
489
|
+
self, q, azimuth_curr, inclination_curr, azimuth_target, inclination_target
|
490
|
+
):
|
491
|
+
delta_azimuth = azimuth_target - azimuth_curr
|
492
|
+
delta_inclination = inclination_target - inclination_curr
|
493
|
+
|
494
|
+
cosA = math.cos(delta_azimuth)
|
495
|
+
sinA = math.sin(delta_azimuth)
|
496
|
+
cosI = math.cos(delta_inclination / 2)
|
497
|
+
sinI = math.sin(delta_inclination / 2)
|
498
|
+
|
499
|
+
m00 = complex(cosI, 0)
|
500
|
+
m01 = complex(-cosA, sinA) * sinI
|
501
|
+
m10 = complex(cosA, sinA) * sinI
|
502
|
+
m11 = complex(cosI, 0)
|
503
|
+
|
504
|
+
q.mtrx([m00, m01, m10, m11])
|
505
|
+
|
506
|
+
def rotate_to_bloch(
|
507
|
+
self, hq, azimuth_curr, inclination_curr, azimuth_target, inclination_target
|
508
|
+
):
|
509
|
+
sim = self.sim[hq[0]]
|
510
|
+
q = hq[1]
|
511
|
+
|
512
|
+
delta_azimuth = azimuth_target - azimuth_curr
|
513
|
+
delta_inclination = inclination_target - inclination_curr
|
514
|
+
|
515
|
+
# Apply rotation as "Azimuth, Inclination" (AI)
|
516
|
+
cosA = math.cos(delta_azimuth)
|
517
|
+
sinA = math.sin(delta_azimuth)
|
518
|
+
cosI = math.cos(delta_inclination / 2)
|
519
|
+
sinI = math.sin(delta_inclination / 2)
|
520
|
+
|
521
|
+
m00 = complex(cosI, 0)
|
522
|
+
m01 = complex(-cosA, sinA) * sinI
|
523
|
+
m10 = complex(cosA, sinA) * sinI
|
524
|
+
m11 = complex(cosI, 0)
|
525
|
+
|
526
|
+
sim.mtrx([m00, m01, m10, m11], q)
|
527
|
+
|
407
528
|
def _correct(self, lq, phase=False):
|
408
529
|
hq = self._unpack(lq)
|
409
530
|
|
@@ -454,6 +575,28 @@ class QrackAceBackend:
|
|
454
575
|
hq[q].x()
|
455
576
|
else:
|
456
577
|
self.sim[hq[q][0]].x(hq[q][1])
|
578
|
+
|
579
|
+
p, a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
|
580
|
+
p[0], a[0], i[0] = self.get_bloch_angles(hq[0])
|
581
|
+
p[1], a[1], i[1] = self.get_bloch_angles(hq[1])
|
582
|
+
p[3], a[2], i[2] = self.get_bloch_angles(hq[3])
|
583
|
+
p[4], a[3], i[3] = self.get_bloch_angles(hq[4])
|
584
|
+
|
585
|
+
indices = []
|
586
|
+
a_target = 0
|
587
|
+
i_target = 0
|
588
|
+
for x in range(4):
|
589
|
+
if p[x] < 0.5:
|
590
|
+
continue
|
591
|
+
indices.append(x)
|
592
|
+
a_target += a[x]
|
593
|
+
i_target += i[x]
|
594
|
+
|
595
|
+
if len(indices) > 1:
|
596
|
+
a_target /= len(indices)
|
597
|
+
i_target /= len(indices)
|
598
|
+
for x in indices:
|
599
|
+
self.rotate_to_bloch(hq[x], a[x], i[x], a_target, i_target)
|
457
600
|
else:
|
458
601
|
# RMS
|
459
602
|
p = [
|
@@ -473,6 +616,26 @@ class QrackAceBackend:
|
|
473
616
|
else:
|
474
617
|
self.sim[hq[q][0]].x(hq[q][1])
|
475
618
|
|
619
|
+
p, a, i = [0, 0], [0, 0], [0, 0]
|
620
|
+
p[0], a[0], i[0] = self.get_bloch_angles(hq[0])
|
621
|
+
p[1], a[1], i[1] = self.get_bloch_angles(hq[1])
|
622
|
+
|
623
|
+
indices = []
|
624
|
+
a_target = 0
|
625
|
+
i_target = 0
|
626
|
+
for x in range(2):
|
627
|
+
if p[x] < 0.5:
|
628
|
+
continue
|
629
|
+
indices.append(x)
|
630
|
+
a_target += a[x]
|
631
|
+
i_target += i[x]
|
632
|
+
|
633
|
+
if len(indices) > 1:
|
634
|
+
a_target /= len(indices)
|
635
|
+
i_target /= len(indices)
|
636
|
+
for x in indices:
|
637
|
+
self.rotate_to_bloch(hq[x], a[x], i[x], a_target, i_target)
|
638
|
+
|
476
639
|
if phase:
|
477
640
|
for q in qb:
|
478
641
|
b = hq[q]
|
@@ -122,6 +122,9 @@ class QrackSimulator:
|
|
122
122
|
def _ulonglong_byref(self, a):
|
123
123
|
return (ctypes.c_ulonglong * len(a))(*a)
|
124
124
|
|
125
|
+
def _longlong_byref(self, a):
|
126
|
+
return (ctypes.c_longlong * len(a))(*a)
|
127
|
+
|
125
128
|
def _double_byref(self, a):
|
126
129
|
return (ctypes.c_double * len(a))(*a)
|
127
130
|
|
@@ -190,6 +193,11 @@ class QrackSimulator:
|
|
190
193
|
Qrack.qrack_lib.set_device(self.sid, d)
|
191
194
|
self._throw_if_error()
|
192
195
|
|
196
|
+
def set_device_list(self, d):
|
197
|
+
"""Set the GPU device ID"""
|
198
|
+
Qrack.qrack_lib.set_device_list(self.sid, len(d), self._longlong_byref(d))
|
199
|
+
self._throw_if_error()
|
200
|
+
|
193
201
|
def clone(self):
|
194
202
|
return QrackSimulator(cloneSid=self.sid)
|
195
203
|
|
@@ -144,7 +144,14 @@ class QrackSystem:
|
|
144
144
|
self.qrack_lib.set_concurrency.argtypes = [c_ulonglong, c_ulonglong]
|
145
145
|
|
146
146
|
self.qrack_lib.set_device.restype = None
|
147
|
-
self.qrack_lib.set_device.argtypes = [c_ulonglong,
|
147
|
+
self.qrack_lib.set_device.argtypes = [c_ulonglong, c_longlong]
|
148
|
+
|
149
|
+
self.qrack_lib.set_device_list.restype = None
|
150
|
+
self.qrack_lib.set_device_list.argtypes = [
|
151
|
+
c_ulonglong,
|
152
|
+
c_ulonglong,
|
153
|
+
POINTER(c_longlong),
|
154
|
+
]
|
148
155
|
|
149
156
|
# pseudo-quantum
|
150
157
|
|
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
|