pyqrack-complex128 1.62.0__py3-none-macosx_13_0_x86_64.whl → 1.71.1__py3-none-macosx_13_0_x86_64.whl

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.

Potentially problematic release.


This version of pyqrack-complex128 might be problematic. Click here for more details.

@@ -27,6 +27,169 @@ except ImportError:
27
27
  _IS_QISKIT_AER_AVAILABLE = False
28
28
 
29
29
 
30
+ # Initial stub and concept produced through conversation with Elara
31
+ # (the custom OpenAI GPT)
32
+ class LHVQubit:
33
+ def __init__(self, toClone=None):
34
+ # Initial state in "Bloch vector" terms, defaults to |0⟩
35
+ if toClone:
36
+ self.bloch = toClone.bloch.copy()
37
+ else:
38
+ self.reset()
39
+
40
+ def reset(self):
41
+ self.bloch = [0.0, 0.0, 1.0]
42
+
43
+ def h(self):
44
+ # Hadamard: rotate around Y-axis then X-axis (simplified for LHV)
45
+ x, y, z = self.bloch
46
+ self.bloch = [(x + z) / math.sqrt(2), y, (z - x) / math.sqrt(2)]
47
+
48
+ def x(self):
49
+ x, y, z = self.bloch
50
+ self.bloch = [x, y, -z]
51
+
52
+ def y(self):
53
+ x, y, z = self.bloch
54
+ self.bloch = [-x, y, z]
55
+
56
+ def z(self):
57
+ x, y, z = self.bloch
58
+ self.bloch = [x, -y, z]
59
+
60
+ def rx(self, theta):
61
+ # Rotate Bloch vector around X-axis by angle theta
62
+ x, y, z = self.bloch
63
+ cos_theta = math.cos(theta)
64
+ sin_theta = math.sin(theta)
65
+ new_y = cos_theta * y - sin_theta * z
66
+ new_z = sin_theta * y + cos_theta * z
67
+ self.bloch = [x, new_y, new_z]
68
+
69
+ def ry(self, theta):
70
+ # Rotate Bloch vector around Y-axis by angle theta
71
+ x, y, z = self.bloch
72
+ cos_theta = math.cos(theta)
73
+ sin_theta = math.sin(theta)
74
+ new_x = cos_theta * x + sin_theta * z
75
+ new_z = -sin_theta * x + cos_theta * z
76
+ self.bloch = [new_x, y, new_z]
77
+
78
+ def rz(self, theta):
79
+ # Rotate Bloch vector around Z-axis by angle theta (in radians)
80
+ x, y, z = self.bloch
81
+ cos_theta = math.cos(theta)
82
+ sin_theta = math.sin(theta)
83
+ new_x = cos_theta * x - sin_theta * y
84
+ new_y = sin_theta * x + cos_theta * y
85
+ self.bloch = [new_x, new_y, z]
86
+
87
+ def s(self):
88
+ self.rz(math.pi / 2)
89
+
90
+ def adjs(self):
91
+ self.rz(-math.pi / 2)
92
+
93
+ def t(self):
94
+ self.rz(math.pi / 4)
95
+
96
+ def adjt(self):
97
+ self.rz(-math.pi / 4)
98
+
99
+ def u(self, theta, phi, lam):
100
+ # Apply general single-qubit unitary gate
101
+ self.rz(lam)
102
+ self.ry(theta)
103
+ self.rz(phi)
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
+ p = math.sqrt(new_x**2 + new_y**2 + new_z**2)
143
+
144
+ new_x /= p
145
+ new_y /= p
146
+ new_z /= p
147
+
148
+ self.bloch = [new_x, new_y, new_z]
149
+
150
+ def prob(self, basis=Pauli.PauliZ):
151
+ """Sample a classical outcome from the current 'quantum' state"""
152
+ if basis == Pauli.PauliZ:
153
+ prob_1 = (1 - self.bloch[2]) / 2
154
+ elif basis == Pauli.PauliX:
155
+ prob_1 = (1 - self.bloch[0]) / 2
156
+ elif basis == Pauli.PauliY:
157
+ prob_1 = (1 - self.bloch[1]) / 2
158
+ else:
159
+ raise ValueError(f"Unsupported basis: {basis}")
160
+ return prob_1
161
+
162
+ def m(self):
163
+ result = random.random() < self.prob()
164
+ self.reset()
165
+ if result:
166
+ self.x()
167
+ return result
168
+
169
+
170
+ # Provided by Elara (the custom OpenAI GPT)
171
+ def _cpauli_lhv(prob, targ, axis, anti, theta=math.pi):
172
+ """
173
+ Apply a 'soft' controlled-Pauli gate: rotate target qubit
174
+ proportionally to control's Z expectation value.
175
+
176
+ theta: full rotation angle if control in |1⟩
177
+ """
178
+ # Control influence is (1 - ctrl.bloch[2]) / 2 = P(|1⟩)
179
+ # BUT we avoid collapse by using the expectation value:
180
+ control_influence = (1 - prob) if anti else prob
181
+
182
+ effective_theta = control_influence * theta
183
+
184
+ # Apply partial rotation to target qubit:
185
+ if axis == Pauli.PauliX:
186
+ targ.rx(effective_theta)
187
+ elif axis == Pauli.PauliY:
188
+ targ.ry(effective_theta)
189
+ elif axis == Pauli.PauliZ:
190
+ targ.rz(effective_theta)
191
+
192
+
30
193
  class QrackAceBackend:
31
194
  """A back end for elided quantum error correction
32
195
 
@@ -45,7 +208,6 @@ class QrackAceBackend:
45
208
  sim(QrackSimulator): Array of simulators corresponding to "patches" between boundary rows.
46
209
  long_range_columns(int): How many ideal rows between QEC boundary rows?
47
210
  is_transpose(bool): Rows are long if False, columns are long if True
48
- correction_bias(float): Bias magnitude and direction during pseudo-QEC
49
211
  """
