pyqrack-cpu 1.61.1__tar.gz → 1.61.3__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.

Potentially problematic release.


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

Files changed (29) hide show
  1. {pyqrack_cpu-1.61.1/pyqrack_cpu.egg-info → pyqrack_cpu-1.61.3}/PKG-INFO +1 -1
  2. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/qrack_ace_backend.py +51 -348
  3. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3/pyqrack_cpu.egg-info}/PKG-INFO +1 -1
  4. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/setup.py +1 -1
  5. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/LICENSE +0 -0
  6. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/MANIFEST.in +0 -0
  7. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/Makefile +0 -0
  8. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/README.md +0 -0
  9. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyproject.toml +0 -0
  10. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/__init__.py +0 -0
  11. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/neuron_activation_fn.py +0 -0
  12. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/pauli.py +0 -0
  13. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/qrack_circuit.py +0 -0
  14. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/qrack_neuron.py +0 -0
  15. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  16. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/qrack_simulator.py +0 -0
  17. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/qrack_stabilizer.py +0 -0
  18. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/qrack_system/__init__.py +0 -0
  19. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/qrack_system/qrack_system.py +0 -0
  20. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/quimb_circuit_type.py +0 -0
  21. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/stats/__init__.py +0 -0
  22. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/stats/load_quantized_data.py +0 -0
  23. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack/stats/quantize_by_range.py +0 -0
  24. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack_cpu.egg-info/SOURCES.txt +0 -0
  25. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack_cpu.egg-info/dependency_links.txt +0 -0
  26. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack_cpu.egg-info/not-zip-safe +0 -0
  27. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack_cpu.egg-info/requires.txt +0 -0
  28. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/pyqrack_cpu.egg-info/top_level.txt +0 -0
  29. {pyqrack_cpu-1.61.1 → pyqrack_cpu-1.61.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cpu
3
- Version: 1.61.1
3
+ Version: 1.61.3
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -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
 
@@ -287,14 +130,6 @@ class QrackAceBackend:
287
130
  qubit.append((t_sim_id, sim_counts[t_sim_id]))
288
131
  sim_counts[t_sim_id] += 1
289
132
 
290
- qubit.append(
291
- LHVQubit(
292
- toClone=(
293
- toClone._qubit_dict[tot_qubits][2] if toClone else None
294
- )
295
- )
296
- )
297
-
298
133
  if (not c) and (not r):
299
134
  t_sim_id = (sim_id + col_patch_count) % sim_count
300
135
  qubit.append((t_sim_id, sim_counts[t_sim_id]))
@@ -426,34 +261,16 @@ class QrackAceBackend:
426
261
  def _unpack(self, lq):
427
262
  return self._qubit_dict[lq]
428
263
 
429
- def _get_qb_lhv_indices(self, hq):
264
+ def _get_qb_indices(self, hq):
430
265
  qb = []
431
266
  if len(hq) < 2:
432
267
  qb = [0]
433
- lhv = -1
434
268
  elif len(hq) < 4:
435
269
  qb = [0, 1]
436
- lhv = 2
437
270
  else:
438
- qb = [0, 1, 3, 4]
439
- lhv = 2
440
-
441
- return qb, lhv
442
-
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)
271
+ qb = [0, 1, 2, 3]
452
272
 
453
- inclination = math.atan2(math.sqrt(x**2 + y**2), z)
454
- azimuth = math.atan2(y, x)
455
-
456
- return azimuth, inclination
273
+ return qb
457
274
 
458
275
  def _get_bloch_angles(self, hq):
459
276
  sim = self.sim[hq[0]].clone()
@@ -480,9 +297,7 @@ class QrackAceBackend:
480
297
 
481
298
  return azimuth, inclination
482
299
 
483
- def _rotate_to_bloch(
484
- self, hq, delta_azimuth, delta_inclination
485
- ):
300
+ def _rotate_to_bloch(self, hq, delta_azimuth, delta_inclination):
486
301
  sim = self.sim[hq[0]]
487
302
  q = hq[1]
488
303
 
@@ -499,142 +314,96 @@ class QrackAceBackend:
499
314
 
500
315
  sim.mtrx([m00, m01, m10, m11], q)
501
316
 
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
317
  def _correct(self, lq, phase=False, skip_rotation=False):
521
318
  hq = self._unpack(lq)
522
319
 
523
320
  if len(hq) == 1:
524
321
  return
525
322
 
526
- qb, lhv = self._get_qb_lhv_indices(hq)
323
+ qb = self._get_qb_indices(hq)
527
324
 
