pyqrack-cuda 1.46.7__tar.gz → 1.47.1__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.46.7/pyqrack_cuda.egg-info → pyqrack_cuda-1.47.1}/PKG-INFO +1 -1
  2. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/qrack_ace_backend.py +223 -93
  3. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
  4. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/setup.py +1 -1
  5. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/LICENSE +0 -0
  6. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/MANIFEST.in +0 -0
  7. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/Makefile +0 -0
  8. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/README.md +0 -0
  9. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyproject.toml +0 -0
  10. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/__init__.py +0 -0
  11. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/neuron_activation_fn.py +0 -0
  12. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/pauli.py +0 -0
  13. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/qrack_circuit.py +0 -0
  14. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/qrack_neuron.py +0 -0
  15. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  16. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/qrack_simulator.py +0 -0
  17. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/qrack_stabilizer.py +0 -0
  18. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/qrack_system/__init__.py +0 -0
  19. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/qrack_system/qrack_system.py +0 -0
  20. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/quimb_circuit_type.py +0 -0
  21. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/stats/__init__.py +0 -0
  22. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/stats/load_quantized_data.py +0 -0
  23. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack/stats/quantize_by_range.py +0 -0
  24. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
  25. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
  26. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
  27. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack_cuda.egg-info/requires.txt +0 -0
  28. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/pyqrack_cuda.egg-info/top_level.txt +0 -0
  29. {pyqrack_cuda-1.46.7 → pyqrack_cuda-1.47.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cuda
3
- Version: 1.46.7
3
+ Version: 1.47.1
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -34,6 +34,7 @@ class QrackAceBackend:
34
34
  Attributes:
35
35
  sim(QrackSimulator): Corresponding simulator.
36
36
  alternating_codes(bool): Alternate repetition code elision by index?
37
+ recursive_stack_depth(int): How many recursive nestings?
37
38
  row_length(int): Qubits per row.
38
39
  col_length(int): Qubits per column.
39
40
  """
@@ -41,29 +42,56 @@ class QrackAceBackend:
41
42
  def __init__(
42
43
  self,
43
44
  qubit_count=1,
45
+ long_range_rows=0,
44
46
  recursive_stack_depth=1,
45
47
  alternating_codes=True,
48
+ reverse_row_and_col=False,
46
49
  isTensorNetwork=False,
47
50
  isStabilizerHybrid=False,
48
51
  isBinaryDecisionTree=False,
49
52
  toClone=None,
50
53
  ):
54
+ if long_range_rows < 0:
55
+ long_range_rows = 0
56
+ if qubit_count < 0:
57
+ qubit_count = 0
51
58
  if toClone:
52
59
  qubit_count = toClone.num_qubits()
53
60
  recursive_stack_depth = toClone.recursive_stack_depth
54
61
  if recursive_stack_depth < 1:
55
62
  recursive_stack_depth = 1
63
+
56
64
  self.recursive_stack_depth = recursive_stack_depth
57
- self._ancilla = 3 * qubit_count
58
- self._factor_width(qubit_count)
65
+ self._factor_width(qubit_count, reverse_row_and_col)
59
66
  self.alternating_codes = alternating_codes
60
67
  self._is_init = [False] * qubit_count
68
+
69
+ col_seq = [False] + [True] * long_range_rows
70
+ len_col_seq = len(col_seq)
71
+ self._is_col_long_range = (col_seq * ((self.row_length + len_col_seq - 1) // len_col_seq))[:self.row_length]
72
+ self._hardware_offset = []
73
+ tot_qubits = 0
74
+ for _ in range(self.col_length):
75
+ for c in self._is_col_long_range:
76
+ self._hardware_offset.append(tot_qubits)
77
+ tot_qubits += 1 if c else 3
78
+ self._ancilla = tot_qubits
79
+ tot_qubits += 1
80
+
61
81
  if recursive_stack_depth > 1:
62
82
  recursive_stack_depth -= 1
63
83
  self.sim = (
64
84
  toClone.sim
65
85
  if toClone
66
- else QrackAceBackend(3 * qubit_count + 1, recursive_stack_depth=recursive_stack_depth, alternating_codes=alternating_codes, isTensorNetwork=isTensorNetwork, isStabilizerHybrid=isStabilizerHybrid, isBinaryDecisionTree=isBinaryDecisionTree)
86
+ else QrackAceBackend(
87
+ tot_qubits,
88
+ recursive_stack_depth,
89
+ alternating_codes,
90
+ reverse_row_and_col,
91
+ isTensorNetwork,
92
+ isStabilizerHybrid,
93
+ isBinaryDecisionTree,
94
+ )
67
95
  )
68
96
  # This leaves an "odd-man-out" ancillary qubit.
69
97
  self.sim.row_length = 3 * self.row_length
@@ -72,23 +100,28 @@ class QrackAceBackend:
72
100
  self.sim = (
73
101
  toClone.sim.clone()
74
102
  if toClone
75
- else QrackSimulator(3 * qubit_count + 1, isTensorNetwork=isTensorNetwork, isStabilizerHybrid=isStabilizerHybrid, isBinaryDecisionTree=isBinaryDecisionTree)
103
+ else QrackSimulator(
104
+ tot_qubits,
105
+ isTensorNetwork=isTensorNetwork,
106
+ isStabilizerHybrid=isStabilizerHybrid,
107
+ isBinaryDecisionTree=isBinaryDecisionTree,
108
+ )
76
109
  )
77
110
 
78
111
  def clone(self):
79
112
  return QrackAceBackend(toClone=self)
80
113
 
81
114
  def num_qubits(self):
82
- return self.sim.num_qubits() // 3
115
+ return self.row_length * self.col_length
83
116
 
84
- def _factor_width(self, width):
117
+ def _factor_width(self, width, reverse=False):
85
118
  col_len = math.floor(math.sqrt(width))
86
119
  while ((width // col_len) * col_len) != width:
87
120
  col_len -= 1
88
121
  row_len = width // col_len
89
122
 
90
- self.col_length = col_len
91
- self.row_length = row_len
123
+ self.col_length = row_len if reverse else col_len
124
+ self.row_length = col_len if reverse else row_len
92
125
 
93
126
  def _ct_pair_prob(self, q1, q2):
94
127
  p1 = self.sim.prob(q1)
@@ -130,14 +163,18 @@ class QrackAceBackend:
130
163
  self.sim.x(t)
131
164
 
132
165
  def _unpack(self, lq, reverse=False):
166
+ offset = self._hardware_offset[lq]
167
+
168
+ if self._is_col_long_range[lq % self.row_length]:
169
+ return [offset]
170
+
133
171
  return (
134
- [3 * lq + 2, 3 * lq + 1, 3 * lq]
172
+ [offset + 2, offset + 1, offset]
135
173
  if reverse
136
- else [3 * lq, 3 * lq + 1, 3 * lq + 2]
174
+ else [offset, offset + 1, offset + 2]
137
175
  )
138
176
 
139
- def _encode(self, hq, reverse=False):
140
- lq = hq[0] // 3
177
+ def _encode(self, lq, hq, reverse=False):
141
178
  even_row = not ((lq // self.row_length) & 1)
142
179
  # Encode shadow-first
143
180
  if self._is_init[lq]:
@@ -148,8 +185,7 @@ class QrackAceBackend:
148
185
  self.sim.mcx([hq[0]], hq[1])
149
186
  self._is_init[lq] = True
150
187
 
151
- def _decode(self, hq, reverse=False):
152
- lq = hq[0] // 3
188
+ def _decode(self, lq, hq, reverse=False):
153
189
  if not self._is_init[lq]:
154
190
  return
155
191
  even_row = not ((lq // self.row_length) & 1)
@@ -266,6 +302,11 @@ class QrackAceBackend:
266
302
  self._correct(lq)
267
303
 
268
304
  def u(self, lq, th, ph, lm):
305
+ hq = self._unpack(lq)
306
+ if self._is_col_long_range[lq % self.row_length]:
307
+ self.sim.u(hq[0], th, ph, lm)
308
+ return
309
+
269
310
  while ph > math.pi:
270
311
  ph -= 2 * math.pi
271
312
  while ph <= -math.pi:
@@ -274,85 +315,121 @@ class QrackAceBackend:
274
315
  lm -= 2 * math.pi
275
316
  while lm <= -math.pi:
276
317
  lm += 2 * math.pi
277
- hq = self._unpack(lq)
318
+
278
319
  if not math.isclose(ph, -lm) and not math.isclose(abs(ph), math.pi / 2):
279
320
  # Produces/destroys superposition
280
321
  self._correct_if_like_h(th, lq)
281
- self._decode(hq)
322
+ self._decode(lq, hq)
282
323
  self.sim.u(hq[0], th, ph, lm)
283
324
  if not self._is_init[lq]:
284
325
  self.sim.u(hq[2], th, ph, lm)
285
- self._encode(hq)
326
+ self._encode(lq, hq)
286
327
  else:
287
328
  # Shouldn't produce/destroy superposition
288
329
  for b in hq:
289
330
  self.sim.u(b, th, ph, lm)
290
331
 
291
332
  def r(self, p, th, lq):
333
+ hq = self._unpack(lq)
334
+ if self._is_col_long_range[lq % self.row_length]:
335
+ self.sim.r(p, th, hq[0])
336
+ return
337
+
292
338
  while th > math.pi:
293
339
  th -= 2 * math.pi
294
340
  while th <= -math.pi:
295
341
  th += 2 * math.pi
296
342
  if p == Pauli.PauliY:
297
343
  self._correct_if_like_h(th, lq)
298
- hq = self._unpack(lq)
344
+
299
345
  if (p == Pauli.PauliZ) or math.isclose(abs(th), math.pi):
300
346
  # Doesn't produce/destroy superposition
301
347
  for b in hq:
302
348
  self.sim.r(p, th, b)
303
349
  else:
304
350
  # Produces/destroys superposition
305
- self._decode(hq)
351
+ self._decode(lq, hq)
306
352
  self.sim.r(p, th, hq[0])
307
353
  if not self._is_init[lq]:
308
354
  self.sim.r(p, th, hq[2])
309
- self._encode(hq)
355
+ self._encode(lq, hq)
310
356
 
311
357
  def h(self, lq):
312
358
  hq = self._unpack(lq)
313
- self._decode(hq)
359
+ if self._is_col_long_range[lq % self.row_length]:
360
+ self.sim.h(hq[0])
361
+ return
362
+
363
+ self._decode(lq, hq)
314
364
  self.sim.h(hq[0])
315
365
  if not self._is_init[lq]:
316
366
  self.sim.h(hq[2])
317
- self._encode(hq)
367
+ self._encode(lq, hq)
318
368
 
319
369
  def s(self, lq):
320
370
  hq = self._unpack(lq)
371
+ if self._is_col_long_range[lq % self.row_length]:
372
+ self.sim.s(hq[0])
373
+ return
374
+
321
375
  for b in hq:
322
376
  self.sim.s(b)
323
377
 
324
378
  def adjs(self, lq):
325
379
  hq = self._unpack(lq)
380
+ if self._is_col_long_range[lq % self.row_length]:
381
+ self.sim.adjs(hq[0])
382
+ return
383
+
326
384
  for b in hq:
327
385
  self.sim.adjs(b)
328
386
 
329
387
  def x(self, lq):
330
388
  hq = self._unpack(lq)
389
+ if self._is_col_long_range[lq % self.row_length]:
390
+ self.sim.x(hq[0])
391
+ return
392
+
331
393
  for b in hq:
332
394
  self.sim.x(b)
333
395
 
334
396
  def y(self, lq):
335
397
  hq = self._unpack(lq)
398
+ if self._is_col_long_range[lq % self.row_length]:
399
+ self.sim.y(hq[0])
400
+ return
401
+
336
402
  for b in hq:
337
403
  self.sim.y(b)
338
404
 
339
405
  def z(self, lq):
340
406
  hq = self._unpack(lq)
407
+ if self._is_col_long_range[lq % self.row_length]:
408
+ self.sim.z(hq[0])
409
+ return
410
+
341
411
  for b in hq:
342
412
  self.sim.z(b)
343
413
 
344
414
  def t(self, lq):
345
415
  hq = self._unpack(lq)
416
+ if self._is_col_long_range[lq % self.row_length]:
417
+ self.sim.t(hq[0])
418
+ return
419
+
346
420
  for b in hq:
347
421
  self.sim.t(b)
348
422
 
349
423
  def adjt(self, lq):
350
424
  hq = self._unpack(lq)
425
+ if self._is_col_long_range[lq % self.row_length]:
426
+ self.sim.adjt(hq[0])
427
+ return
428
+
351
429
  for b in hq:
352
430
  self.sim.adjt(b)
353
431
 
354
432
  def _cpauli(self, lq1, lq2, anti, pauli):
355
- self._correct(lq1)
356
433
  gate = None
357
434
  shadow = None
358
435
  if pauli == Pauli.PauliX:
@@ -367,12 +444,29 @@ class QrackAceBackend:
367
444
  else:
368
445
  return
369
446
 
447
+ lq1_lr = self._is_col_long_range[lq1 % self.row_length]
448
+ lq2_lr = self._is_col_long_range[lq2 % self.row_length]
449
+ if lq1_lr and lq2_lr:
450
+ gate(self._unpack(lq1), self._unpack(lq2)[0])
451
+ return
452
+
453
+ self._correct(lq1)
454
+
370
455
  if not self._is_init[lq1]:
371
456
  hq1 = self._unpack(lq1)
372
457
  hq2 = self._unpack(lq2)
373
- gate([hq1[0]], hq2[0])
374
- gate([hq1[1]], hq2[1])
375
- gate([hq1[2]], hq2[2])
458
+ if lq1_lr:
459
+ self._decode(lq2, hq2)
460
+ gate(hq1, hq2[0])
461
+ self._encode(lq2, hq2)
462
+ elif lq1_lr:
463
+ self._decode(lq1, hq1)
464
+ gate([hq1[0]], hq2[0])
465
+ self._encode(lq1, hq1)
466
+ else:
467
+ gate([hq1[0]], hq2[0])
468
+ gate([hq1[1]], hq2[1])
469
+ gate([hq1[2]], hq2[2])
376
470
 
377
471
  return
378
472
 
@@ -384,32 +478,70 @@ class QrackAceBackend:
384
478
  hq1 = None
385
479
  hq2 = None
386
480
  if (lq2_row == lq1_row) and (((lq1_col + 1) % self.row_length) == lq2_col):
387
- self._correct(lq2)
388
- hq1 = self._unpack(lq1, True)
389
- hq2 = self._unpack(lq2, False)
390
- self._decode(hq1, True)
391
- self._decode(hq2, False)
392
- gate([hq1[0]], hq2[0])
393
- self._encode(hq2, False)
394
- self._encode(hq1, True)
481
+ if lq1_lr:
482
+ self._correct(lq2)
483
+ hq1 = self._unpack(lq1)
484
+ hq2 = self._unpack(lq2, False)
485
+ self._decode(lq2, hq2, False)
486
+ gate(hq1, hq2[0])
487
+ self._encode(lq2, hq2, False)
488
+ elif lq2_lr:
489
+ hq1 = self._unpack(lq1, True)
490
+ hq2 = self._unpack(lq2)
491
+ self._decode(lq1, hq1, True)
492
+ gate([hq1[0]], hq2[0])
493
+ self._encode(lq1, hq1, True)
494
+ else:
495
+ self._correct(lq2)
496
+ hq1 = self._unpack(lq1, True)
497
+ hq2 = self._unpack(lq2, False)
498
+ self._decode(lq1, hq1, True)
499
+ self._decode(lq2, hq2, False)
500
+ gate([hq1[0]], hq2[0])
501
+ self._encode(lq2, hq2, False)
502
+ self._encode(lq1, hq1, True)
395
503
  elif (lq1_row == lq2_row) and (((lq2_col + 1) % self.row_length) == lq1_col):
396
- self._correct(lq2)
397
- hq2 = self._unpack(lq2, True)
398
- hq1 = self._unpack(lq1, False)
399
- self._decode(hq2, True)
400
- self._decode(hq1, False)
401
- gate([hq1[0]], hq2[0])
402
- self._encode(hq1, False)
403
- self._encode(hq2, True)
504
+ if lq1_lr:
505
+ self._correct(lq2)
506
+ hq2 = self._unpack(lq2, True)
507
+ hq1 = self._unpack(lq1)
508
+ self._decode(lq2, hq2, True)
509
+ gate(hq1, hq2[0])
510
+ self._encode(lq2, hq2, True)
511
+ elif lq2_lr:
512
+ hq2 = self._unpack(lq2)
513
+ hq1 = self._unpack(lq1, False)
514
+ self._decode(lq1, hq1, False)
515
+ gate([hq1[0]], hq2[0])
516
+ self._encode(lq1, hq1, False)
517
+ else:
518
+ self._correct(lq2)
519
+ hq2 = self._unpack(lq2, True)
520
+ hq1 = self._unpack(lq1, False)
521
+ self._decode(lq2, hq2, True)
522
+ self._decode(lq1, hq1, False)
523
+ gate([hq1[0]], hq2[0])
524
+ self._encode(lq1, hq1, False)
525
+ self._encode(lq2, hq2, True)
404
526
  else:
405
527
  hq1 = self._unpack(lq1)
406
528
  hq2 = self._unpack(lq2)
407
- gate([hq1[0]], hq2[0])
408
- if self.alternating_codes and ((lq2_row & 1) != (lq1_row & 1)):
409
- shadow(hq1[1], hq2[1])
529
+ if lq1_lr:
530
+ self._correct(lq2)
531
+ self._decode(lq2, hq2)
532
+ gate(hq1, hq2[0])
533
+ self._encode(lq2, hq2)
534
+ elif lq2_lr:
535
+ self._decode(lq1, hq1)
536
+ gate([hq1[0]], hq2[0])
537
+ self._encode(lq1, hq1)
410
538
  else:
411
- gate([hq1[1]], hq2[1])
412
- gate([hq1[2]], hq2[2])
539
+ gate([hq1[0]], hq2[0])
540
+ if self.alternating_codes and ((lq2_row & 1) != (lq1_row & 1)):
541
+ shadow(hq1[1], hq2[1])
542
+ else:
543
+ gate([hq1[1]], hq2[1])
544
+ gate([hq1[2]], hq2[2])
413
545
 
414
546
  def cx(self, lq1, lq2):
415
547
  self._cpauli(lq1, lq2, False, Pauli.PauliX)
@@ -431,32 +563,44 @@ class QrackAceBackend:
431
563
 
432
564
  def mcx(self, lq1, lq2):
433
565
  if len(lq1) > 1:
434
- raise RuntimeError("QrackAceBackend.mcx() is provided for syntax convenience and only supports 1 control qubit!")
566
+ raise RuntimeError(
567
+ "QrackAceBackend.mcx() is provided for syntax convenience and only supports 1 control qubit!"
568
+ )
435
569
  self._cpauli(lq1[0], lq2, False, Pauli.PauliX)
436
570
 
437
571
  def mcy(self, lq1, lq2):
438
572
  if len(lq1) > 1:
439
- raise RuntimeError("QrackAceBackend.mcy() is provided for syntax convenience and only supports 1 control qubit!")
573
+ raise RuntimeError(
574
+ "QrackAceBackend.mcy() is provided for syntax convenience and only supports 1 control qubit!"
575
+ )
440
576
  self._cpauli(lq1[0], lq2, False, Pauli.PauliY)
441
577
 
442
578
  def mcz(self, lq1, lq2):
443
579
  if len(lq1) > 1:
444
- raise RuntimeError("QrackAceBackend.mcz() is provided for syntax convenience and only supports 1 control qubit!")
580
+ raise RuntimeError(
581
+ "QrackAceBackend.mcz() is provided for syntax convenience and only supports 1 control qubit!"
582
+ )
445
583
  self._cpauli(lq1[0], lq2, False, Pauli.PauliZ)
446
584
 
447
585
  def macx(self, lq1, lq2):
448
586
  if len(lq1) > 1:
449
- raise RuntimeError("QrackAceBackend.macx() is provided for syntax convenience and only supports 1 control qubit!")
587
+ raise RuntimeError(
588
+ "QrackAceBackend.macx() is provided for syntax convenience and only supports 1 control qubit!"
589
+ )
450
590
  self._cpauli(lq1[0], lq2, True, Pauli.PauliX)
451
591
 
452
592
  def macy(self, lq1, lq2):
453
593
  if len(lq1) > 1:
454
- raise RuntimeError("QrackAceBackend.macy() is provided for syntax convenience and only supports 1 control qubit!")
594
+ raise RuntimeError(
595
+ "QrackAceBackend.macy() is provided for syntax convenience and only supports 1 control qubit!"
596
+ )
455
597
  self._cpauli(lq1[0], lq2, True, Pauli.PauliY)
456
598
 
457
599
  def macz(self, lq1, lq2):
458
600
  if len(lq1) > 1:
459
- raise RuntimeError("QrackAceBackend.macz() is provided for syntax convenience and only supports 1 control qubit!")
601
+ raise RuntimeError(
602
+ "QrackAceBackend.macz() is provided for syntax convenience and only supports 1 control qubit!"
603
+ )
460
604
  self._cpauli(lq1[0], lq2, True, Pauli.PauliZ)
461
605
 
462
606
  def swap(self, lq1, lq2):
@@ -477,7 +621,11 @@ class QrackAceBackend:
477
621
  self.swap(lq1, lq2)
478
622
 
479
623
  def m(self, lq):
624
+ self._is_init[lq] = False
480
625
  hq = self._unpack(lq)
626
+ if self._is_col_long_range[lq % self.row_length]:
627
+ return self.sim.m(hq[0])
628
+
481
629
  if not self.alternating_codes or not ((lq // self.row_length) & 1):
482
630
  single_bit = 2
483
631
  other_bits = [0, 1]
@@ -492,16 +640,18 @@ class QrackAceBackend:
492
640
  # but not non-locally, via entanglement.
493
641
  # Collapse the other separable part toward agreement.
494
642
  syndrome += self.sim.force_m(hq[single_bit], bool(syndrome))
495
- self._is_init[lq] = False
496
643
 
497
644
  return True if (syndrome > 1) else False
498
645
 
499
646
  def force_m(self, lq, c):
500
647
  hq = self._unpack(lq)
648
+ self._is_init[lq] = False
649
+ if self._is_col_long_range[lq % self.row_length]:
650
+ return self.sim.force_m(hq[0])
651
+
501
652
  self._correct(lq)
502
653
  for q in hq:
503
654
  self.sim.force_m(q, c)
504
- self._is_init[lq] = False
505
655
 
506
656
  return c
507
657
 
@@ -516,54 +666,34 @@ class QrackAceBackend:
516
666
  col_offset = random.randint(0, self.row_length - 1)
517
667
  col_reverse = self.alternating_codes and (lq_row & 1)
518
668
  for c in range(self.row_length):
519
- lq_col = (((self.row_length - (c + 1)) if col_reverse else c) + col_offset) % self.row_length
669
+ lq_col = (
670
+ ((self.row_length - (c + 1)) if col_reverse else c) + col_offset
671
+ ) % self.row_length
520
672
  lq = lq_row * self.row_length + lq_col
521
673
  if self.m(lq):
522
674
  result |= 1 << lq
523
675
 
524
676
  return result
525
677
 
526
- def measure_shots(self, q, s, high_accuracy=True):
527
- if high_accuracy:
528
- samples = []
529
- for _ in range(s):
530
- clone = self.clone()
531
- _sample = clone.m_all()
532
- sample = 0
533
- for i in range(len(q)):
534
- if (_sample >> q[i]) & 1:
535
- sample |= 1 << i
536
- samples.append(sample)
537
-
538
- return samples
539
-
540
- _q = []
541
- for i in q:
542
- _q.append(3 * i)
543
- _q.append(3 * i + 1)
544
- _q.append(3 * i + 2)
545
-
546
- samples = self.sim.measure_shots(_q, s)
547
-
548
- results = []
549
- for sample in samples:
550
- logical_sample = 0
678
+ def measure_shots(self, q, s):
679
+ samples = []
680
+ for _ in range(s):
681
+ clone = self.clone()
682
+ _sample = clone.m_all()
683
+ sample = 0
551
684
  for i in range(len(q)):
552
- logical_sample <<= 1
553
- bit_count = 0
554
- for _ in range(3):
555
- if sample & 1:
556
- bit_count += 1
557
- sample >>= 1
558
- if bit_count > 1:
559
- logical_sample |= 1
560
- results.append(logical_sample)
561
-
562
- return results
685
+ if (_sample >> q[i]) & 1:
686
+ sample |= 1 << i
687
+ samples.append(sample)
688
+
689
+ return samples
563
690
 
564
691
  def prob(self, lq):
565
- self._correct(lq)
566
692
  hq = self._unpack(lq)
693
+ if self._is_col_long_range[lq % self.row_length]:
694
+ return self.sim.prob(hq[0])
695
+
696
+ self._correct(lq)
567
697
  if not self.alternating_codes or not ((lq // self.row_length) & 1):
568
698
  other_bits = [0, 1]
569
699
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cuda
3
- Version: 1.46.7
3
+ Version: 1.47.1
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.46.7"
10
+ VERSION = "1.47.1"
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
File without changes