50
212
 
51
213
  def __init__(
@@ -54,7 +216,6 @@ class QrackAceBackend:
54
216
  long_range_columns=4,
55
217
  long_range_rows=4,
56
218
  is_transpose=False,
57
- correction_bias=0,
58
219
  isTensorNetwork=False,
59
220
  isSchmidtDecomposeMulti=False,
60
221
  isSchmidtDecompose=True,
@@ -83,7 +244,6 @@ class QrackAceBackend:
83
244
  self.long_range_columns = long_range_columns
84
245
  self.long_range_rows = long_range_rows
85
246
  self.is_transpose = is_transpose
86
- self.correction_bias = correction_bias
87
247
 
88
248
  fppow = 5
89
249
  if "QRACK_FPPOW" in os.environ:
@@ -122,6 +282,7 @@ class QrackAceBackend:
122
282
  self._qubits = []
123
283
  sim_counts = [0] * sim_count
124
284
  sim_id = 0
285
+ tot_qubits = 0
125
286
  for r in self._is_row_long_range:
126
287
  for c in self._is_col_long_range:
127
288
  qubit = [(sim_id, sim_counts[sim_id])]
@@ -132,6 +293,14 @@ class QrackAceBackend:
132
293
  qubit.append((t_sim_id, sim_counts[t_sim_id]))
133
294
  sim_counts[t_sim_id] += 1
134
295
 
296
+ qubit.append(
297
+ LHVQubit(
298
+ toClone=(
299
+ toClone._qubits[tot_qubits][2] if toClone else None
300
+ )
301
+ )
302
+ )
303
+
135
304
  if (not c) and (not r):
136
305
  t_sim_id = (sim_id + col_patch_count) % sim_count
137
306
  qubit.append((t_sim_id, sim_counts[t_sim_id]))
@@ -145,6 +314,7 @@ class QrackAceBackend:
145
314
  sim_id = (sim_id + 1) % sim_count
146
315
 
147
316
  self._qubits.append(qubit)
317
+ tot_qubits += 1
148
318
 
149
319
  self.sim = []
150
320
  for i in range(sim_count):
@@ -262,16 +432,34 @@ class QrackAceBackend:
262
432
  def _unpack(self, lq):
263
433
  return self._qubits[lq]
264
434
 
265
- def _get_qb_indices(self, hq):
435
+ def _get_qb_lhv_indices(self, hq):
266
436
  qb = []
267
437
  if len(hq) < 2:
268
438
  qb = [0]
439
+ lhv = -1
269
440
  elif len(hq) < 4:
270
441
  qb = [0, 1]
442
+ lhv = 2
271
443
  else:
272
- qb = [0, 1, 2, 3]
444
+ qb = [0, 1, 3, 4]
445
+ lhv = 2
273
446
 
274
- return qb
447
+ return qb, lhv
448
+
449
+ def _get_lhv_bloch_angles(self, sim):
450
+ # Z axis
451
+ z = sim.bloch[2]
452
+
453
+ # X axis
454
+ x = sim.bloch[0]
455
+
456
+ # Y axis
457
+ y = sim.bloch[1]
458
+
459
+ inclination = math.atan2(math.sqrt(x**2 + y**2), z)
460
+ azimuth = math.atan2(y, x)
461
+
462
+ return azimuth, inclination
275
463
 
276
464
  def _get_bloch_angles(self, hq):
277
465
  sim = self.sim[hq[0]].clone()
@@ -315,100 +503,146 @@ class QrackAceBackend:
315
503
 
316
504
  sim.mtrx([m00, m01, m10, m11], q)
317
505
 
506
+ def _rotate_lhv_to_bloch(self, sim, delta_azimuth, delta_inclination):
507
+ # Apply rotation as "Azimuth, Inclination" (AI)
508
+ cosA = math.cos(delta_azimuth)
509
+ sinA = math.sin(delta_azimuth)
510
+ cosI = math.cos(delta_inclination / 2)
511
+ sinI = math.sin(delta_inclination / 2)
512
+
513
+ m00 = complex(cosI, 0)
514
+ m01 = complex(-cosA, sinA) * sinI
515
+ m10 = complex(cosA, sinA) * sinI
516
+ m11 = complex(cosI, 0)
517
+
518
+ sim.mtrx([m00, m01, m10, m11])
519
+
318
520
  def _correct(self, lq, phase=False, skip_rotation=False):
319
521
  hq = self._unpack(lq)
320
522
 
321
523
  if len(hq) == 1:
322
524
  return
323
525
 
324
- qb = self._get_qb_indices(hq)
526
+ qb, lhv = self._get_qb_lhv_indices(hq)
325
527
 
326
528
  if phase:
327
529
  for q in qb:
328
530
  b = hq[q]
329
531
  self.sim[b[0]].h(b[1])
532
+ b = hq[lhv]
533
+ b.h()
330
534
 
331
535
  if len(hq) == 5:
332
536
  # RMS
333
537
  p = [
334
538
  self.sim[hq[0][0]].prob(hq[0][1]),
335
539
  self.sim[hq[1][0]].prob(hq[1][1]),
336
- self.sim[hq[2][0]].prob(hq[2][1]),
540
+ hq[2].prob(),
337
541
  self.sim[hq[3][0]].prob(hq[3][1]),
542
+ self.sim[hq[4][0]].prob(hq[4][1]),
338
543
  ]
339
544
  # Balancing suggestion from Elara (the custom OpenAI GPT)
340
- prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
545
+ prms = math.sqrt(
546
+ (p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
547
+ )
341
548
  qrms = math.sqrt(
342
- ((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
343
- / 4
549
+ (
550
+ (1 - p[0]) ** 2
551
+ + (1 - p[1]) ** 2
552
+ + 3 * ((1 - p[2]) ** 2)
553
+ + (1 - p[3]) ** 2
554
+ + (1 - p[4]) ** 2
555
+ )
556
+ / 7
344
557
  )
345
558
  result = ((prms + (1 - qrms)) / 2) >= 0.5
346
559
  syndrome = (
347
- [1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3]]
560
+ [1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3], 1 - p[4]]
348
561
  if result
349
- else [p[0], p[1], p[2], p[3]]
562
+ else [p[0], p[1], p[2], p[3], p[4]]
350
563
  )
351
- for q in range(4):
564
+ for q in range(5):
352
565
  if syndrome[q] > (0.5 + self._epsilon):
353
- self.sim[hq[q][0]].x(hq[q][1])
566
+ if q == 2:
567
+ hq[q].x()
568
+ else:
569
+ self.sim[hq[q][0]].x(hq[q][1])
354
570
 
355
571
  if not skip_rotation:
356
- a, i = [0, 0, 0, 0], [0, 0, 0, 0]
572
+ a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
357
573
  a[0], i[0] = self._get_bloch_angles(hq[0])
358
574
  a[1], i[1] = self._get_bloch_angles(hq[1])
359
- a[2], i[2] = self._get_bloch_angles(hq[3])
360
- a[3], i[3] = self._get_bloch_angles(hq[4])
575
+ a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
576
+ a[3], i[3] = self._get_bloch_angles(hq[3])
577
+ a[4], i[4] = self._get_bloch_angles(hq[4])
361
578
 
362
579
  a_target = 0
363
580
  i_target = 0
364
- for x in range(4):
581
+ for x in range(5):
582
+ if x == 2:
583
+ continue
365
584
  a_target += a[x]
366
585
  i_target += i[x]
367
586
 
368
- a_target /= 4
369
- i_target /= 4
370
- for x in range(4):
371
- self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
372
-
373
- self.apply_magnetic_bias([lq], self.correction_bias)
587
+ a_target /= 5
588
+ i_target /= 5
589
+ for x in range(5):
590
+ if x == 2:
591
+ self._rotate_lhv_to_bloch(
592
+ hq[x], a_target - a[x], i_target - i[x]
593
+ )
594
+ else:
595
+ self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
374
596
 
375
597
  else:
376
598
  # RMS
377
599
  p = [
378
600
  self.sim[hq[0][0]].prob(hq[0][1]),
379
601
  self.sim[hq[1][0]].prob(hq[1][1]),
602
+ hq[2].prob(),
380
603
  ]
381
604
  # Balancing suggestion from Elara (the custom OpenAI GPT)
382
- prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
383
- qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
605
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
606
+ qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
384
607
  result = ((prms + (1 - qrms)) / 2) >= 0.5
385
- syndrome = [1 - p[0], 1 - p[1]] if result else [p[0], p[1]]
386
- for q in range(2):
608
+ syndrome = [1 - p[0], 1 - p[1], 1 - p[2]] if result else [p[0], p[1], p[2]]
609
+ for q in range(3):
387
610
  if syndrome[q] > (0.5 + self._epsilon):
388
- self.sim[hq[q][0]].x(hq[q][1])
611
+ if q == 2:
612
+ hq[q].x()
613
+ else:
614
+ self.sim[hq[q][0]].x(hq[q][1])
389
615
 
390
616
  if not skip_rotation:
391
- a, i = [0, 0], [0, 0]
617
+ a, i = [0, 0, 0], [0, 0, 0]
392
618
  a[0], i[0] = self._get_bloch_angles(hq[0])
393
619
  a[1], i[1] = self._get_bloch_angles(hq[1])
620
+ a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
394
621
 
395
622
  a_target = 0
396
623
  i_target = 0
397
- for x in range(2):
624
+ for x in range(3):
625
+ if x == 2:
626
+ continue
398
627
  a_target += a[x]
399
628
  i_target += i[x]
400
629
 
401
- a_target /= 2
402
- i_target /= 2
403
- for x in range(2):
404
- self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
405
-
406
- self.apply_magnetic_bias([lq], self.correction_bias)
630
+ a_target /= 3
631
+ i_target /= 3
632
+ for x in range(3):
633
+ if x == 2:
634
+ self._rotate_lhv_to_bloch(
635
+ hq[x], a_target - a[x], i_target - i[x]
636
+ )
637
+ else:
638
+ self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
407
639
 
408
640
  if phase:
409
641
  for q in qb:
410
642
  b = hq[q]
411
643
  self.sim[b[0]].h(b[1])
644
+ b = hq[lhv]
645
+ b.h()
412
646
 
413
647
  def apply_magnetic_bias(self, q, b):
414
648
  if b == 0:
@@ -416,11 +650,22 @@ class QrackAceBackend:
416
650
  b = math.exp(b)
417
651
  for x in q:
418
652
  hq = self._unpack(x)
419
- for h in hq:
420
- a, i = self._get_bloch_angles(h)
421
- self._rotate_to_bloch(
422
- h, math.atan(math.tan(a) * b) - a, math.atan(math.tan(i) * b) - i
423
- )
653
+ for c in range(len(hq)):
654
+ h = hq[c]
655
+ if c == 2:
656
+ a, i = self._get_lhv_bloch_angles(h)
657
+ self._rotate_lhv_to_bloch(
658
+ h,
659
+ math.atan(math.tan(a) * b) - a,
660
+ math.atan(math.tan(i) * b) - i,
661
+ )
662
+ else:
663
+ a, i = self._get_bloch_angles(h)
664
+ self._rotate_to_bloch(
665
+ h,
666
+ math.atan(math.tan(a) * b) - a,
667
+ math.atan(math.tan(i) * b) - i,
668
+ )
424
669
 
425
670
  def u(self, lq, th, ph, lm):
426
671
  hq = self._unpack(lq)
@@ -429,12 +674,15 @@ class QrackAceBackend:
429
674
  self.sim[b[0]].u(b[1], th, ph, lm)
430
675
  return
431
676
 
432
- qb = self._get_qb_indices(hq)
677
+ qb, lhv = self._get_qb_lhv_indices(hq)
433
678
 
434
679
  for q in qb:
435
680
  b = hq[q]
436
681
  self.sim[b[0]].u(b[1], th, ph, lm)
437
682
 
683
+ b = hq[lhv]
684
+ b.u(th, ph, lm)
685
+
438
686
  self._correct(lq, False, True)
439
687
  self._correct(lq, True, False)
440
688
 
@@ -445,12 +693,20 @@ class QrackAceBackend:
445
693
  self.sim[b[0]].r(p, th, b[1])
446
694
  return
447
695
 
448
- qb = self._get_qb_indices(hq)
696
+ qb, lhv = self._get_qb_lhv_indices(hq)
449
697
 
450
698
  for q in qb:
451
699
  b = hq[q]
452
700
  self.sim[b[0]].r(p, th, b[1])
453
701
 
702
+ b = hq[lhv]
703
+ if p == Pauli.PauliX:
704
+ b.rx(th)
705
+ elif p == Pauli.PauliY:
706
+ b.ry(th)
707
+ elif p == Pauli.PauliZ:
708
+ b.rz(th)
709
+
454
710
  if p != Pauli.PauliZ:
455
711
  self._correct(lq, False, p != Pauli.PauliX)
456
712
  if p != Pauli.PauliX:
@@ -465,12 +721,15 @@ class QrackAceBackend:
465
721
 
466
722
  self._correct(lq)
467
723
 
468
- qb = self._get_qb_indices(hq)
724
+ qb, lhv = self._get_qb_lhv_indices(hq)
469
725
 
470
726
  for q in qb:
471
727
  b = hq[q]
472
728
  self.sim[b[0]].h(b[1])
473
729
 
730
+ b = hq[lhv]
731
+ b.h()
732
+
474
733
  self._correct(lq)
475
734
 
476
735
  def s(self, lq):
@@ -480,12 +739,15 @@ class QrackAceBackend:
480
739
  self.sim[b[0]].s(b[1])
481
740
  return
482
741
 
483
- qb = self._get_qb_indices(hq)
742
+ qb, lhv = self._get_qb_lhv_indices(hq)
484
743
 
485
744
  for q in qb:
486
745
  b = hq[q]
487
746
  self.sim[b[0]].s(b[1])
488
747
 
748
+ b = hq[lhv]
749
+ b.s()
750
+
489
751
  def adjs(self, lq):
490
752
  hq = self._unpack(lq)
491
753
  if len(hq) < 2:
@@ -493,12 +755,15 @@ class QrackAceBackend:
493
755
  self.sim[b[0]].adjs(b[1])
494
756
  return
495
757
 
496
- qb = self._get_qb_indices(hq)
758
+ qb, lhv = self._get_qb_lhv_indices(hq)
497
759
 
498
760
  for q in qb:
499
761
  b = hq[q]
500
762
  self.sim[b[0]].adjs(b[1])
501
763
 
764
+ b = hq[lhv]
765
+ b.adjs()
766
+
502
767
  def x(self, lq):
503
768
  hq = self._unpack(lq)
504
769
  if len(hq) < 2:
@@ -506,12 +771,15 @@ class QrackAceBackend:
506
771
  self.sim[b[0]].x(b[1])
507
772
  return
508
773
 
509
- qb = self._get_qb_indices(hq)
774
+ qb, lhv = self._get_qb_lhv_indices(hq)
510
775
 
511
776
  for q in qb:
512
777
  b = hq[q]
513
778
  self.sim[b[0]].x(b[1])
514
779
 
780
+ b = hq[lhv]
781
+ b.x()
782
+
515
783
  def y(self, lq):
516
784
  hq = self._unpack(lq)
517
785
  if len(hq) < 2:
@@ -519,12 +787,15 @@ class QrackAceBackend:
519
787
  self.sim[b[0]].y(b[1])
520
788
  return
521
789
 
522
- qb = self._get_qb_indices(hq)
790
+ qb, lhv = self._get_qb_lhv_indices(hq)
523
791
 
524
792
  for q in qb:
525
793
  b = hq[q]
526
794
  self.sim[b[0]].y(b[1])
527
795
 
796
+ b = hq[lhv]
797
+ b.y()
798
+
528
799
  def z(self, lq):
529
800
  hq = self._unpack(lq)
530
801
  if len(hq) < 2:
@@ -532,12 +803,15 @@ class QrackAceBackend:
532
803
  self.sim[b[0]].z(b[1])
533
804
  return
534
805
 
535
- qb = self._get_qb_indices(hq)
806
+ qb, lhv = self._get_qb_lhv_indices(hq)
536
807
 
537
808
  for q in qb:
538
809
  b = hq[q]
539
810
  self.sim[b[0]].z(b[1])
540
811
 
812
+ b = hq[lhv]
813
+ b.z()
814
+
541
815
  def t(self, lq):
542
816
  hq = self._unpack(lq)
543
817
  if len(hq) < 2:
@@ -545,12 +819,15 @@ class QrackAceBackend:
545
819
  self.sim[b[0]].t(b[1])
546
820
  return
547
821
 
548
- qb = self._get_qb_indices(hq)
822
+ qb, lhv = self._get_qb_lhv_indices(hq)
549
823
 
550
824
  for q in qb:
551
825
  b = hq[q]
552
826
  self.sim[b[0]].t(b[1])
553
827
 
828
+ b = hq[lhv]
829
+ b.t()
830
+
554
831
  def adjt(self, lq):
555
832
  hq = self._unpack(lq)
556
833
  if len(hq) < 2:
@@ -558,12 +835,15 @@ class QrackAceBackend:
558
835
  self.sim[b[0]].adjt(b[1])
559
836
  return
560
837
 
561
- qb = self._get_qb_indices(hq)
838
+ qb, lhv = self._get_qb_lhv_indices(hq)
562
839
 
563
840
  for q in qb:
564
841
  b = hq[q]
565
842
  self.sim[b[0]].adjt(b[1])
566
843
 
844
+ b = hq[lhv]
845
+ b.adjt()
846
+
567
847
  def _get_gate(self, pauli, anti, sim_id):
568
848
  gate = None
569
849
  shadow = None
@@ -604,11 +884,15 @@ class QrackAceBackend:
604
884
 
605
885
  return connected, boundary
606
886
 
607
- def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr):
887
+ def _apply_coupling(self, pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr):
608
888
  for q1 in qb1:
889
+ if q1 == lhv1:
890
+ continue
609
891
  b1 = hq1[q1]
610
892
  gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
611
893
  for q2 in qb2:
894
+ if q2 == lhv2:
895
+ continue
612
896
  b2 = hq2[q2]
613
897
  if b1[0] == b2[0]:
614
898
  gate_fn([b1[1]], b2[1])
@@ -633,10 +917,18 @@ class QrackAceBackend:
633
917
 
634
918
  self._correct(lq1)
635
919
 
636
- qb1 = self._get_qb_indices(hq1)
637
- qb2 = self._get_qb_indices(hq2)
920
+ qb1, lhv1 = self._get_qb_lhv_indices(hq1)
921
+ qb2, lhv2 = self._get_qb_lhv_indices(hq2)
638
922
  # Apply cross coupling on hardware qubits first
639
- self._apply_coupling(pauli, anti, qb1, hq1, qb2, hq2, lq1_lr)
923
+ self._apply_coupling(pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr)
924
+ # Apply coupling to the local-hidden-variable target
925
+ if lhv2 >= 0:
926
+ _cpauli_lhv(
927
+ hq1[lhv1].prob() if lhv1 >= 0 else self.sim[hq1[0][0]].prob(hq1[0][1]),
928
+ hq2[lhv2],
929
+ pauli,
930
+ anti,
931
+ )
640
932
 
641
933
  self._correct(lq1, True)
642
934
  if pauli != Pauli.PauliZ:
@@ -738,20 +1030,29 @@ class QrackAceBackend:
738
1030
  self.sim[hq[4][0]].prob(hq[4][1]),
739
1031
  ]
