pyqrack-cpu 1.61.2__py3-none-macosx_13_0_x86_64.whl → 1.62.0__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.
@@ -27,163 +27,6 @@ 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
- self.bloch = [new_x, new_y, new_z]
143
-
144
- def prob(self, basis=Pauli.PauliZ):
145
- """Sample a classical outcome from the current 'quantum' state"""
146
- if basis == Pauli.PauliZ:
147
- prob_1 = (1 - self.bloch[2]) / 2
148
- elif basis == Pauli.PauliX:
149
- prob_1 = (1 - self.bloch[0]) / 2
150
- elif basis == Pauli.PauliY:
151
- prob_1 = (1 - self.bloch[1]) / 2
152
- else:
153
- raise ValueError(f"Unsupported basis: {basis}")
154
- return prob_1
155
-
156
- def m(self):
157
- result = random.random() < self.prob()
158
- self.reset()
159
- if result:
160
- self.x()
161
- return result
162
-
163
-
164
- # Provided by Elara (the custom OpenAI GPT)
165
- def _cpauli_lhv(prob, targ, axis, anti, theta=math.pi):
166
- """
167
- Apply a 'soft' controlled-Pauli gate: rotate target qubit
168
- proportionally to control's Z expectation value.
169
-
170
- theta: full rotation angle if control in |1⟩
171
- """
172
- # Control influence is (1 - ctrl.bloch[2]) / 2 = P(|1⟩)
173
- # BUT we avoid collapse by using the expectation value:
174
- control_influence = (1 - prob) if anti else prob
175
-
176
- effective_theta = control_influence * theta
177
-
178
- # Apply partial rotation to target qubit:
179
- if axis == Pauli.PauliX:
180
- targ.rx(effective_theta)
181
- elif axis == Pauli.PauliY:
182
- targ.ry(effective_theta)
183
- elif axis == Pauli.PauliZ:
184
- targ.rz(effective_theta)
185
-
186
-
187
30
  class QrackAceBackend:
188
31
  """A back end for elided quantum error correction
189
32
 
@@ -202,6 +45,7 @@ class QrackAceBackend:
202
45
  sim(QrackSimulator): Array of simulators corresponding to "patches" between boundary rows.
203
46
  long_range_columns(int): How many ideal rows between QEC boundary rows?
204
47
  is_transpose(bool): Rows are long if False, columns are long if True
48
+ correction_bias(float): Bias magnitude and direction during pseudo-QEC
205
49
  """
206
50
 