528
325
  if phase:
529
326
  for q in qb:
530
327
  b = hq[q]
531
328
  self.sim[b[0]].h(b[1])
532
- b = hq[lhv]
533
- b.h()
534
329
 
535
330
  if len(hq) == 5:
536
331
  # RMS
537
332
  p = [
538
333
  self.sim[hq[0][0]].prob(hq[0][1]),
539
334
  self.sim[hq[1][0]].prob(hq[1][1]),
540
- hq[2].prob(),
335
+ self.sim[hq[2][0]].prob(hq[2][1]),
541
336
  self.sim[hq[3][0]].prob(hq[3][1]),
542
- self.sim[hq[4][0]].prob(hq[4][1]),
543
337
  ]
544
338
  # 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
- )
339
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
548
340
  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
341
+ ((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
342
+ / 4
557
343
  )
558
344
  result = ((prms + (1 - qrms)) / 2) >= 0.5
559
345
  syndrome = (
560
- [1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3], 1 - p[4]]
346
+ [1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3]]
561
347
  if result
562
- else [p[0], p[1], p[2], p[3], p[4]]
348
+ else [p[0], p[1], p[2], p[3]]
563
349
  )
564
- for q in range(5):
350
+ for q in range(4):
565
351
  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])
352
+ self.sim[hq[q][0]].x(hq[q][1])
570
353
 
571
354
  if not skip_rotation:
572
355
  a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
573
356
  a[0], i[0] = self._get_bloch_angles(hq[0])
574
357
  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])
358
+ a[2], i[2] = self._get_bloch_angles(hq[3])
359
+ a[3], i[3] = self._get_bloch_angles(hq[4])
578
360
 
579
361
  a_target = 0
580
362
  i_target = 0
581
- for x in range(5):
363
+ for x in range(4):
582
364
  a_target += a[x]
583
365
  i_target += i[x]
584
366
 
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])
367
+ a_target /= 4
368
+ i_target /= 4
369
+ for x in range(4):
370
+ self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
592
371
 
593
372
  else:
594
373
  # RMS
595
374
  p = [
596
375
  self.sim[hq[0][0]].prob(hq[0][1]),
597
376
  self.sim[hq[1][0]].prob(hq[1][1]),
598
- hq[2].prob(),
599
377
  ]
600
378
  # 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)
379
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
380
+ qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
603
381
  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):
382
+ syndrome = [1 - p[0], 1 - p[1]] if result else [p[0], p[1]]
383
+ for q in range(2):
606
384
  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])
385
+ self.sim[hq[q][0]].x(hq[q][1])
611
386
 
612
387
  if not skip_rotation:
613
388
  a, i = [0, 0, 0], [0, 0, 0]
614
389
  a[0], i[0] = self._get_bloch_angles(hq[0])
615
390
  a[1], i[1] = self._get_bloch_angles(hq[1])
616
- a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
617
391
 
618
392
  a_target = 0
619
393
  i_target = 0
620
- for x in range(3):
394
+ for x in range(2):
621
395
  a_target += a[x]
622
396
  i_target += i[x]
623
397
 
624
- a_target /= 5
625
- i_target /= 5
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])
398
+ a_target /= 2
399
+ i_target /= 2
400
+ for x in range(2):
401
+ self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
631
402
 
632
403
  if phase:
633
404
  for q in qb:
634
405
  b = hq[q]
635
406
  self.sim[b[0]].h(b[1])
636
- b = hq[lhv]
637
- b.h()
638
407
 
639
408
  def u(self, lq, th, ph, lm):
640
409
  hq = self._unpack(lq)
@@ -643,15 +412,12 @@ class QrackAceBackend:
643
412
  self.sim[b[0]].u(b[1], th, ph, lm)
644
413
  return
645
414
 
646
- qb, lhv = self._get_qb_lhv_indices(hq)
415
+ qb = self._get_qb_indices(hq)
647
416
 
648
417
  for q in qb:
649
418
  b = hq[q]
650
419
  self.sim[b[0]].u(b[1], th, ph, lm)
651
420
 
652
- b = hq[lhv]
653
- b.u(th, ph, lm)
654
-
655
421
  self._correct(lq, False, True)
656
422
  self._correct(lq, True, False)
657
423
 
@@ -662,20 +428,12 @@ class QrackAceBackend:
662
428
  self.sim[b[0]].r(p, th, b[1])
663
429
  return
664
430
 