740
1032
  # Balancing suggestion from Elara (the custom OpenAI GPT)
741
- prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
1033
+ prms = math.sqrt(
1034
+ (p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
1035
+ )
742
1036
  qrms = math.sqrt(
743
- ((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
744
- / 4
1037
+ (
1038
+ (1 - p[0]) ** 2
1039
+ + (1 - p[1]) ** 2
1040
+ + 3 * ((1 - p[2]) ** 2)
1041
+ + (1 - p[3]) ** 2
1042
+ + (1 - p[4]) ** 2
1043
+ )
1044
+ / 7
745
1045
  )
746
1046
  else:
747
1047
  # RMS
748
1048
  p = [
749
1049
  self.sim[hq[0][0]].prob(hq[0][1]),
750
1050
  self.sim[hq[1][0]].prob(hq[1][1]),
1051
+ hq[2].prob(),
751
1052
  ]
752
1053
  # Balancing suggestion from Elara (the custom OpenAI GPT)
753
- prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
754
- qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
1054
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
1055
+ qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
755
1056
 
756
1057
  return (prms + (1 - qrms)) / 2
757
1058
 
@@ -764,7 +1065,7 @@ class QrackAceBackend:
764
1065
  p = self.prob(lq)
765
1066
  result = ((p + self._epsilon) >= 1) or (random.random() < p)
766
1067
 
767
- qb = self._get_qb_indices(hq)
1068
+ qb, lhv = self._get_qb_lhv_indices(hq)
768
1069
 
769
1070
  for q in qb:
770
1071
  b = hq[q]
@@ -775,6 +1076,11 @@ class QrackAceBackend:
775
1076
  else:
776
1077
  self.sim[b[0]].force_m(b[1], result)
777
1078
 
1079
+ b = hq[lhv]
1080
+ b.reset()
1081
+ if result:
1082
+ b.x()
1083
+
778
1084
  return result
779
1085
 
780
1086
  def force_m(self, lq, result):
@@ -785,7 +1091,7 @@ class QrackAceBackend:
785
1091
 
786
1092
  self._correct(lq)
787
1093
 
788
- qb = self._get_qb_indices(hq)
1094
+ qb, lhv = self._get_qb_lhv_indices(hq)
789
1095
 
790
1096
  for q in qb:
791
1097
  b = hq[q]
@@ -796,6 +1102,11 @@ class QrackAceBackend:
796
1102
  else:
797
1103
  self.sim[b[0]].force_m(b[1], result)
798
1104
 
1105
+ b = hq[1]
1106
+ b.reset()
1107
+ if result:
1108
+ b.x()
1109
+
799
1110
  return c
800
1111
 
801
1112
  def m_all(self):
@@ -60,6 +60,7 @@ class QrackSimulator:
60
60
  isHostPointer=(
61
61
  True if os.environ.get("PYQRACK_HOST_POINTER_DEFAULT_ON") else False
62
62
  ),
63
+ isSparse=False,
63
64
  noise=0,
64
65
  pyzxCircuit=None,
65
66
  qiskitCircuit=None,
@@ -99,6 +100,7 @@ class QrackSimulator:
99
100
  isCpuGpuHybrid,
100
101
  isOpenCL,
101
102
  isHostPointer,
103
+ isSparse
102
104
  )
103
105
 
104
106
  self._throw_if_error()
@@ -1053,9 +1055,16 @@ class QrackSimulator:
1053
1055
  Returns:
1054
1056
  Measurement result of all qubits.
1055
1057
  """
1056
- result = Qrack.qrack_lib.MAll(self.sid)
1058
+ num_q = self.num_qubits()
1059
+ num_words = (num_q + 63) // 64
1060
+ _r = (ctypes.c_ulonglong * num_words)()
1061
+ Qrack.qrack_lib.MAllLong(self.sid, _r)
1057
1062
  self._throw_if_error()
1058
- return result
1063
+ r = 0
1064
+ for w in range(num_words):
1065
+ r <<= 64
1066
+ r |= _r[w]
1067
+ return r
1059
1068
 
1060
1069
  def measure_pauli(self, b, q):
1061
1070
  """Pauli Measurement gate
@@ -2125,9 +2134,7 @@ class QrackSimulator:
2125
2134
  def decompose(self, q):
2126
2135
  """Decompose system
2127
2136
 
2128
- Decompose the given qubit out of the system.
2129
- Warning: The qubit subsystem state must be separable, or the behavior
2130
- of this method is undefined.
2137
+ Factorize a set of contiguous bits with minimal fidelity loss.
2131
2138
 
2132
2139
  Args:
2133
2140
  q: qubit id
@@ -2137,7 +2144,7 @@ class QrackSimulator:
2137
2144
  RuntimeError: QrackSimulator with isTensorNetwork=True option cannot decompose()! (Turn off just this option, in the constructor.)
2138
2145
 
2139
2146
  Returns:
2140
- State of the systems.
2147
+ Decomposed subsystem simulator.
2141
2148
  """
2142
2149
  if self.is_tensor_network:
2143
2150
  raise RuntimeError(
@@ -2154,10 +2161,8 @@ class QrackSimulator:
2154
2161
  def dispose(self, q):
2155
2162
  """Dispose qubits
2156
2163
 
2157
- Minimally decompose a set of contiguous bits from the separably
2158
- composed unit, and discard the separable bits.
2159
- Warning: The qubit subsystem state must be separable, or the behavior
2160
- of this method is undefined.
2164
+ Factorize a set of contiguous bits with minimal fidelity loss,
2165
+ and discard the separable bits.
2161
2166
 
2162
2167
  Args:
2163
2168
  q: qubit
@@ -2165,9 +2170,6 @@ class QrackSimulator:
2165
2170
  Raises:
2166
2171
  RuntimeError: QrackSimulator raised an exception.
2167
2172
  RuntimeError: QrackSimulator with isTensorNetwork=True option cannot dispose()! (Turn off just this option, in the constructor.)
2168
-
2169
- Returns:
2170
- State of the systems.
2171
2173
  """
2172
2174
  if self.is_tensor_network:
2173
2175
  raise RuntimeError(
@@ -2285,6 +2287,72 @@ class QrackSimulator:
2285
2287
  self._throw_if_error()
2286
2288
  return list(probs)
2287
2289
 
2290
+ def out_rdm(self, q):
2291
+ """Get reduced density matrix
2292
+
2293
+ Returns the raw reduced density matrix of the simulator, for the qubit list.
2294
+ Warning: State vector or is not always the internal representation leading
2295
+ to sub-optimal performance of the method.
2296
+
2297
+ Raises:
2298
+ RuntimeError: QrackSimulator raised an exception.
2299
+
2300
+ Returns:
2301
+ flat list structure representing the reduced density matrix.
2302
+ """
2303
+ amp_count = 1 << len(q)
2304
+ sqr_amp_count = amp_count * amp_count
2305
+ flat_rdm = self._qrack_complex_byref([complex(0, 0)] * sqr_amp_count)
2306
+ Qrack.qrack_lib.OutReducedDensityMatrix(self.sid, len(q), self._ulonglong_byref(q), flat_rdm)
2307
+ self._throw_if_error()
2308
+ return [complex(r, i) for r, i in self._pairwise(flat_rdm)]
2309
+
2310
+ def highest_prob_perm(self):
2311
+ """Get the permutation (bit string) with the highest probability
2312
+
2313
+ Returns the single highest-probability bit string in the Hilbert space
2314
+
2315
+ Raises:
2316
+ RuntimeError: QrackSimulator raised an exception.
2317
+
2318
+ Returns:
2319
+ Highest probability dimension index
2320
+ """
2321
+ num_q = self.num_qubits()
2322
+ num_words = (num_q + 63) // 64
2323
+ _r = (ctypes.c_ulonglong * num_words)()
2324
+ Qrack.qrack_lib.HighestProbAll(self.sid, _r)
2325
+ self._throw_if_error()
2326
+ r = 0
2327
+ for w in range(num_words):
2328
+ r <<= 64
2329
+ r |= _r[w]
2330
+ return r
2331
+
2332
+ def highest_n_prob_perm(self, n):
2333
+ """Get the top n permutations (bit strings) with the highest probability
2334
+
2335
+ Returns the top n highest-probability bit strings in the Hilbert space
2336
+
2337
+ Raises:
2338
+ RuntimeError: QrackSimulator raised an exception.
2339
+
2340
+ Returns:
2341
+ Top n highest probability dimension indices
2342
+ """
2343
+ num_q = self.num_qubits()
2344
+ num_words = (num_q + 63) // 64
2345
+ _r = (ctypes.c_ulonglong * (num_words * n))()
2346
+ Qrack.qrack_lib.HighestProbAllN(self.sid, n, _r)
2347
+ self._throw_if_error()
2348
+ r = [0] * n
2349
+ for i in range(n):
2350
+ r[i] = 0
2351
+ for w in range(num_words):
2352
+ r[i] <<= 64
2353
+ r[i] |= _r[(i * num_words) + w]
2354
+ return r
2355
+
2288
2356
  def prob_all(self, q):
2289
2357
  """Probabilities of all subset permutations
2290
2358
 
@@ -87,19 +87,22 @@ class QrackSystem:
87
87
  CFUNCTYPE(c_ulonglong, c_double, c_double),
88
88
  ]
89
89
 
90
- # These next two methods need to have c_double pointers, if PyQrack is built with fp64.
90
+ # These next few methods need to have c_double pointers, if PyQrack is built with fp64.
91
91
  self.qrack_lib.InKet.restype = None
92
92
  self.qrack_lib.OutKet.restype = None
93
93
  self.qrack_lib.OutProbs.restype = None
94
+ self.qrack_lib.OutReducedDensityMatrix.restype = None
94
95
 
95
96
  if self.fppow < 6:
96
97
  self.qrack_lib.InKet.argtypes = [c_ulonglong, POINTER(c_float)]
97
98
  self.qrack_lib.OutKet.argtypes = [c_ulonglong, POINTER(c_float)]
98
99
  self.qrack_lib.OutProbs.argtypes = [c_ulonglong, POINTER(c_float)]
100
+ self.qrack_lib.OutReducedDensityMatrix.argtypes = [c_ulonglong, c_ulonglong, POINTER(c_ulonglong), POINTER(c_float)]
99
101
  else:
100
102
  self.qrack_lib.InKet.argtypes = [c_ulonglong, POINTER(c_double)]
101
103
  self.qrack_lib.OutKet.argtypes = [c_ulonglong, POINTER(c_double)]
102
104
  self.qrack_lib.OutProbs.argtypes = [c_ulonglong, POINTER(c_double)]
105
+ self.qrack_lib.OutReducedDensityMatrix.argtypes = [c_ulonglong, c_ulonglong, POINTER(c_ulonglong), POINTER(c_double)]
103
106
 
104
107
  self.qrack_lib.init.restype = c_ulonglong
105
108
  self.qrack_lib.init.argtypes = []
@@ -108,10 +111,10 @@ class QrackSystem:
108
111
  self.qrack_lib.get_error.argtypes = [c_ulonglong]
109
112
 
110
113
  self.qrack_lib.init_count.restype = c_ulonglong
111
- self.qrack_lib.init_count.argtypes = [c_ulonglong, c_bool]
114
+ self.qrack_lib.init_count.argtypes = [c_ulonglong, c_bool, c_bool]
112
115
 
113
116
  self.qrack_lib.init_count_pager.restype = c_ulonglong
114
- self.qrack_lib.init_count_pager.argtypes = [c_ulonglong, c_bool]
117
+ self.qrack_lib.init_count_pager.argtypes = [c_ulonglong, c_bool, c_bool]
115
118
 
116
119
  self.qrack_lib.init_count_type.restype = c_ulonglong
117
120
  self.qrack_lib.init_count_type.argtypes = [
@@ -126,6 +129,7 @@ class QrackSystem:
126
129
  c_bool,
127
130
  c_bool,
128
131
  c_bool,
132
+ c_bool
129
133
  ]
130
134
 
131
135
  self.qrack_lib.init_count_stabilizer.restype = c_ulonglong
@@ -155,6 +159,12 @@ class QrackSystem:
155
159
 
156
160
  # pseudo-quantum
157
161
 
162
+ self.qrack_lib.HighestProbAll.restype = None
163
+ self.qrack_lib.HighestProbAll.argtypes = [c_ulonglong, POINTER(c_ulonglong)]
164
+
165
+ self.qrack_lib.HighestProbAllN.restype = None
166
+ self.qrack_lib.HighestProbAllN.argtypes = [c_ulonglong, c_ulonglong, POINTER(c_ulonglong)]
167
+
158
168
  self.qrack_lib.ProbAll.restype = None
159
169
  if self.fppow == 5:
160
170
  self.qrack_lib.ProbAll.argtypes = [
@@ -790,6 +800,9 @@ class QrackSystem:
790
800
  self.qrack_lib.MAll.restype = c_ulonglong
791
801
  self.qrack_lib.MAll.argtypes = [c_ulonglong]
792
802
 
803
+ self.qrack_lib.MAllLong.restype = None
804
+ self.qrack_lib.MAllLong.argtypes = [c_ulonglong, POINTER(c_ulonglong)]
805
+
793
806
  self.qrack_lib.Measure.restype = c_ulonglong
794
807
  self.qrack_lib.Measure.argtypes = [
795
808
  c_ulonglong,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyqrack-complex128
3
- Version: 1.62.0
3
+ Version: 1.71.1
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -41,7 +41,7 @@ Provides-Extra: dev
41
41
  Requires-Dist: pytest>=7.3.1; extra == "dev"
42
42
 
43
43
  # pyqrack
44
- [![Downloads](https://pepy.tech/badge/pyqrack)](https://pepy.tech/project/pyqrack) [![Downloads](https://pepy.tech/badge/pyqrack/month)](https://pepy.tech/project/pyqrack) [![Downloads](https://static.pepy.tech/badge/pyqrack/week)](https://pepy.tech/project/pyqrack)
44
+ [![Downloads](https://pepy.tech/badge/pyqrack-complex128)](https://pepy.tech/project/pyqrack-complex128) [![Downloads](https://pepy.tech/badge/pyqrack-complex128/month)](https://pepy.tech/project/pyqrack-complex128) [![Downloads](https://static.pepy.tech/badge/pyqrack-complex128/week)](https://pepy.tech/project/pyqrack-complex128)
45
45
 
46
46
  Pure Python bindings for the pure C++11/OpenCL Qrack quantum computer simulator library
47
47
 
@@ -1,23 +1,23 @@
1
1
  pyqrack/__init__.py,sha256=3tBwfCCD-zQjQ2g1EUZdggKdn-3b2uSFTbT7LS0YLaU,785
2
2
  pyqrack/neuron_activation_fn.py,sha256=fQTTFfsvwcot_43Vopacot47IV2Rxk8pelUyuzwpXPs,593
3
3
  pyqrack/pauli.py,sha256=wg500wDOwdIU4lEVJoMmjtbAdmtakZYzLPjdzC2rwUQ,654
4
- pyqrack/qrack_ace_backend.py,sha256=SLmRwJmUAzV0BWoZJFskMYl21Kg9VXjQnoaAb4g6eDk,40334
4
+ pyqrack/qrack_ace_backend.py,sha256=Prw1NhVVt0csbHiJeW8MJI9rl1P1YS63sXM5quoNPrI,49392
5
5
  pyqrack/qrack_circuit.py,sha256=vDCKGbcEHJDFUKprjCpWgit8lXFnMrPimKHURD2_Hj4,19538
6
6
  pyqrack/qrack_neuron.py,sha256=UiJdjAGB6usjAGHWSosSFCUUeIkhh3MtZbsaxfsIsNw,9043
7
7
  pyqrack/qrack_neuron_torch_layer.py,sha256=Bs5BLC2GFevfSpo_jSJ2AZl-hfDRJmzlGN9pFw1CtoQ,6160
8
- pyqrack/qrack_simulator.py,sha256=2z4zGNPvDvVz2ctjeJl3jxUnKu0CxkABHvW5zxdUHa8,143781
8
+ pyqrack/qrack_simulator.py,sha256=PSrcEIlzCt33WXjoEo5dZdmzx9zR90QI_Dw9LTphjMg,146030
9
9
  pyqrack/qrack_stabilizer.py,sha256=O-7VJ9Vw4h25PK_kesSjIqHXGSo8lLrQLIyGgmzG7Co,2124
10
10
  pyqrack/quimb_circuit_type.py,sha256=Sk-Tmn38kUYmAkJJ75btWuhYZyTXOOezmowFhfdiGDc,621
11
11
  pyqrack/qrack_system/__init__.py,sha256=-oZ9dsb1hixsnrkUJRY_C5DzQ_l6MtifF_Z465BgqV4,334
12
- pyqrack/qrack_system/qrack_system.py,sha256=FWEMiBfDDoNIAo8jbqFR9MkvRGr6rOU_frvKGMgnTO8,42943
12
+ pyqrack/qrack_system/qrack_system.py,sha256=3NFejSMePILaND-h3bdwRrX-WuhdZj-Uzt-8i90_xQE,43719
13
13
  pyqrack/qrack_system/qrack_cl_precompile/qrack_cl_precompile,sha256=8xQYqoFTKIl-5v6ZkqmbWp14Eowkl8ty2vNF2shC5hU,35040
14
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.9.22.0.dylib,sha256=ZRtCsCAF67qRyTLsF9IPkEQlue-Ye0aDYIWE4L-AWFk,3136856
15
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.dylib,sha256=ZRtCsCAF67qRyTLsF9IPkEQlue-Ye0aDYIWE4L-AWFk,3136856
14
+ pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.9.30.1.dylib,sha256=dFn-CqdTw3R3k08t-5zDqZRKbjMgyvSUAXk8mugjkds,3941720
15
+ pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.dylib,sha256=dFn-CqdTw3R3k08t-5zDqZRKbjMgyvSUAXk8mugjkds,3941720
16
16
  pyqrack/stats/__init__.py,sha256=Hla85my2fY_roR9lIjGBVpEG7ySOTMwjWa8D6-kgCnY,276
17
17
  pyqrack/stats/load_quantized_data.py,sha256=z12u9F7Nt3P-i44nY1xxvso_klS6WIHS3iqq7R2_lqE,1184
18
18
  pyqrack/stats/quantize_by_range.py,sha256=UM0_7jJDdQ7g30cR3UQAxkbzkqrmsy1oUfqg0h11FUY,2270
19
- pyqrack_complex128-1.62.0.dist-info/LICENSE,sha256=HxB-7SaWTuewAk1nz-3_3FUD6QhgX73kNT_taKVUTq8,1069
20
- pyqrack_complex128-1.62.0.dist-info/METADATA,sha256=lqLRMSEBTkrv5xD9kMDPrl74gVuOHbcvrrLLljwsmuY,5903
21
- pyqrack_complex128-1.62.0.dist-info/WHEEL,sha256=nZx8s83OrgdDmpcWX-8FgI0sEAjdQimt4SdYsdcCaC8,107
22
- pyqrack_complex128-1.62.0.dist-info/top_level.txt,sha256=YE_3q9JTGRLMilNg2tGP1y7uU-Dx8PDao2OhwoIbv8E,8
23
- pyqrack_complex128-1.62.0.dist-info/RECORD,,
19
+ pyqrack_complex128-1.71.1.dist-info/LICENSE,sha256=HxB-7SaWTuewAk1nz-3_3FUD6QhgX73kNT_taKVUTq8,1069
20
+ pyqrack_complex128-1.71.1.dist-info/METADATA,sha256=Xci4A4ZRU7BKKqNPv_UQmR1qyV8m8w1xl4qwnbqetUo,5969
21
+ pyqrack_complex128-1.71.1.dist-info/WHEEL,sha256=nZx8s83OrgdDmpcWX-8FgI0sEAjdQimt4SdYsdcCaC8,107
22
+ pyqrack_complex128-1.71.1.dist-info/top_level.txt,sha256=YE_3q9JTGRLMilNg2tGP1y7uU-Dx8PDao2OhwoIbv8E,8
23
+ pyqrack_complex128-1.71.1.dist-info/RECORD,,