pyqrack-cuda 1.58.0__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.58.0/pyqrack_cuda.egg-info → pyqrack_cuda-1.58.5}/PKG-INFO +1 -1
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/qrack_ace_backend.py +163 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/qrack_system/qrack_system.py +5 -1
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/setup.py +1 -1
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/LICENSE +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/MANIFEST.in +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/Makefile +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/README.md +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyproject.toml +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/__init__.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/qrack_simulator.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/requires.txt +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/top_level.txt +0 -0
- {pyqrack_cuda-1.58.0 → pyqrack_cuda-1.58.5}/setup.cfg +0 -0
@@ -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]
|
@@ -147,7 +147,11 @@ class QrackSystem:
|
|
147
147
|
self.qrack_lib.set_device.argtypes = [c_ulonglong, c_longlong]
|
148
148
|
|
149
149
|
self.qrack_lib.set_device_list.restype = None
|
150
|
-
self.qrack_lib.set_device_list.argtypes = [
|
150
|
+
self.qrack_lib.set_device_list.argtypes = [
|
151
|
+
c_ulonglong,
|
152
|
+
c_ulonglong,
|
153
|
+
POINTER(c_longlong),
|
154
|
+
]
|
151
155
|
|
152
156
|
# pseudo-quantum
|
153
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
|
File without changes
|
File without changes
|