665
- qb, lhv = self._get_qb_lhv_indices(hq)
431
+ qb = self._get_qb_indices(hq)
666
432
 
667
433
  for q in qb:
668
434
  b = hq[q]
669
435
  self.sim[b[0]].r(p, th, b[1])
670
436
 
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
437
  if p != Pauli.PauliZ:
680
438
  self._correct(lq, False, p != Pauli.PauliX)
681
439
  if p != Pauli.PauliX:
@@ -690,15 +448,12 @@ class QrackAceBackend:
690
448
 
691
449
  self._correct(lq)
692
450
 
693
- qb, lhv = self._get_qb_lhv_indices(hq)
451
+ qb = self._get_qb_indices(hq)
694
452
 
695
453
  for q in qb:
696
454
  b = hq[q]
697
455
  self.sim[b[0]].h(b[1])
698
456
 
699
- b = hq[lhv]
700
- b.h()
701
-
702
457
  self._correct(lq)
703
458
 
704
459
  def s(self, lq):
@@ -708,15 +463,12 @@ class QrackAceBackend:
708
463
  self.sim[b[0]].s(b[1])
709
464
  return
710
465
 
711
- qb, lhv = self._get_qb_lhv_indices(hq)
466
+ qb = self._get_qb_indices(hq)
712
467
 
713
468
  for q in qb:
714
469
  b = hq[q]
715
470
  self.sim[b[0]].s(b[1])
716
471
 
717
- b = hq[lhv]
718
- b.s()
719
-
720
472
  def adjs(self, lq):
721
473
  hq = self._unpack(lq)
722
474
  if len(hq) < 2:
@@ -724,15 +476,12 @@ class QrackAceBackend:
724
476
  self.sim[b[0]].adjs(b[1])
725
477
  return
726
478
 
727
- qb, lhv = self._get_qb_lhv_indices(hq)
479
+ qb = self._get_qb_indices(hq)
728
480
 
729
481
  for q in qb:
730
482
  b = hq[q]
731
483
  self.sim[b[0]].adjs(b[1])
732
484
 
733
- b = hq[lhv]
734
- b.adjs()
735
-
736
485
  def x(self, lq):
737
486
  hq = self._unpack(lq)
738
487
  if len(hq) < 2:
@@ -740,15 +489,12 @@ class QrackAceBackend:
740
489
  self.sim[b[0]].x(b[1])
741
490
  return
742
491
 
743
- qb, lhv = self._get_qb_lhv_indices(hq)
492
+ qb = self._get_qb_indices(hq)
744
493
 
745
494
  for q in qb:
746
495
  b = hq[q]
747
496
  self.sim[b[0]].x(b[1])
748
497
 
749
- b = hq[lhv]
750
- b.x()
751
-
752
498
  def y(self, lq):
753
499
  hq = self._unpack(lq)
754
500
  if len(hq) < 2:
@@ -756,15 +502,12 @@ class QrackAceBackend:
756
502
  self.sim[b[0]].y(b[1])
757
503
  return
758
504
 
759
- qb, lhv = self._get_qb_lhv_indices(hq)
505
+ qb = self._get_qb_indices(hq)
760
506
 
761
507
  for q in qb:
762
508
  b = hq[q]
763
509
  self.sim[b[0]].y(b[1])
764
510
 
765
- b = hq[lhv]
766
- b.y()
767
-
768
511
  def z(self, lq):
769
512
  hq = self._unpack(lq)
770
513
  if len(hq) < 2:
@@ -772,15 +515,12 @@ class QrackAceBackend:
772
515
  self.sim[b[0]].z(b[1])
773
516
  return
774
517
 
775
- qb, lhv = self._get_qb_lhv_indices(hq)
518
+ qb = self._get_qb_indices(hq)
776
519
 
777
520
  for q in qb:
778
521
  b = hq[q]
779
522
  self.sim[b[0]].z(b[1])
780
523
 
781
- b = hq[lhv]
782
- b.z()
783
-
784
524
  def t(self, lq):
785
525
  hq = self._unpack(lq)
786
526
  if len(hq) < 2:
@@ -788,15 +528,12 @@ class QrackAceBackend:
788
528
  self.sim[b[0]].t(b[1])
789
529
  return
790
530
 
791
- qb, lhv = self._get_qb_lhv_indices(hq)
531
+ qb = self._get_qb_indices(hq)
792
532
 
793
533
  for q in qb:
794
534
  b = hq[q]
795
535
  self.sim[b[0]].t(b[1])
796
536
 
797
- b = hq[lhv]
798
- b.t()
799
-
800
537
  def adjt(self, lq):