207
51
  def __init__(
@@ -210,6 +54,7 @@ class QrackAceBackend:
210
54
  long_range_columns=4,
211
55
  long_range_rows=4,
212
56
  is_transpose=False,
57
+ correction_bias=0,
213
58
  isTensorNetwork=False,
214
59
  isSchmidtDecomposeMulti=False,
215
60
  isSchmidtDecompose=True,
@@ -238,6 +83,7 @@ class QrackAceBackend:
238
83
  self.long_range_columns = long_range_columns
239
84
  self.long_range_rows = long_range_rows
240
85
  self.is_transpose = is_transpose
86
+ self.correction_bias = correction_bias
241
87
 
242
88
  fppow = 5
243
89
  if "QRACK_FPPOW" in os.environ:
@@ -273,10 +119,9 @@ class QrackAceBackend:
273
119
  self._is_row_long_range[-1] = False
274
120
  sim_count = col_patch_count * row_patch_count
275
121
 
276
- self._qubit_dict = {}
122
+ self._qubits = []
277
123
  sim_counts = [0] * sim_count
278
124
  sim_id = 0
279
- tot_qubits = 0
280
125
  for r in self._is_row_long_range:
281
126
  for c in self._is_col_long_range:
282
127
  qubit = [(sim_id, sim_counts[sim_id])]
@@ -287,14 +132,6 @@ class QrackAceBackend:
287
132
  qubit.append((t_sim_id, sim_counts[t_sim_id]))
288
133
  sim_counts[t_sim_id] += 1
289
134
 
290
- qubit.append(
291
- LHVQubit(
292
- toClone=(
293
- toClone._qubit_dict[tot_qubits][2] if toClone else None
294
- )
295
- )
296
- )
297
-
298
135
  if (not c) and (not r):
299
136
  t_sim_id = (sim_id + col_patch_count) % sim_count
300
137
  qubit.append((t_sim_id, sim_counts[t_sim_id]))
@@ -307,8 +144,7 @@ class QrackAceBackend:
307
144
  if not c:
308
145
  sim_id = (sim_id + 1) % sim_count
309
146
 
310
- self._qubit_dict[tot_qubits] = qubit
311
- tot_qubits += 1
147
+ self._qubits.append(qubit)
312
148
 
313
149
  self.sim = []
314
150
  for i in range(sim_count):
@@ -424,36 +260,18 @@ class QrackAceBackend:
424
260
  self._qec_x(c)
425
261
 
426
262
  def _unpack(self, lq):
427
- return self._qubit_dict[lq]
263
+ return self._qubits[lq]
428
264
 
429
- def _get_qb_lhv_indices(self, hq):
265
+ def _get_qb_indices(self, hq):
430
266
  qb = []
431
267
  if len(hq) < 2:
432
268
  qb = [0]
433
- lhv = -1
434
269
  elif len(hq) < 4:
435
270
  qb = [0, 1]
436
- lhv = 2
437
271
  else:
438
- qb = [0, 1, 3, 4]
439
- lhv = 2
440
-
441
- return qb, lhv
272
+ qb = [0, 1, 2, 3]
442
273
 
443
- def _get_lhv_bloch_angles(self, sim):
444
- # Z axis
445
- z = 1 - 2 * sim.prob(Pauli.PauliZ)
446
-
447
- # X axis
448
- x = 1 - 2 * sim.prob(Pauli.PauliX)
449
-
450
- # Y axis
451
- y = 1 - 2 * sim.prob(Pauli.PauliY)
452
-
453
- inclination = math.atan2(math.sqrt(x**2 + y**2), z)
454
- azimuth = math.atan2(y, x)
455
-
456
- return azimuth, inclination
274
+ return qb
457
275
 
458
276
  def _get_bloch_angles(self, hq):
459
277
  sim = self.sim[hq[0]].clone()
@@ -480,9 +298,7 @@ class QrackAceBackend:
480
298
 
481
299
  return azimuth, inclination
482
300
 
483
- def _rotate_to_bloch(
484
- self, hq, delta_azimuth, delta_inclination
485
- ):
301
+ def _rotate_to_bloch(self, hq, delta_azimuth, delta_inclination):
486
302
  sim = self.sim[hq[0]]
487
303
  q = hq[1]
488
304
 
@@ -499,142 +315,112 @@ class QrackAceBackend:
499
315
 
500
316
  sim.mtrx([m00, m01, m10, m11], q)
501
317
 
502
-
503
- def _rotate_lhv_to_bloch(
504
- self, sim, delta_azimuth, delta_inclination
505
- ):
506
- # Apply rotation as "Azimuth, Inclination" (AI)
507
- cosA = math.cos(delta_azimuth)
508
- sinA = math.sin(delta_azimuth)
509
- cosI = math.cos(delta_inclination / 2)
510
- sinI = math.sin(delta_inclination / 2)
511
-
512
- m00 = complex(cosI, 0)
513
- m01 = complex(-cosA, sinA) * sinI
514
- m10 = complex(cosA, sinA) * sinI
515
- m11 = complex(cosI, 0)
516
-
517
- sim.mtrx([m00, m01, m10, m11])
518
-
519
-
520
318
  def _correct(self, lq, phase=False, skip_rotation=False):
521
319
  hq = self._unpack(lq)
522
320
 
523
321
  if len(hq) == 1:
524
322
  return
525
323
 
526
- qb, lhv = self._get_qb_lhv_indices(hq)
324
+ qb = self._get_qb_indices(hq)
527
325
 
528
326
  if phase:
529
327
  for q in qb:
530
328
  b = hq[q]
531
329
  self.sim[b[0]].h(b[1])
532
- b = hq[lhv]
533
- b.h()
534
330
 
535
331
  if len(hq) == 5:
536
332
  # RMS
537
333
  p = [
538
334
  self.sim[hq[0][0]].prob(hq[0][1]),
539
335
  self.sim[hq[1][0]].prob(hq[1][1]),
540
- hq[2].prob(),
336
+ self.sim[hq[2][0]].prob(hq[2][1]),
541
337
  self.sim[hq[3][0]].prob(hq[3][1]),
542
- self.sim[hq[4][0]].prob(hq[4][1]),
543
338
  ]
544
339
  # Balancing suggestion from Elara (the custom OpenAI GPT)
545
- prms = math.sqrt(
546
- (p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
547
- )
340
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
548
341
  qrms = math.sqrt(
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
342
+ ((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
343
+ / 4
557
344
  )
558
345
  result = ((prms + (1 - qrms)) / 2) >= 0.5
559
346
  syndrome = (
560
- [1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3], 1 - p[4]]
347
+ [1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3]]
561
348
  if result
562
- else [p[0], p[1], p[2], p[3], p[4]]
349
+ else [p[0], p[1], p[2], p[3]]
563
350
  )
564
- for q in range(5):
351
+ for q in range(4):
565
352
  if syndrome[q] > (0.5 + self._epsilon):
566
- if q == 2:
567
- hq[q].x()
568
- else:
569
- self.sim[hq[q][0]].x(hq[q][1])
353
+ self.sim[hq[q][0]].x(hq[q][1])
570
354
 
571
355
  if not skip_rotation:
572
- a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
356
+ a, i = [0, 0, 0, 0], [0, 0, 0, 0]
573
357
  a[0], i[0] = self._get_bloch_angles(hq[0])
574
358
  a[1], i[1] = self._get_bloch_angles(hq[1])
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])
359
+ a[2], i[2] = self._get_bloch_angles(hq[3])
360
+ a[3], i[3] = self._get_bloch_angles(hq[4])
578
361
 
