pyqrack-complex128 2.26.0__tar.gz → 2.26.2__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.26.0/pyqrack_complex128.egg-info → pyqrack_complex128-2.26.2}/PKG-INFO +1 -1
  2. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_ace_backend.py +52 -47
  3. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2/pyqrack_complex128.egg-info}/PKG-INFO +1 -1
  4. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/setup.py +1 -1
  5. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/LICENSE +0 -0
  6. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/MANIFEST.in +0 -0
  7. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/Makefile +0 -0
  8. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/README.md +0 -0
  9. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyproject.toml +0 -0
  10. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/__init__.py +0 -0
  11. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/neuron_activation_fn.py +0 -0
  12. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/pauli.py +0 -0
  13. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_circuit.py +0 -0
  14. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
  15. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_neuron.py +0 -0
  16. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  17. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_simulator.py +0 -0
  18. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_stabilizer.py +0 -0
  19. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_system/__init__.py +0 -0
  20. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/qrack_system/qrack_system.py +0 -0
  21. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/quimb_circuit_type.py +0 -0
  22. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/stats/__init__.py +0 -0
  23. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/stats/load_quantized_data.py +0 -0
  24. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack/stats/quantize_by_range.py +0 -0
  25. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack_complex128.egg-info/SOURCES.txt +0 -0
  26. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack_complex128.egg-info/dependency_links.txt +0 -0
  27. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack_complex128.egg-info/not-zip-safe +0 -0
  28. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack_complex128.egg-info/requires.txt +0 -0
  29. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/pyqrack_complex128.egg-info/top_level.txt +0 -0
  30. {pyqrack_complex128-2.26.0 → pyqrack_complex128-2.26.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-complex128
3
- Version: 2.26.0
3
+ Version: 2.26.2
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -1384,6 +1384,15 @@ class QrackAceBackend:
1384
1384
  def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr, lq1=None, lq2=None):
1385
1385
  shadow_targets = []
1386
1386
 
1387
+ if len(hq1) == len(hq2) and all(hq1[i][0] == hq2[i][0] for i in range(len(hq1))):
1388
+ for i in range(len(hq1)):
1389
+ sim_id, idx1 = hq1[i]
1390
+ gate_fn, shadow_fn = self._get_gate(pauli, anti, sim_id)
1391
+ _, idx2 = hq2[i]
1392
+ self.sim[sim_id].swap(idx1, idx2)
1393
+ gate_fn([idx1], idx2)
1394
+ return
1395
+
1387
1396
  # Logical-level error-detection gadget: an earlier version of this
1388
1397
  # also captured lq1's own logical value into a dedicated ancilla
1389
1398
  # (via a nested cx()), on the theory that the shadow-coupling
@@ -1410,7 +1419,7 @@ class QrackAceBackend:
1410
1419
  # a lq2-invariant check for that gate family, same reasoning as
1411
1420
  # the single-replica CZ dual-check elsewhere.
1412
1421
  anc2 = None
1413
- if self.is_error_detection and not self._in_gadget_capture and (len(hq1) > 1):
1422
+ if self.is_error_detection and (not self._in_gadget_capture) and (len(hq2) > 1):
1414
1423
  anc_sim = hq1[0][0]
1415
1424
  t_sims = {y[0] for y in hq2 if y[0] >= 0}
1416
1425
  for x in hq1:
@@ -1810,42 +1819,6 @@ class QrackAceBackend:
1810
1819
  hq1 = self._unpack(lq1)
1811
1820
  hq2 = self._unpack(lq2)
1812
1821
 
1813
- sims1 = {r[0] for r in hq1}
1814
- sims2 = {r[0] for r in hq2}
1815
-
1816
- if sims1.isdisjoint(sims2):
1817
- self._correct(lq1)
1818
- self._correct(lq2)
1819
-
1820
- # Once fully resolved, the swap itself is nothing but a
1821
- # reference exchange: self._qubits[lq] is a reference to the
1822
- # replica-list object, so swapping which index points to
1823
- # which object IS the swap -- no separate content to copy.
1824
- self._qubits[lq1], self._qubits[lq2] = self._qubits[lq2], self._qubits[lq1]
1825
-
1826
- lhv1 = self._lhv.pop(lq1, None)
1827
- lhv2 = self._lhv.pop(lq2, None)
1828
- if lhv2 is not None:
1829
- self._lhv[lq1] = lhv2
1830
- if lhv1 is not None:
1831
- self._lhv[lq2] = lhv1
1832
-
1833
- # Boundary repetition code needs no bookkeeping here, unlike
1834
- # self._qubits/self._lhv just above: it's on-demand now, not
1835
- # a permanent, per-logical-index dict of pre-allocated
1836
- # partners -- eligibility is just len(self._qubits[lq]) > 1,
1837
- # computed fresh on every coupling event, so the reference
1838
- # swap of self._qubits above already, automatically carries
1839
- # the right eligibility with it. Nothing else to move.
1840
- return
1841
-
1842
- # Boundary-to-boundary handling
1843
- if (len(hq1) > 1) and (len(hq2) > 1):
1844
- self.cx(lq1, lq2)
1845
- self.cx(lq2, lq1)
1846
- self.cx(lq1, lq2)
1847
- return
1848
-
1849
1822
  # Fast/exact path: every replica of lq1 lines up, position-for-
1850
1823
  # position, with the corresponding replica of lq2 on the SAME
1851
1824
  # underlying simulator. A native swap() there is pure index
@@ -1872,8 +1845,6 @@ class QrackAceBackend:
1872
1845
  # two sides can land on different simulators (the partial-match
1873
1846
  # branches below) needs separate, careful treatment -- not
1874
1847
  # reused as-is from _cpauli's helper.
