pyqrack-complex128 2.22.2__tar.gz → 2.22.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.
Files changed (30) hide show
  1. {pyqrack_complex128-2.22.2/pyqrack_complex128.egg-info → pyqrack_complex128-2.22.3}/PKG-INFO +1 -1
  2. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_ace_backend.py +77 -31
  3. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3/pyqrack_complex128.egg-info}/PKG-INFO +1 -1
  4. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/setup.py +1 -1
  5. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/LICENSE +0 -0
  6. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/MANIFEST.in +0 -0
  7. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/Makefile +0 -0
  8. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/README.md +0 -0
  9. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyproject.toml +0 -0
  10. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/__init__.py +0 -0
  11. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/neuron_activation_fn.py +0 -0
  12. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/pauli.py +0 -0
  13. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_circuit.py +0 -0
  14. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
  15. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_neuron.py +0 -0
  16. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  17. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_simulator.py +0 -0
  18. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_stabilizer.py +0 -0
  19. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_system/__init__.py +0 -0
  20. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/qrack_system/qrack_system.py +0 -0
  21. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/quimb_circuit_type.py +0 -0
  22. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/stats/__init__.py +0 -0
  23. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/stats/load_quantized_data.py +0 -0
  24. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack/stats/quantize_by_range.py +0 -0
  25. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack_complex128.egg-info/SOURCES.txt +0 -0
  26. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack_complex128.egg-info/dependency_links.txt +0 -0
  27. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack_complex128.egg-info/not-zip-safe +0 -0
  28. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack_complex128.egg-info/requires.txt +0 -0
  29. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/pyqrack_complex128.egg-info/top_level.txt +0 -0
  30. {pyqrack_complex128-2.22.2 → pyqrack_complex128-2.22.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-complex128
3
- Version: 2.22.2
3
+ Version: 2.22.3
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -1552,7 +1552,7 @@ class QrackAceBackend:
1552
1552
  # this gate family only -- same reasoning as the earlier
1553
1553
  # single-replica CZ dual-check, just applied at the logical
1554
1554
  # level now.
1555
- anc1, anc2, anc1b = None, None, None
1555
+ anc1, anc2, anc1b, anc1c = None, None, None, None
1556
1556
  if self.is_error_detection and not self._in_gadget_capture and ((len(hq1) > 1) or (len(hq2) > 1)):
1557
1557
  anc1 = self._detect_ancilla1_lq[hq1[0][0]]
1558
1558
  self._in_gadget_capture = True
@@ -1564,6 +1564,23 @@ class QrackAceBackend:
1564
1564
  # Control bit-flip
1565
1565
  self.cx(lq1, anc1b)
1566
1566
 
1567
+ # Third participant: hq1 is a boundary qubit here
1568
+ # (len(hq1) > 1), so it always carries a genuine physical
1569
+ # replica in the shared boundary "crossbar" simulator too
1570
+ # -- index 2 of its replica list, by construction (see
1571
+ # __init__'s qubit-building loop: the crossbar replica is
1572
+ # always appended right after the (up to two) patch
1573
+ # replicas, for every boundary qubit, edge or corner
1574
+ # alike). That replica was never checked by this gadget
1575
+ # before now, even though it's a distinct physical copy
1576
+ # of lq1's value -- give it its own dedicated ancilla,
1577
+ # already allocated in the crossbar sim alongside every
1578
+ # other simulator's pair, and capture lq1 through it the
1579
+ # same nested-cx way as anc1/anc1b, so it can vote
1580
+ # alongside them below instead of going unchecked.
1581
+ anc1c = self._detect_ancilla1_lq[hq1[2][0]]
1582
+ self.cx(lq1, anc1c)
1583
+
1567
1584
  anc2 = self._detect_ancilla2_lq[hq1[0][0]]
1568
1585
  # XOR on target
1569
1586
  self.cx(lq2, anc2)
@@ -1645,38 +1662,67 @@ class QrackAceBackend:
1645
1662
  # probability), reset the ancilla back to |0>, and apply
1646
1663
  # a corrective X to lq1 to restore the detected
1647
1664
  # invariant.
1648
- if anc1b is not None:
1649
- self.cx(lq1, anc1b)
1650
- anc_sim, anc_idx = self._qubits[anc1][0]
1651
- p1 = self.sim[anc_sim].prob(anc_idx)
1652
- anc_sim, anc_idx = self._qubits[anc1b][0]
1653
- p2 = self.sim[anc_sim].prob(anc_idx)
1654
- if self._ps_epsilon >= (1.0 - p1):
1655
- b1 = self.force_m(anc1, True)
1656
- if self._ps_epsilon >= p2:
1657
- b2 = self.force_m(anc1b, True)
1658
- else:
1659
- b2 = self.m(anc1b)
1660
- elif self._ps_epsilon >= (1.0 - p2):
1661
- b2 = self.force_m(anc1b, True)
1662
- if self._ps_epsilon >= p1:
1663
- b1 = self.force_m(anc1, True)
1664
- else:
1665
- b1 = self.m(anc1)
1665
+ if (anc1b is not None) or (anc1c is not None):
1666
+ # Generalized N-way version (N = 2 or 3, i.e. patch A and
1667
+ # patch B and/or the crossbar's own replica) of the
1668
+ # single-pair steering above: same per-participant rule,
1669
+ # just no longer hand-written per pair. Read every
1670
+ # participant's prob() BEFORE forcing any of them (a
1671
+ # forced measurement can affect correlated others), find
1672
+ # whichever one -- if any -- shows confident (within
1673
+ # ps_epsilon of certain) evidence of an actual flip, force
1674
+ # THAT one first (the branch its own probability actually
1675
+ # supports, never the near-impossible one), then for each
1676
+ # remaining participant either steer it to agree (force
1677
+ # True) if its own signal is too close to the hard-zero
1678
+ # boundary to trust as an honest independent reading, or
1679
+ # let it measure honestly otherwise -- exactly the same
1680
+ # judgment call the original single anc1b case made, now
1681
+ # just applied per-participant in a loop. If nobody shows
1682
+ # confident evidence of a flip, every participant is
1683
+ # forced to the "no error" branch, as before.
1684
+ ancs = [anc1] + ([anc1b] if anc1b is not None else []) + ([anc1c] if anc1c is not None else [])
1685
+ # Complete each participant's before/after XOR capture
1686
+ # (anc1's own second cx() already happened just above,
1687
+ # unconditionally) before reading any prob() below.
1688
+ if anc1b is not None:
1689
+ self.cx(lq1, anc1b)
1690
+ if anc1c is not None:
1691
+ self.cx(lq1, anc1c)
1692
+ probs = []
1693
+ for a in ancs:
1694
+ anc_sim, anc_idx = self._qubits[a][0]
1695
+ probs.append(self.sim[anc_sim].prob(anc_idx))
1696
+
1697
+ anchor = None
1698
+ for i in range(len(ancs)):
1699
+ if self._ps_epsilon >= (1.0 - probs[i]):
1700
+ anchor = i
1701
+ break
1702
+
1703
+ bits = [None] * len(ancs)
1704
+ if anchor is not None:
1705
+ bits[anchor] = self.force_m(ancs[anchor], True)
1706
+ for i in range(len(ancs)):
1707
+ if i == anchor:
1708
+ continue
1709
+ if self._ps_epsilon >= probs[i]:
1710
+ bits[i] = self.force_m(ancs[i], True)
1711
+ else:
1712
+ bits[i] = self.m(ancs[i])
1666
1713
  else:
1667
- b1 = self.force_m(anc1, False)
1668
- b2 = self.force_m(anc1b, False)
1714
+ bits = [self.force_m(a, False) for a in ancs]
1715
+
1669
1716
  is_flipped = False
1670
- if b1:
1671
- self.x(anc1)
1672
- if p1 >= p2:
1673
- self.x(lq1)
1674
- is_flipped = True
1675
- if b2:
1676
- self.x(anc1b)
1677
- if (not is_flipped) and (p2 >= p1):
1678
- self.x(lq1)
1679
- is_flipped = True
1717
+ best_p = -1.0
1718
+ for i, a in enumerate(ancs):
1719
+ if bits[i]:
1720
+ self.x(a)
1721
+ if probs[i] > best_p:
1722
+ best_p = probs[i]
1723
+ if best_p >= 0.0:
1724
+ self.x(lq1)
1725
+ is_flipped = True
1680
1726
  else:
1681
1727
  anc_sim, anc_idx = self._qubits[anc1][0]
1682
1728
  p = self.sim[anc_sim].prob(anc_idx)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-complex128
3
- Version: 2.22.2
3
+ Version: 2.22.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 = "2.22.2"
10
+ VERSION = "2.22.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')