801
538
  hq = self._unpack(lq)
802
539
  if len(hq) < 2:
@@ -804,15 +541,12 @@ class QrackAceBackend:
804
541
  self.sim[b[0]].adjt(b[1])
805
542
  return
806
543
 
807
- qb, lhv = self._get_qb_lhv_indices(hq)
544
+ qb = self._get_qb_indices(hq)
808
545
 
809
546
  for q in qb:
810
547
  b = hq[q]
811
548
  self.sim[b[0]].adjt(b[1])
812
549
 
813
- b = hq[lhv]
814
- b.adjt()
815
-
816
550
  def _get_gate(self, pauli, anti, sim_id):
817
551
  gate = None
818
552
  shadow = None
@@ -853,15 +587,11 @@ class QrackAceBackend:
853
587
 
854
588
  return connected, boundary
855
589
 
856
- def _apply_coupling(self, pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr):
590
+ def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr):
857
591
  for q1 in qb1:
858
- if q1 == lhv1:
859
- continue
860
592
  b1 = hq1[q1]
861
593
  gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
862
594
  for q2 in qb2:
863
- if q2 == lhv2:
864
- continue
865
595
  b2 = hq2[q2]
866
596
  if b1[0] == b2[0]:
867
597
  gate_fn([b1[1]], b2[1])
@@ -886,18 +616,10 @@ class QrackAceBackend:
886
616
 
887
617
  self._correct(lq1)
888
618
 
889
- qb1, lhv1 = self._get_qb_lhv_indices(hq1)
890
- qb2, lhv2 = self._get_qb_lhv_indices(hq2)
619
+ qb1 = self._get_qb_indices(hq1)
620
+ qb2 = self._get_qb_indices(hq2)
891
621
  # 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
- )
622
+ self._apply_coupling(pauli, anti, qb1, hq1, qb2, hq2, lq1_lr)
901
623
 
902
624
  self._correct(lq1, True)
903
625
  if pauli != Pauli.PauliZ:
@@ -999,29 +721,20 @@ class QrackAceBackend:
999
721
  self.sim[hq[4][0]].prob(hq[4][1]),
1000
722
  ]
1001
723
  # 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
- )
724
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2 + p[3] ** 2) / 4)
1005
725
  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
726
+ ((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2 + (1 - p[3]) ** 2)
727
+ / 4
1014
728
  )
1015
729
  else:
1016
730
  # RMS
1017
731
  p = [
1018
732
  self.sim[hq[0][0]].prob(hq[0][1]),
1019
733
  self.sim[hq[1][0]].prob(hq[1][1]),
1020
- hq[2].prob(),
1021
734
  ]
1022
735
  # 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)
736
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 3)
737
+ qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 3)
1025
738
 
1026
739
  return (prms + (1 - qrms)) / 2
1027
740
 
@@ -1034,7 +747,7 @@ class QrackAceBackend:
1034
747
  p = self.prob(lq)
1035
748
  result = ((p + self._epsilon) >= 1) or (random.random() < p)
1036
749
 
1037
- qb, lhv = self._get_qb_lhv_indices(hq)
750
+ qb = self._get_qb_indices(hq)
1038
751
 
1039
752
  for q in qb:
1040
753
  b = hq[q]
@@ -1045,11 +758,6 @@ class QrackAceBackend:
1045
758
  else:
1046
759
  self.sim[b[0]].force_m(b[1], result)
1047
760
 
1048
- b = hq[lhv]
1049
- b.reset()
1050
- if result:
1051
- b.x()
1052
-
1053
761
  return result
1054
762
 
1055
763
  def force_m(self, lq, result):
@@ -1060,7 +768,7 @@ class QrackAceBackend:
1060
768
 
1061
769
  self._correct(lq)
1062
770
 
1063
- qb, lhv = self._get_qb_lhv_indices(hq)
771
+ qb = self._get_qb_indices(hq)
1064
772
 
1065
773
  for q in qb:
1066
774
  b = hq[q]
@@ -1071,11 +779,6 @@ class QrackAceBackend:
1071
779
  else:
1072
780
  self.sim[b[0]].force_m(b[1], result)
1073
781
 
1074
- b = hq[1]
1075
- b.reset()
1076
- if result:
1077
- b.x()
1078
-
1079
782
  return c
1080
783
 
1081
784
  def m_all(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cpu
3
- Version: 1.61.1
3
+ Version: 1.61.3
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.61.1"
10
+ VERSION = "1.61.3"
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