579
362
  a_target = 0
580
363
  i_target = 0
581
- for x in range(5):
364
+ for x in range(4):
582
365
  a_target += a[x]
583
366
  i_target += i[x]
584
367
 
585
- a_target /= 5
586
- i_target /= 5
587
- for x in range(5):
588
- if x == 2:
589
- self._rotate_lhv_to_bloch(hq[x], a_target - a[x], i_target - i[x])
590
- else:
591
- self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
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)
592
374
 
593
375
  else:
594
376
  # RMS
595
377
  p = [
596
378
  self.sim[hq[0][0]].prob(hq[0][1]),
597
379
  self.sim[hq[1][0]].prob(hq[1][1]),
598
- hq[2].prob(),
599
380
  ]
600
381
  # Balancing suggestion from Elara (the custom OpenAI GPT)
601
- prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
602
- qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
382
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
383
+ qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
603
384
  result = ((prms + (1 - qrms)) / 2) >= 0.5
604
- syndrome = [1 - p[0], 1 - p[1], 1 - p[2]] if result else [p[0], p[1], p[2]]
605
- for q in range(3):
385
+ syndrome = [1 - p[0], 1 - p[1]] if result else [p[0], p[1]]
386
+ for q in range(2):
606
387
  if syndrome[q] > (0.5 + self._epsilon):
607
- if q == 2:
608
- hq[q].x()
609
- else:
610
- self.sim[hq[q][0]].x(hq[q][1])
388
+ self.sim[hq[q][0]].x(hq[q][1])
611
389
 
612
390
  if not skip_rotation:
613
- a, i = [0, 0, 0], [0, 0, 0]
391
+ a, i = [0, 0], [0, 0]
614
392
  a[0], i[0] = self._get_bloch_angles(hq[0])
615
393
  a[1], i[1] = self._get_bloch_angles(hq[1])
616
- a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
617
394
 
618
395
  a_target = 0
619
396
  i_target = 0
620
- for x in range(3):
397
+ for x in range(2):
621
398
  a_target += a[x]
622
399
  i_target += i[x]
623
400
 
624
- a_target /= 3
625
- i_target /= 3
626
- for x in range(3):
627
- if x == 2:
628
- self._rotate_lhv_to_bloch(hq[x], a_target - a[x], i_target - i[x])
629
- else:
630
- self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
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)
631
407
 
632
408
  if phase:
633
409
  for q in qb:
634
410
  b = hq[q]
635
411
  self.sim[b[0]].h(b[1])
636
- b = hq[lhv]
637
- b.h()
412
+
413
+ def apply_magnetic_bias(self, q, b):
414
+ if b == 0:
415
+ return
416
+ b = math.exp(b)
417
+ for x in q:
418
+ 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
+ )
638
424
 
639
425
  def u(self, lq, th, ph, lm):
640
426
  hq = self._unpack(lq)
@@ -643,15 +429,12 @@ class QrackAceBackend:
643
429
  self.sim[b[0]].u(b[1], th, ph, lm)
