pyqrack-cpu 2.18.3__tar.gz → 2.18.4__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 (33) hide show
  1. {pyqrack_cpu-2.18.3/pyqrack_cpu.egg-info → pyqrack_cpu-2.18.4}/PKG-INFO +1 -1
  2. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_ace_backend.py +63 -64
  3. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4/pyqrack_cpu.egg-info}/PKG-INFO +1 -1
  4. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack_cpu.egg-info/SOURCES.txt +0 -3
  5. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/setup.py +1 -1
  6. pyqrack_cpu-2.18.3/pyqrack/qrack_system/qrack_cl_precompile/qrack_cl_precompile +0 -0
  7. pyqrack_cpu-2.18.3/pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.so +0 -0
  8. pyqrack_cpu-2.18.3/pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.so.10.13.0 +0 -0
  9. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/LICENSE +0 -0
  10. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/MANIFEST.in +0 -0
  11. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/Makefile +0 -0
  12. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/README.md +0 -0
  13. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyproject.toml +0 -0
  14. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/__init__.py +0 -0
  15. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/neuron_activation_fn.py +0 -0
  16. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/pauli.py +0 -0
  17. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_circuit.py +0 -0
  18. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
  19. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_neuron.py +0 -0
  20. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  21. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_simulator.py +0 -0
  22. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_stabilizer.py +0 -0
  23. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_system/__init__.py +0 -0
  24. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/qrack_system/qrack_system.py +0 -0
  25. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/quimb_circuit_type.py +0 -0
  26. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/stats/__init__.py +0 -0
  27. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/stats/load_quantized_data.py +0 -0
  28. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack/stats/quantize_by_range.py +0 -0
  29. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack_cpu.egg-info/dependency_links.txt +0 -0
  30. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack_cpu.egg-info/not-zip-safe +0 -0
  31. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack_cpu.egg-info/requires.txt +0 -0
  32. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/pyqrack_cpu.egg-info/top_level.txt +0 -0
  33. {pyqrack_cpu-2.18.3 → pyqrack_cpu-2.18.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cpu
3
- Version: 2.18.3
3
+ Version: 2.18.4
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -1179,9 +1179,7 @@ class QrackAceBackend:
1179
1179
  self.sim[b[0]].h(b[1])
1180
1180
  return
1181
1181
 
1182
- self._correct(lq)
1183
1182
  skip = self._invalidate_for_gate(lq)
1184
-
1185
1183
  qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
1186
1184
 
1187
1185
  for q in qb:
@@ -1479,7 +1477,7 @@ class QrackAceBackend:
1479
1477
  # single-replica CZ dual-check, just applied at the logical
1480
1478
  # level now.
1481
1479
  anc1, anc2 = None, None
1482
- if self.is_error_detection and not self._in_gadget_capture:
1480
+ if self.is_error_detection and not self._in_gadget_capture and ((len(hq1) > 1) or (len(hq2) > 1)):
1483
1481
  anc1 = self._detect_ancilla1_lq[hq1[0][0]]
1484
1482
  self._in_gadget_capture = True
1485
1483
  # Control bit-flip
@@ -1639,7 +1637,7 @@ class QrackAceBackend:
1639
1637
  self._cpauli(lq1, lq2, False, Pauli.PauliX)
1640
1638
 
1641
1639
  def cy(self, lq1, lq2):
1642
- if self.is_error_detection:
1640
+ if self.is_error_detection and ((len(self._unpack(lq1)) > 1) or (len(self._unpack(lq2)) > 1)):
1643
1641
  self.adjs(lq2)
1644
1642
  self.cx(lq1, lq2)
1645
1643
  self.s(lq2)
@@ -1647,7 +1645,7 @@ class QrackAceBackend:
1647
1645
  self._cpauli(lq1, lq2, False, Pauli.PauliY)
1648
1646
 
1649
1647
  def cz(self, lq1, lq2):
1650
- if self.is_error_detection:
1648
+ if self.is_error_detection and ((len(self._unpack(lq1)) > 1) or (len(self._unpack(lq2)) > 1)):
1651
1649
  self.h(lq2)
1652
1650
  self.cx(lq1, lq2)
1653
1651
  self.h(lq2)
@@ -1658,7 +1656,7 @@ class QrackAceBackend:
1658
1656
  self._cpauli(lq1, lq2, True, Pauli.PauliX)
1659
1657
 
1660
1658
  def acy(self, lq1, lq2):
1661
- if self.is_error_detection:
1659
+ if self.is_error_detection and ((len(self._unpack(lq1)) > 1) or (len(self._unpack(lq2)) > 1)):
1662
1660
  self.adjs(lq2)
1663
1661
  self.acx(lq1, lq2)
1664
1662
  self.s(lq2)
@@ -1666,7 +1664,7 @@ class QrackAceBackend:
1666
1664
  self._cpauli(lq1, lq2, True, Pauli.PauliY)
1667
1665
 
1668
1666
  def acz(self, lq1, lq2):
1669
- if self.is_error_detection:
1667
+ if self.is_error_detection and ((len(self._unpack(lq1)) > 1) or (len(self._unpack(lq2)) > 1)):
1670
1668
  self.h(lq2)
1671
1669
  self.acx(lq1, lq2)
1672
1670
  self.h(lq2)
@@ -1811,7 +1809,7 @@ class QrackAceBackend:
1811
1809
  return
1812
1810
 
1813
1811
  anc1, anc2 = None, None
1814
- if self.is_error_detection and not self._in_gadget_capture:
1812
+ if self.is_error_detection and not self._in_gadget_capture and ((len(hq1) > 1) or (len(hq2) > 1)):
1815
1813
  if len(hq2) == 1:
1816
1814
  anc1 = self._detect_ancilla1_lq[hq1[0][0]]
1817
1815
  anc2 = self._detect_ancilla2_lq[hq1[0][0]]
@@ -2513,35 +2511,32 @@ class QrackAceBackend:
2513
2511
 
2514
2512
  coupling_map = self.get_logical_coupling_map()
2515
2513
 
2516
- # Error-detection damping (cx/cy/cz only -- see below for why not
2517
- # swap/iswap): a qubit only ever gets the gadget's benefit when it
2518
- # actually plays CONTROL in some real (u=0) gate somewhere in the
2519
- # coupling map -- that's what gives its replica a chance to be
2520
- # swept clean via _apply_coupling's capture-sandwich-force_m
2521
- # before any shadow decision reads its .prob(). This is a
2522
- # structural fact about each qubit individually, computed once
2523
- # here, not a property of the circuit or a global constant --
2524
- # which is exactly why this can't be reproduced by a user just
2525
- # passing a smaller x: x scales every pair uniformly, and this
2526
- # doesn't apply uniformly, either across qubits (only ones with a
2527
- # real-gate opportunity qualify) or across gate types (see below).
2528
- #
2529
- # Both sides of a real (u=0) pair get added, not just the control:
2530
- # CZ's own gadget check now covers its target too (CZ is diagonal
2531
- # -- unlike CX/CY, it never changes either qubit's Z-population,
2532
- # so the target is an equally valid invariance check there, see
2533
- # _apply_coupling). The coupling map doesn't distinguish which
2534
- # gate type a future circuit will actually use for a given pair,
2535
- # so this necessarily overstates the CX/CY case slightly (where
2536
- # only the control gets swept) -- an approximation on top of an
2537
- # already-approximate placeholder, not a new source of precision
2538
- # lost.
2539
- has_real_partner = set()
2540
- if self.is_error_detection:
2541
- for lq1, lq2 in coupling_map:
2542
- if _uncommon_sim_fraction(lq1, lq2) == 0:
2543
- has_real_partner.add(lq1)
2544
- has_real_partner.add(lq2)
2514
+ # Error-detection damping (cx/cy/cz; swap/iswap handled
2515
+ # separately below): the current gadget structurally requires
2516
+ # lq1 (== "a" for a given coupling_map entry, since a always
2517
+ # plays the control's role for that entry -- confirmed against
2518
+ # _cpauli's own convention) to be a multi-replica (boundary)
2519
+ # qubit -- see _cpauli: anc1 (the control-invariance capture) is
2520
+ # unconditional but structurally trivial for a single-replica
2521
+ # control (_correct() is already a no-op there, nothing for the
2522
+ # gadget to protect against), and anc2 (the target-value
2523
+ # verification against the CX/ACX-predicted output) is
2524
+ # explicitly gated on len(hq1) > 1. Both halves are gated the
2525
+ # same, simple way: whether a itself is boundary. This replaces
2526
+ # an older version keyed on _uncommon_sim_fraction(lq1,lq2)==0
2527
+ # ("does this pair share a simulator"), which matched an EARLIER
2528
+ # gadget that wrapped gate_fn alone and only ever ran on the
2529
+ # real (same-sim) branch -- that gadget was subsequently proven
2530
+ # a mathematically guaranteed no-op (gate_fn structurally never
2531
+ # touches its control's Z-value regardless of the control's
2532
+ # incoming state, verified directly to floating-point
2533
+ # precision) and replaced with the current mechanism, which
2534
+ # doesn't care whether a and b share a simulator at all: the
2535
+ # nested cx(lq1, anc) capture goes through the full logical
2536
+ # coupling machinery (shadow or real, whichever applies) and
2537
+ # works the same way regardless. So this is checked directly,
2538
+ # per pair, from len(self._qubits[a]) -- no precomputed set
2539
+ # needed.
2545
2540
 
2546
2541
  # This factor is a theory-derived placeholder, not an empirical
2547
2542
  # fit -- deliberately, per instruction not to chase a regression
@@ -2585,13 +2580,13 @@ class QrackAceBackend:
2585
2580
  # Pauli-string convention is big-endian relative to the qubit
2586
2581
  # list: the LAST qubit corresponds to the LEFTMOST character).
2587
2582
  p_shadow_ccz = 1 - sp * p
2588
- if a in has_real_partner:
2583
+ if self.is_error_detection and len(self._qubits[a]) > 1:
2589
2584
  # a is the control for this pair (_cpauli(lq1=a, lq2=b,
2590
- # ...) is always called with a as the coupling source),
2591
- # and a has at least one real-gate opportunity elsewhere
2592
- # in the map -- so its .prob() reading, which THIS
2593
- # shadow decision partly depends on, has a structural
2594
- # chance of having been kept clean. Damp accordingly.
2585
+ # ...) is always called with a as the coupling source).
2586
+ # Both gadget halves that protect this pair (anc1 on a,
2587
+ # anc2 verifying b) are structurally live exactly when a
2588
+ # itself is boundary -- see the comment above this loop.
2589
+ # Damp accordingly.
2595
2590
  p_shadow_ccz *= y
2596
2591
  noise_model.add_quantum_error(
2597
2592
  pauli_error([("ZI", p_shadow_ccz), ("II", 1 - p_shadow_ccz)]), "cz", [a, b]
@@ -2645,21 +2640,22 @@ class QrackAceBackend:
2645
2640
  # same condition to stay consistent with what the gate does.
2646
2641
  if (is_a_simple != is_b_simple) and has_match:
2647
2642
  p_net_swap = 2 * p * (1 - p)
2648
- # swap() now routes its own matching-replica gate through
2649
- # _detect_swap (a genuine same-simulator, parity-invariant
2650
- # gadget: idx1^idx2 is exactly conserved across a SWAP,
2651
- # the same way a CNOT's control is conserved -- see
2652
- # _detect_swap), so this IS damped now, unlike the stale
2653
- # "swap/iswap deliberately not damped" note this replaced.
2654
- # Gate on whichever side bears the error (the boundary
2655
- # qubit), using the same has_real_partner structural
2656
- # proxy as the cx/cy/cz case above -- the matching-replica
2657
- # branch needs the same "shares a simulator with
2658
- # something else" precondition _uncommon_sim_fraction==0
2659
- # already captures, so reusing that set here keeps this
2660
- # consistent rather than re-deriving a parallel condition.
2661
- boundary_qubit = b if is_a_simple else a
2662
- if boundary_qubit in has_real_partner:
2643
+ # swap()'s own anc1/anc2 cross-check (verifying lq1's new
2644
+ # value against lq2's old, and vice versa -- see swap())
2645
+ # wraps the ENTIRE call, every branch, not specifically
2646
+ # this matching-replica step -- _detect_swap itself is
2647
+ # just a plain swap(), carrying no gadget of its own
2648
+ # (an earlier per-replica parity gadget living there was
2649
+ # proven a mathematically guaranteed no-op, the same way
2650
+ # the old cx/cy/cz gadget was, and was simplified away).
2651
+ # So this IS damped, unlike the stale "swap/iswap
2652
+ # deliberately not damped" note this replaced -- but
2653
+ # unconditionally so, not gated on any structural
2654
+ # per-qubit condition: swap()'s gadget captures both
2655
+ # sides whenever is_error_detection is on, full stop, no
2656
+ # len(hq)>1-style precondition the way _cpauli's anc2
2657
+ # has.
2658
+ if self.is_error_detection:
2663
2659
  p_net_swap *= y
2664
2660
  if is_a_simple:
2665
2661
  # a is bulk, b is boundary -> error lands on b
@@ -2692,12 +2688,15 @@ class QrackAceBackend:
2692
2688
  # previous formula.
2693
2689
  if (is_a_simple != is_b_simple) and has_match:
2694
2690
  p_cz = 1 - sp * p # same per-call formula as standalone cz
2695
- if boundary_qubit in has_real_partner:
2696
- # this cz component is the SAME kind of shadow-driven
2697
- # term as the main cx/cy/cz loop above (see that
2698
- # comment for the mechanism); p_net_swap was already
2699
- # damped above, independently, since it comes from a
2700
- # different gate (the now-protected native swap, not
2691
+ if self.is_error_detection and len(self._qubits[a]) > 1:
2692
+ # this cz component is routed through cx() when
2693
+ # is_error_detection is on (see cz()'s own wrapper),
2694
+ # so it's the SAME kind of shadow-driven term, gated
2695
+ # the SAME way, as the main cx/cy/cz loop above (see
2696
+ # that comment for the mechanism); p_net_swap was
2697
+ # already damped above, independently, since it comes
2698
+ # from a different gate (the now-protected native
2699
+ # swap, not
2701
2700
  # this cz component).
2702
2701
  p_cz *= y
2703
2702
  p_i = (1 - p_net_swap) * (1 - p_cz)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cpu
3
- Version: 2.18.3
3
+ Version: 2.18.4
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -17,9 +17,6 @@ pyqrack/qrack_stabilizer.py
17
17
  pyqrack/quimb_circuit_type.py
18
18
  pyqrack/qrack_system/__init__.py
19
19
  pyqrack/qrack_system/qrack_system.py
20
- pyqrack/qrack_system/qrack_cl_precompile/qrack_cl_precompile
21
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.so
22
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.so.10.13.0
23
20
  pyqrack/stats/__init__.py
24
21
  pyqrack/stats/load_quantized_data.py
25
22
  pyqrack/stats/quantize_by_range.py
@@ -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.18.3"
10
+ VERSION = "2.18.4"
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