pyqrack-cuda 1.50.1__tar.gz → 1.52.0__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.50.1 → pyqrack_cuda-1.52.0}/Makefile +1 -1
  2. {pyqrack_cuda-1.50.1/pyqrack_cuda.egg-info → pyqrack_cuda-1.52.0}/PKG-INFO +1 -1
  3. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_ace_backend.py +71 -65
  4. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_simulator.py +6 -0
  5. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_system/qrack_system.py +3 -0
  6. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
  7. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/setup.py +1 -1
  8. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/LICENSE +0 -0
  9. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/MANIFEST.in +0 -0
  10. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/README.md +0 -0
  11. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyproject.toml +0 -0
  12. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/__init__.py +0 -0
  13. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/neuron_activation_fn.py +0 -0
  14. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/pauli.py +0 -0
  15. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_circuit.py +0 -0
  16. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_neuron.py +0 -0
  17. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  18. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_stabilizer.py +0 -0
  19. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_system/__init__.py +0 -0
  20. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/quimb_circuit_type.py +0 -0
  21. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/stats/__init__.py +0 -0
  22. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/stats/load_quantized_data.py +0 -0
  23. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/stats/quantize_by_range.py +0 -0
  24. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
  25. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
  26. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
  27. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/requires.txt +0 -0
  28. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/top_level.txt +0 -0
  29. {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/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 065d4575ca82be0398ed726de59899c16500581f; cd ..
21
+ git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout f0738286f49fb0ffaeb46d6e5d2294dbfc7f6138; 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.50.1
3
+ Version: 1.52.0
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -35,12 +35,14 @@ class QrackAceBackend:
35
35
 
36
36
  The backend was originally designed assuming an (orbifolded) 2D qubit grid like 2019 Sycamore.
37
37
  However, it quickly became apparent that users can basically design their own connectivity topologies,
38
- without breaking the concept. (Not all will work equally well.) For maximum flexibility, set
39
- "alternating_codes=False". (For best performance on Sycamore-like topologies,leave it "True.")
38
+ without breaking the concept. (Not all will work equally well.)
39
+
40
+ Consider distributing the different "patches" to different GPUs with self.sim[sim_id].set_device(gpu_id)!
41
+ (If you have 3+ patches, maybe your discrete GPU can do multiple patches in the time it takes an Intel HD
42
+ to do one patch worth of work!)
40
43
 
41
44
  Attributes:
42
- sim(QrackSimulator): Corresponding simulator.
43
- alternating_codes(bool): Alternate repetition code elision by index?
45
+ sim(QrackSimulator): Array of simulators corresponding to "patches" between boundary rows.
44
46
  row_length(int): Qubits per row.
45
47
  col_length(int): Qubits per column.
46
48
  long_range_columns(int): How many ideal rows between QEC boundary rows?
@@ -50,7 +52,6 @@ class QrackAceBackend:
50
52
  self,
51
53
  qubit_count=1,
52
54
  long_range_columns=-1,
53
- alternating_codes=True,
54
55
  reverse_row_and_col=False,
55
56
  isTensorNetwork=False,
56
57
  isStabilizerHybrid=False,
@@ -68,7 +69,6 @@ class QrackAceBackend:
68
69
  long_range_columns = 3 if (self.row_length % 3) == 1 else 2
69
70
  self.long_range_columns = long_range_columns
70
71
 
71
- self.alternating_codes = alternating_codes
72
72
  self._coupling_map = None
73
73
 
74
74
  # If there's only one or zero "False" columns,
@@ -96,24 +96,24 @@ class QrackAceBackend:
96
96
  self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
97
97
  tot_qubits += 1
98
98
  sim_counts[sim_id] += 1
99
- elif not self.alternating_codes or not (r & 1):
100
- self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
101
- tot_qubits += 1
102
- sim_counts[sim_id] += 1
103
- sim_id = (sim_id + 1) % sim_count
99
+ elif (r & 1):
104
100
  for _ in range(2):
105
101
  self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
106
102
  tot_qubits += 1
107
103
  sim_counts[sim_id] += 1
104
+ sim_id = (sim_id + 1) % sim_count
105
+ self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
106
+ tot_qubits += 1
107
+ sim_counts[sim_id] += 1
108
108
  else:
109
+ self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
110
+ tot_qubits += 1
111
+ sim_counts[sim_id] += 1
112
+ sim_id = (sim_id + 1) % sim_count
109
113
  for _ in range(2):
110
114
  self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
111
115
  tot_qubits += 1
112
116
  sim_counts[sim_id] += 1
113
- sim_id = (sim_id + 1) % sim_count
114
- self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
115
- tot_qubits += 1
116
- sim_counts[sim_id] += 1
117
117
 
118
118
  self.sim = []
119
119
  for i in range(sim_count):
@@ -230,6 +230,16 @@ class QrackAceBackend:
230
230
  b2 = hq[2]
231
231
  self.sim[b2[0]].mcx([b2[1]], hq[1][1])
232
232
 
233
+ def _encode_decode_half(self, lq, hq, toward_0):
234
+ if len(hq) < 2:
235
+ return
236
+ if toward_0 and (hq[0][0] == hq[1][0]):
237
+ b0 = hq[0]
238
+ self.sim[b0[0]].mcx([b0[1]], hq[1][1])
239
+ elif not toward_0 and (hq[2][0] == hq[1][0]):
240
+ b2 = hq[2]
241
+ self.sim[b2[0]].mcx([b2[1]], hq[1][1])
242
+
233
243
  def _correct(self, lq):
234
244
  if self._is_col_long_range[lq % self.row_length]:
235
245
  return
@@ -258,9 +268,9 @@ class QrackAceBackend:
258
268
 
259
269
  # Suggestion from Elara (the custom OpenAI GPT):
260
270
  # Create phase parity tie before measurement.
261
- # self._ccx_shadow(hq[single_bit], hq[other_bits[0]], [ancilla_sim, ancilla])
262
- # self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
263
- # self.sim[ancilla_sim].force_m(ancilla, False)
271
+ self._ccx_shadow(hq[single_bit], hq[other_bits[0]], [ancilla_sim, ancilla])
272
+ self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
273
+ self.sim[ancilla_sim].force_m(ancilla, False)
264
274
 
265
275
  samples = self.sim[ancilla_sim].measure_shots(
266
276
  [hq[other_bits[0]][1], hq[other_bits[1]][1]], shots
@@ -363,13 +373,13 @@ class QrackAceBackend:
363
373
 
364
374
  if not math.isclose(ph, -lm) and not math.isclose(abs(ph), math.pi / 2):
365
375
  # Produces/destroys superposition
366
- self._correct_if_like_h(th, lq)
367
376
  self._encode_decode(lq, hq)
368
377
  b = hq[0]
369
378
  self.sim[b[0]].u(b[1], th, ph, lm)
370
379
  b = hq[2]
371
380
  self.sim[b[0]].u(b[1], th, ph, lm)
372
381
  self._encode_decode(lq, hq)
382
+ self._correct_if_like_h(th, lq)
373
383
  else:
374
384
  # Shouldn't produce/destroy superposition
375
385
  for b in hq:
@@ -386,9 +396,6 @@ class QrackAceBackend:
386
396
  th -= 2 * math.pi
387
397
  while th <= -math.pi:
388
398
  th += 2 * math.pi
389
- if p == Pauli.PauliY:
390
- self._correct_if_like_h(th, lq)
391
-
392
399
  if (p == Pauli.PauliZ) or math.isclose(abs(th), math.pi):
393
400
  # Doesn't produce/destroy superposition
394
401
  for b in hq:
@@ -401,6 +408,7 @@ class QrackAceBackend:
401
408
  b = hq[2]
402
409
  self.sim[b[0]].r(p, th, b[1])
403
410
  self._encode_decode(lq, hq)
411
+ self._correct_if_like_h(th, lq)
404
412
 
405
413
  def h(self, lq):
406
414
  hq = self._unpack(lq)
@@ -409,13 +417,13 @@ class QrackAceBackend:
409
417
  self.sim[b[0]].h(b[1])
410
418
  return
411
419
 
412
- self._correct(lq)
413
420
  self._encode_decode(lq, hq)
414
421
  b = hq[0]
415
422
  self.sim[b[0]].h(b[1])
416
423
  b = hq[2]
417
424
  self.sim[b[0]].h(b[1])
418
425
  self._encode_decode(lq, hq)
426
+ self._correct(lq)
419
427
 
420
428
  def s(self, lq):
421
429
  hq = self._unpack(lq)
@@ -547,13 +555,10 @@ class QrackAceBackend:
547
555
  shadow(b1, b2)
548
556
  return
549
557
 
550
- self._correct(lq1)
551
- self._correct(lq2)
552
-
553
558
  if (lq2_col in connected_cols) and (connected_cols.index(lq2_col) < boundary):
554
559
  # lq2_col < lq1_col
555
- self._encode_decode(lq1, hq1)
556
- self._encode_decode(lq2, hq2)
560
+ self._encode_decode_half(lq1, hq1, True)
561
+ self._encode_decode_half(lq2, hq2, False)
557
562
  b = hq1[0]
558
563
  if lq1_lr:
559
564
  self._get_gate(pauli, anti, hq1[0][0])[0]([b[1]], hq2[2][1])
@@ -561,12 +566,12 @@ class QrackAceBackend:
561
566
  self._get_gate(pauli, anti, hq2[0][0])[0]([b[1]], hq2[0][1])
562
567
  else:
563
568
  self._get_gate(pauli, anti, b[0])[0]([b[1]], hq2[2][1])
564
- self._encode_decode(lq2, hq2)
565
- self._encode_decode(lq1, hq1)
569
+ self._encode_decode_half(lq2, hq2, False)
570
+ self._encode_decode_half(lq1, hq1, True)
566
571
  elif lq2_col in connected_cols:
567
572
  # lq1_col < lq2_col
568
- self._encode_decode(lq1, hq1)
569
- self._encode_decode(lq2, hq2)
573
+ self._encode_decode_half(lq1, hq1, False)
574
+ self._encode_decode_half(lq2, hq2, True)
570
575
  b = hq2[0]
571
576
  if lq1_lr:
572
577
  self._get_gate(pauli, anti, hq1[0][0])[0]([hq1[0][1]], b[1])
@@ -574,37 +579,41 @@ class QrackAceBackend:
574
579
  self._get_gate(pauli, anti, hq2[0][0])[0]([hq1[2][1]], b[1])
575
580
  else:
576
581
  self._get_gate(pauli, anti, b[0])[0]([hq1[2][1]], b[1])
577
- self._encode_decode(lq2, hq2)
578
- self._encode_decode(lq1, hq1)
582
+ self._encode_decode_half(lq2, hq2, True)
583
+ self._encode_decode_half(lq1, hq1, False)
579
584
  elif lq1_col == lq2_col:
580
585
  # Both are in the same boundary column.
586
+ self._encode_decode(lq1, hq1)
587
+ self._encode_decode(lq2, hq2)
581
588
  b = hq1[0]
582
589
  gate, shadow = self._get_gate(pauli, anti, b[0])
583
590
  gate([b[1]], hq2[0][1])
584
591
  b = hq1[2]
585
592
  gate, shadow = self._get_gate(pauli, anti, b[0])
586
593
  gate([b[1]], hq2[2][1])
587
- if hq1[1][0] != hq2[1][0]:
588
- shadow(hq1[1], hq2[1])
589
- else:
590
- b = hq1[1]
591
- gate, shadow = self._get_gate(pauli, anti, b[0])
592
- gate([b[1]], hq2[1][1])
593
594
  else:
594
595
  # The qubits have no quantum connection.
595
596
  gate, shadow = self._get_gate(pauli, anti, hq1[0][0])
596
597
  if lq1_lr:
598
+ connected01 = (hq2[0][0] == hq2[1][0])
597
599
  self._encode_decode(lq2, hq2)
598
- shadow(hq1[0], hq2[0])
600
+ shadow(hq1[0], hq2[0] if connected01 else hq2[2])
599
601
  self._encode_decode(lq2, hq2)
600
602
  elif lq2_lr:
603
+ connected01 = (hq1[0][0] == hq1[1][0])
601
604
  self._encode_decode(lq1, hq1)
602
- shadow(hq1[0], hq2[0])
605
+ shadow(hq1[0] if connected01 else hq1[2], hq2[0])
603
606
  self._encode_decode(lq1, hq1)
604
607
  else:
608
+ self._encode_decode(lq1, hq1)
609
+ self._encode_decode(lq2, hq2)
605
610
  shadow(hq1[0], hq2[0])
606
- shadow(hq1[1], hq2[1])
607
611
  shadow(hq1[2], hq2[2])
612
+ self._encode_decode(lq2, hq2)
613
+ self._encode_decode(lq1, hq1)
614
+
615
+ self._correct(lq1)
616
+ self._correct(lq2)
608
617
 
609
618
  def cx(self, lq1, lq2):
610
619
  self._cpauli(lq1, lq2, False, Pauli.PauliX)
@@ -725,16 +734,23 @@ class QrackAceBackend:
725
734
  result = 0
726
735
  # Randomize the order of measurement to amortize error.
727
736
  # However, locality of collapse matters:
728
- # always measure across rows, and by row directionality.
729
- rows = list(range(self.col_length))
730
- random.shuffle(rows)
731
- for lq_row in rows:
737
+ # measure in row pairs, and always across rows,
738
+ # and by row directionality.
739
+ row_pairs = list(range((self.col_length + 1) // 2))
740
+ random.shuffle(row_pairs)
741
+ for row_pair in row_pairs:
732
742
  col_offset = random.randint(0, self.row_length - 1)
733
- col_reverse = self.alternating_codes and (lq_row & 1)
743
+ lq_row = row_pair << 1
744
+ for c in range(self.row_length):
745
+ lq_col = (c + col_offset) % self.row_length
746
+ lq = lq_row * self.row_length + lq_col
747
+ if self.m(lq):
748
+ result |= 1 << lq
749
+ lq_row += 1
750
+ if lq_row == self.col_length:
751
+ continue
734
752
  for c in range(self.row_length):
735
- lq_col = (
736
- ((self.row_length - (c + 1)) if col_reverse else c) + col_offset
737
- ) % self.row_length
753
+ lq_col = ((self.row_length - (c + 1)) + col_offset) % self.row_length
738
754
  lq = lq_row * self.row_length + lq_col
739
755
  if self.m(lq):
740
756
  result |= 1 << lq
@@ -761,7 +777,7 @@ class QrackAceBackend:
761
777
  return self.sim[b[0]].prob(b[1])
762
778
 
763
779
  self._correct(lq)
764
- if not self.alternating_codes or not ((lq // self.row_length) & 1):
780
+ if hq[0][0] == hq[1][0]:
765
781
  other_bits = [0, 1]
766
782
  else:
767
783
  other_bits = [1, 2]
@@ -1171,21 +1187,11 @@ class QrackAceBackend:
1171
1187
  continue # No noise on long-to-long
1172
1188
 
1173
1189
  same_col = col_a == col_b
1174
- even_odd = (row_a % 2) != (row_b % 2)
1175
-
1176
- if same_col and not even_odd:
1177
- continue # No noise for even-even or odd-odd within a boundary column
1178
1190
 
1179
1191
  if same_col:
1180
- x_cy = 1 - (1 - x) ** 2
1181
- x_swap = 1 - (1 - x) ** 3
1182
- noise_model.add_quantum_error(depolarizing_error(x, 2), "cx", [a, b])
1183
- noise_model.add_quantum_error(depolarizing_error(x_cy, 2), "cy", [a, b])
1184
- noise_model.add_quantum_error(depolarizing_error(x_cy, 2), "cz", [a, b])
1185
- noise_model.add_quantum_error(
1186
- depolarizing_error(x_swap, 2), "swap", [a, b]
1187
- )
1188
- elif is_long_a or is_long_b:
1192
+ continue # No noise for same column
1193
+
1194
+ if is_long_a or is_long_b:
1189
1195
  y_cy = 1 - (1 - y) ** 2
1190
1196
  y_swap = 1 - (1 - y) ** 3
1191
1197
  noise_model.add_quantum_error(depolarizing_error(y, 2), "cx", [a, b])
@@ -181,9 +181,15 @@ class QrackSimulator:
181
181
  self._throw_if_error()
182
182
 
183
183
  def set_concurrency(self, p):
184
+ """ Set the CPU parallel thread count"""
184
185
  Qrack.qrack_lib.set_concurrency(self.sid, p)
185
186
  self._throw_if_error()
186
187
 
188
+ def set_device(self, d):
189
+ """ Set the GPU device ID"""
190
+ Qrack.qrack_lib.set_device(self.sid, d)
191
+ self._throw_if_error()
192
+
187
193
  def clone(self):
188
194
  return QrackSimulator(cloneSid=self.sid)
189
195
 
@@ -143,6 +143,9 @@ class QrackSystem:
143
143
  self.qrack_lib.set_concurrency.restype = None
144
144
  self.qrack_lib.set_concurrency.argtypes = [c_ulonglong, c_ulonglong]
145
145
 
146
+ self.qrack_lib.set_device.restype = None
147
+ self.qrack_lib.set_device.argtypes = [c_ulonglong, c_ulonglong]
148
+
146
149
  # pseudo-quantum
147
150
 
148
151
  self.qrack_lib.ProbAll.restype = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cuda
3
- Version: 1.50.1
3
+ Version: 1.52.0
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.50.1"
10
+ VERSION = "1.52.0"
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