644
430
  return
645
431
 
646
- qb, lhv = self._get_qb_lhv_indices(hq)
432
+ qb = self._get_qb_indices(hq)
647
433
 
648
434
  for q in qb:
649
435
  b = hq[q]
650
436
  self.sim[b[0]].u(b[1], th, ph, lm)
651
437
 
652
- b = hq[lhv]
653
- b.u(th, ph, lm)
654
-
655
438
  self._correct(lq, False, True)
656
439
  self._correct(lq, True, False)
657
440
 
@@ -662,20 +445,12 @@ class QrackAceBackend:
662
445
  self.sim[b[0]].r(p, th, b[1])
663
446
  return
664
447
 
665
- qb, lhv = self._get_qb_lhv_indices(hq)
448
+ qb = self._get_qb_indices(hq)
666
449
 
667
450
  for q in qb:
668
451
  b = hq[q]
669
452
  self.sim[b[0]].r(p, th, b[1])
670
453
 
671
- b = hq[lhv]
672
- if p == Pauli.PauliX:
673
- b.rx(th)
674
- elif p == Pauli.PauliY:
675
- b.ry(th)
676
- elif p == Pauli.PauliZ:
677
- b.rz(th)
678
-
679
454
  if p != Pauli.PauliZ:
680
455
  self._correct(lq, False, p != Pauli.PauliX)
681
456
  if p != Pauli.PauliX:
@@ -690,15 +465,12 @@ class QrackAceBackend:
690
465
 
691
466
  self._correct(lq)
692
467
 
693
- qb, lhv = self._get_qb_lhv_indices(hq)
468
+ qb = self._get_qb_indices(hq)
694
469
 
695
470
  for q in qb:
696
471
  b = hq[q]
697
472
  self.sim[b[0]].h(b[1])
698
473
 
699
- b = hq[lhv]
700
- b.h()
701
-
702
474
  self._correct(lq)
703
475
 
704
476
  def s(self, lq):
@@ -708,15 +480,12 @@ class QrackAceBackend:
708
480
  self.sim[b[0]].s(b[1])
709
481
  return
710
482
 
711
- qb, lhv = self._get_qb_lhv_indices(hq)
483
+ qb = self._get_qb_indices(hq)
712
484
 
713
485
  for q in qb:
714
486
  b = hq[q]
715
487
  self.sim[b[0]].s(b[1])
716
488
 
717
- b = hq[lhv]
718
- b.s()
719
-
720
489
  def adjs(self, lq):
721
490
  hq = self._unpack(lq)
722
491
  if len(hq) < 2:
@@ -724,15 +493,12 @@ class QrackAceBackend:
724
493
  self.sim[b[0]].adjs(b[1])
725
494
  return
726
495
 
727
- qb, lhv = self._get_qb_lhv_indices(hq)
496
+ qb = self._get_qb_indices(hq)
728
497
 
729
498
  for q in qb:
730
499
  b = hq[q]
731
500
  self.sim[b[0]].adjs(b[1])
732
501
 
733
- b = hq[lhv]
734
- b.adjs()
735
-
736
502
  def x(self, lq):
737
503
  hq = self._unpack(lq)
738
504
  if len(hq) < 2:
@@ -740,15 +506,12 @@ class QrackAceBackend:
740
506
  self.sim[b[0]].x(b[1])
741
507
  return
742
508
 
743
- qb, lhv = self._get_qb_lhv_indices(hq)
509
+ qb = self._get_qb_indices(hq)
744
510
 
745
511
  for q in qb:
746
512
  b = hq[q]
747
513
  self.sim[b[0]].x(b[1])
748
514
 
749
- b = hq[lhv]
750
- b.x()
751
-
752
515
  def y(self, lq):
753
516
  hq = self._unpack(lq)
754
517
  if len(hq) < 2:
@@ -756,15 +519,12 @@ class QrackAceBackend:
756
519
  self.sim[b[0]].y(b[1])
757
520
  return
758
521
 
759
- qb, lhv = self._get_qb_lhv_indices(hq)
522
+ qb = self._get_qb_indices(hq)
760
523
 
761
524
  for q in qb:
762
525
  b = hq[q]
763
526
  self.sim[b[0]].y(b[1])
764
527
 
765
- b = hq[lhv]
766
- b.y()
767
-
768
528
  def z(self, lq):