1875
- self._correct(lq1)
1876
- self._correct(lq2)
1877
1848
 
1878
1849
  if len(hq1) == len(hq2) and all(hq1[i][0] == hq2[i][0] for i in range(len(hq1))):
1879
1850
  for i in range(len(hq1)):
@@ -1887,6 +1858,39 @@ class QrackAceBackend:
1887
1858
  # with or without this call).
1888
1859
  return
1889
1860
 
1861
+ sims1 = {r[0] for r in hq1}
1862
+ sims2 = {r[0] for r in hq2}
1863
+
1864
+ if sims1.isdisjoint(sims2):
1865
+ # Once fully resolved, the swap itself is nothing but a
1866
+ # reference exchange: self._qubits[lq] is a reference to the
1867
+ # replica-list object, so swapping which index points to
1868
+ # which object IS the swap -- no separate content to copy.
1869
+ self._qubits[lq1], self._qubits[lq2] = self._qubits[lq2], self._qubits[lq1]
1870
+
1871
+ lhv1 = self._lhv.pop(lq1, None)
1872
+ lhv2 = self._lhv.pop(lq2, None)
1873
+ if lhv2 is not None:
1874
+ self._lhv[lq1] = lhv2
1875
+ if lhv1 is not None:
1876
+ self._lhv[lq2] = lhv1
1877
+
1878
+ # Boundary repetition code needs no bookkeeping here, unlike
1879
+ # self._qubits/self._lhv just above: it's on-demand now, not
1880
+ # a permanent, per-logical-index dict of pre-allocated
1881
+ # partners -- eligibility is just len(self._qubits[lq]) > 1,
1882
+ # computed fresh on every coupling event, so the reference
1883
+ # swap of self._qubits above already, automatically carries
1884
+ # the right eligibility with it. Nothing else to move.
1885
+ return
1886
+
1887
+ # Boundary-to-boundary handling
1888
+ if (len(hq1) > 1) and (len(hq2) > 1):
1889
+ self.cx(lq1, lq2)
1890
+ self.cx(lq2, lq1)
1891
+ self.cx(lq1, lq2)
1892
+ return
1893
+
1890
1894
  anc1, anc2 = None, None
1891
1895
  if self.is_error_detection and not self._in_gadget_capture and ((len(hq1) > 1) or (len(hq2) > 1)):
1892
1896
  t_sims = {y[0] for y in hq2 if y[0] >= 0}
@@ -1902,6 +1906,9 @@ class QrackAceBackend:
1902
1906
  self.cx(lq2, anc2)
1903
1907
  self._in_gadget_capture = False
1904
1908
 
1909
+ self._correct(lq1)
1910
+ self._correct(lq2)
1911
+
1905
1912
  # Partial-match cases: one side is a simple (single-replica) qubit,
1906
1913
  # the other has multiple replicas. For the multi-replica side's
1907
1914
  # non-matching replicas, the correct decomposition (verified
@@ -2001,10 +2008,6 @@ class QrackAceBackend:
2001
2008
  self.mcx([c1, c2], t)
2002
2009
  return
2003
2010
 
2004
- if not self._in_gadget_capture:
2005
- self._correct(c1)
2006
- self._correct(c2)
2007
-
2008
2011
  # Control-protection ancillas (anc1/anc1b/anc2/anc2b, checking
2009
2012
  # whether c1/c2's own values held still) removed entirely, same
2010
2013
  # basis as _apply_coupling: instrumented and stress-tested
@@ -2028,7 +2031,7 @@ class QrackAceBackend:
2028
2031
  # bulk on this path (the len(hqt) > 1 case returns earlier,
2029
2032
  # above) and nothing else in this method uses that array anymore.
2030
2033
  anc_and = None
2031
- if self.is_error_detection and not self._in_gadget_capture and ((len(hq1) > 1) or (len(hq2) > 1) or (len(hqt) > 1)):
2034
+ if self.is_error_detection and not self._in_gadget_capture and (len(hqt) > 1):
2032
2035
  found = False
2033
2036
  anc_sim = hq1[0][0]
2034
2037
  t_sims = {y[0] for y in hqt if y[0] >= 0}
@@ -2070,6 +2073,9 @@ class QrackAceBackend:
2070
2073
  self.ccx(c1, c2, anc_and)
2071
2074
  self._in_gadget_capture = False
2072
2075
 
2076
+ self._correct(c1)
2077
+ self._correct(c2)
2078
+
2073
2079
  qb1, _ = QrackAceBackend._get_qb_lhv_indices(hq1)
2074
2080
  qb2, _ = QrackAceBackend._get_qb_lhv_indices(hq2)
2075
2081
  qbt, _ = QrackAceBackend._get_qb_lhv_indices(hqt)
@@ -2136,6 +2142,8 @@ class QrackAceBackend:
2136
2142
  for (b1, b2, bt) in witnesses:
2137
2143
  self.sim[b1[0]].mcx([b1[1], b2[1]], bt[1])
2138
2144
 
2145
+ self._correct(t)
2146
+
2139
2147
  self._in_gadget_capture = True
2140
2148
 
2141
2149
  if anc_and is not None:
@@ -2153,9 +2161,6 @@ class QrackAceBackend:
2153
2161
 
2154
2162
  self._in_gadget_capture = False
2155
2163
 
2156
- if not self._in_gadget_capture:
2157
- self._correct(t)
2158
-
2159
2164
  def ccz(self, c1, c2, t):
2160
2165
  self.h(t)
2161
2166
  self.ccx(c1, c2, t)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-complex128
3
- Version: 2.26.0
3
+ Version: 2.26.2
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.26.0"
10
+ VERSION = "2.26.2"
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')