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.
Files changed (29) hide show
  1. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/Makefile +1 -1
  2. {pyqrack_cuda-1.57.1/pyqrack_cuda.egg-info → pyqrack_cuda-1.58.5}/PKG-INFO +1 -1
  3. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_ace_backend.py +163 -0
  4. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_simulator.py +8 -0
  5. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_system/qrack_system.py +8 -1
  6. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
  7. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/setup.py +1 -1
  8. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/LICENSE +0 -0
  9. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/MANIFEST.in +0 -0
  10. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/README.md +0 -0
  11. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyproject.toml +0 -0
  12. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/__init__.py +0 -0
  13. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/neuron_activation_fn.py +0 -0
  14. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/pauli.py +0 -0
  15. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_circuit.py +0 -0
  16. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_neuron.py +0 -0
  17. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  18. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_stabilizer.py +0 -0
  19. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/qrack_system/__init__.py +0 -0
  20. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/quimb_circuit_type.py +0 -0
  21. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/stats/__init__.py +0 -0
  22. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/stats/load_quantized_data.py +0 -0
  23. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack/stats/quantize_by_range.py +0 -0
  24. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
  25. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
  26. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
  27. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/requires.txt +0 -0
  28. {pyqrack_cuda-1.57.1 → pyqrack_cuda-1.58.5}/pyqrack_cuda.egg-info/top_level.txt +0 -0
  29. {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 f0738286f49fb0ffaeb46d6e5d2294dbfc7f6138; cd ..
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cuda
3
- Version: 1.57.1
3
+ Version: 1.58.5
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -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, 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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cuda
3
- Version: 1.57.1
3
+ Version: 1.58.5
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -7,7 +7,7 @@ from setuptools import setup
7
7
  from setuptools.command.build_py import build_py
8
8
 
9
9
 
10
- VERSION = "1.57.1"
10
+ VERSION = "1.58.5"
11
11
 
12
12
  # Read long description from README.
13
13
  README_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'README.md')
File without changes
File without changes
File without changes
File without changes