769
529
  hq = self._unpack(lq)
770
530
  if len(hq) < 2:
@@ -772,15 +532,12 @@ class QrackAceBackend:
772
532
  self.sim[b[0]].z(b[1])
773
533
  return
774
534
 
775
- qb, lhv = self._get_qb_lhv_indices(hq)
535
+ qb = self._get_qb_indices(hq)
776
536
 
777
537
  for q in qb:
778
538
  b = hq[q]
779
539
  self.sim[b[0]].z(b[1])
780
540
 
781
- b = hq[lhv]
782
- b.z()
783
-
784
541
  def t(self, lq):
785
542
  hq = self._unpack(lq)
786
543
  if len(hq) < 2:
@@ -788,15 +545,12 @@ class QrackAceBackend:
788
545
  self.sim[b[0]].t(b[1])
789
546
  return
790
547
 
791
- qb, lhv = self._get_qb_lhv_indices(hq)
548
+ qb = self._get_qb_indices(hq)
792
549
 
793
550
  for q in qb:
794
551
  b = hq[q]
795
552
  self.sim[b[0]].t(b[1])
796
553
 
797
- b = hq[lhv]
798
- b.t()
799
-
800
554
  def adjt(self, lq):
801
555
  hq = self._unpack(lq)
802
556
  if len(hq) < 2:
@@ -804,15 +558,12 @@ class QrackAceBackend:
804
558
  self.sim[b[0]].adjt(b[1])
805
559
  return
806
560
 
807
- qb, lhv = self._get_qb_lhv_indices(hq)
561
+ qb = self._get_qb_indices(hq)
808
562
 
809
563
  for q in qb:
810
564
  b = hq[q]
811
565
  self.sim[b[0]].adjt(b[1])
812
566
 
813
- b = hq[lhv]
814
- b.adjt()
815
-
816
567
  def _get_gate(self, pauli, anti, sim_id):
817
568
  gate = None
818
569
  shadow = None
@@ -853,15 +604,11 @@ class QrackAceBackend:
853
604
 
854
605
  return connected, boundary
855
606
 
856
- def _apply_coupling(self, pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr):
607
+ def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr):
857
608
  for q1 in qb1:
858
- if q1 == lhv1:
859
- continue
860
609
  b1 = hq1[q1]
861
610
  gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
862
611
  for q2 in qb2:
863
- if q2 == lhv2:
864
- continue
865
612
  b2 = hq2[q2]
866
613
  if b1[0] == b2[0]:
867
614
  gate_fn([b1[1]], b2[1])
@@ -886,18 +633,10 @@ class QrackAceBackend:
886
633
 
887
634
  self._correct(lq1)
888
635
 
889
- qb1, lhv1 = self._get_qb_lhv_indices(hq1)
890
- qb2, lhv2 = self._get_qb_lhv_indices(hq2)
636
+ qb1 = self._get_qb_indices(hq1)
637
+ qb2 = self._get_qb_indices(hq2)
891
638
  # Apply cross coupling on hardware qubits first
892
- self._apply_coupling(pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr)
893
- # Apply coupling to the local-hidden-variable target
894
- if lhv2 >= 0:
895
- _cpauli_lhv(
896
- hq1[lhv1].prob() if lhv1 >= 0 else self.sim[hq1[0][0]].prob(hq1[0][1]),
897
- hq2[lhv2],
898
- pauli,
899
- anti,
900
- )
639
+ self._apply_coupling(pauli, anti, qb1, hq1, qb2, hq2, lq1_lr)
901
640
 
902
641
  self._correct(lq1, True)
903
642
  if pauli != Pauli.PauliZ:
@@ -999,29 +738,20 @@ class QrackAceBackend:
999
738
  self.sim[hq[4][0]].prob(hq[4][1]),
1000
739
  ]
1001
740
  # Balancing suggestion from Elara (the custom OpenAI GPT)
1002
- prms = math.sqrt(
1003
- (p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
1004
- )
741
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
1005
742
  qrms = math.sqrt(
1006
- (
1007
- (1 - p[0]) ** 2
1008
- + (1 - p[1]) ** 2
1009
- + 3 * ((1 - p[2]) ** 2)
1010
- + (1 - p[3]) ** 2
1011
- + (1 - p[4]) ** 2
1012
- )
1013
- / 7
743
+ ((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
744
+ / 4
1014
745
  )
1015
746
  else:
1016
747
  # RMS
1017
748
  p = [
1018
749
  self.sim[hq[0][0]].prob(hq[0][1]),
1019
750
  self.sim[hq[1][0]].prob(hq[1][1]),
1020
- hq[2].prob(),
1021
751
  ]
1022
752
  # Balancing suggestion from Elara (the custom OpenAI GPT)
1023
- prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
1024
- qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
753
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
754
+ qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
1025
755
 
1026
756
  return (prms + (1 - qrms)) / 2
1027
757
 
@@ -1034,7 +764,7 @@ class QrackAceBackend:
1034
764
  p = self.prob(lq)
1035
765
  result = ((p + self._epsilon) >= 1) or (random.random() < p)
1036
766
 
1037
- qb, lhv = self._get_qb_lhv_indices(hq)
767
+ qb = self._get_qb_indices(hq)
1038
768
 
1039
769
  for q in qb:
1040
770
  b = hq[q]
@@ -1045,11 +775,6 @@ class QrackAceBackend:
1045
775
  else:
1046
776
  self.sim[b[0]].force_m(b[1], result)
1047
777
 
1048
- b = hq[lhv]
1049
- b.reset()
1050
- if result:
1051
- b.x()
1052
-
1053
778
  return result
1054
779
 
1055
780
  def force_m(self, lq, result):
@@ -1060,7 +785,7 @@ class QrackAceBackend:
1060
785
 
1061
786
  self._correct(lq)
1062
787
 
1063
- qb, lhv = self._get_qb_lhv_indices(hq)
788
+ qb = self._get_qb_indices(hq)
1064
789
 
1065
790
  for q in qb:
1066
791
  b = hq[q]
@@ -1071,11 +796,6 @@ class QrackAceBackend:
1071
796
  else:
1072
797
  self.sim[b[0]].force_m(b[1], result)
1073
798
 
1074
- b = hq[1]
1075
- b.reset()
1076
- if result:
1077
- b.x()
1078
-
1079
799
  return c
1080
800
 
1081
801
  def m_all(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyqrack-cpu
3
- Version: 1.61.2
3
+ Version: 1.62.0
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -1,7 +1,7 @@
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=x1s_I_YijLsKkhkQPWZUUQNHiJom_uTjGFoqz1cgDQQ,48358
4
+ pyqrack/qrack_ace_backend.py,sha256=SLmRwJmUAzV0BWoZJFskMYl21Kg9VXjQnoaAb4g6eDk,40334
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
@@ -16,8 +16,8 @@ pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.dylib,sha256=Cdb_wa2cG_V5lzswBH4
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_cpu-1.61.2.dist-info/LICENSE,sha256=HxB-7SaWTuewAk1nz-3_3FUD6QhgX73kNT_taKVUTq8,1069
20
- pyqrack_cpu-1.61.2.dist-info/METADATA,sha256=BzwhQQ7tAt2oQ4IqtDrLcmbP00EybPVvg690dg7mhIg,5951
21
- pyqrack_cpu-1.61.2.dist-info/WHEEL,sha256=nZx8s83OrgdDmpcWX-8FgI0sEAjdQimt4SdYsdcCaC8,107
22
- pyqrack_cpu-1.61.2.dist-info/top_level.txt,sha256=YE_3q9JTGRLMilNg2tGP1y7uU-Dx8PDao2OhwoIbv8E,8
23
- pyqrack_cpu-1.61.2.dist-info/RECORD,,
19
+ pyqrack_cpu-1.62.0.dist-info/LICENSE,sha256=HxB-7SaWTuewAk1nz-3_3FUD6QhgX73kNT_taKVUTq8,1069
20
+ pyqrack_cpu-1.62.0.dist-info/METADATA,sha256=kB4_IY4ehAucLdHDSPAQg0hsrmN_Ygx15kD3xqqJ3Ig,5951
21
+ pyqrack_cpu-1.62.0.dist-info/WHEEL,sha256=nZx8s83OrgdDmpcWX-8FgI0sEAjdQimt4SdYsdcCaC8,107
22
+ pyqrack_cpu-1.62.0.dist-info/top_level.txt,sha256=YE_3q9JTGRLMilNg2tGP1y7uU-Dx8PDao2OhwoIbv8E,8
23
+ pyqrack_cpu-1.62.0.dist-info/RECORD,,