pyqrack-cpu 2.17.2__tar.gz → 2.18.0__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_cpu-2.17.2 → pyqrack_cpu-2.18.0}/Makefile +1 -1
  2. {pyqrack_cpu-2.17.2/pyqrack_cpu.egg-info → pyqrack_cpu-2.18.0}/PKG-INFO +1 -1
  3. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_ace_backend.py +77 -1
  4. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0/pyqrack_cpu.egg-info}/PKG-INFO +1 -1
  5. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/setup.py +1 -1
  6. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/LICENSE +0 -0
  7. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/MANIFEST.in +0 -0
  8. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/README.md +0 -0
  9. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyproject.toml +0 -0
  10. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/__init__.py +0 -0
  11. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/neuron_activation_fn.py +0 -0
  12. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/pauli.py +0 -0
  13. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_circuit.py +0 -0
  14. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
  15. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_neuron.py +0 -0
  16. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  17. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_simulator.py +0 -0
  18. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_stabilizer.py +0 -0
  19. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_system/__init__.py +0 -0
  20. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/qrack_system/qrack_system.py +0 -0
  21. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/quimb_circuit_type.py +0 -0
  22. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/stats/__init__.py +0 -0
  23. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/stats/load_quantized_data.py +0 -0
  24. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack/stats/quantize_by_range.py +0 -0
  25. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack_cpu.egg-info/SOURCES.txt +0 -0
  26. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack_cpu.egg-info/dependency_links.txt +0 -0
  27. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack_cpu.egg-info/not-zip-safe +0 -0
  28. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack_cpu.egg-info/requires.txt +0 -0
  29. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/pyqrack_cpu.egg-info/top_level.txt +0 -0
  30. {pyqrack_cpu-2.17.2 → pyqrack_cpu-2.18.0}/setup.cfg +0 -0
@@ -30,7 +30,7 @@ build-deps:
30
30
  rm -rf pyqrack/qrack_system/qrack_cl_precompile
31
31
  ifneq ($(OS),Windows_NT)
32
32
  ifeq ($(QRACK_PRESENT),)
33
- git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout d1e972b71cf426c678fb5bfa5ec1f3055d981b51; cd ..
33
+ git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout b51b54d8512cd3d57d0eb395556d40b14c35cc96; cd ..
34
34
  endif
35
35
  mkdir -p qrack/build
36
36
  ifeq ($(UNAME_S),Linux)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cpu
3
- Version: 2.17.2
3
+ Version: 2.18.0
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -242,6 +242,7 @@ class QrackAceBackend:
242
242
  history_window=0,
243
243
  is_torus=True,
244
244
  is_1d_chain=False,
245
+ is_error_detection=True,
245
246
  to_clone=None,
246
247
  ):
247
248
  if to_clone:
@@ -252,6 +253,7 @@ class QrackAceBackend:
252
253
  history_window = to_clone.history_window
253
254
  is_torus = to_clone.is_torus
254
255
  is_1d_chain = to_clone.is_1d_chain
256
+ is_error_detection = to_clone.is_error_detection
255
257
  if qubit_count < 0:
256
258
  qubit_count = 0
257
259
  if long_range_columns < 0:
@@ -266,6 +268,7 @@ class QrackAceBackend:
266
268
  self.is_transpose = is_transpose
267
269
  self.history_window = history_window
268
270
  self.is_torus = is_torus
271
+ self.is_error_detection = is_error_detection
269
272
 
270
273
  fppow = 5
271
274
  if "QRACK_FPPOW" in os.environ:
@@ -402,6 +405,20 @@ class QrackAceBackend:
402
405
  if has_boundary:
403
406
  sim_counts.append(boundary_count)
404
407
 
408
+ # Error-detection gadget (IBM-style detect-and-post-select, not
409
+ # correction): one shared ancilla per simulator -- every patch AND
410
+ # the boundary crossbar sim alike, "a single ancilla per patch,
411
+ # overall" -- reused across every real (same-simulator) coupling
412
+ # gate that touches it, never allocated per-gate or per-qubit.
413
+ # See _apply_coupling for the actual gadget; this block only does
414
+ # the qubit-index bookkeeping, in the same style as every other
415
+ # per-simulator allocation above.
416
+ self._detect_ancilla = []
417
+ if self.is_error_detection:
418
+ for i in range(len(sim_counts)):
419
+ self._detect_ancilla.append(sim_counts[i])
420
+ sim_counts[i] += 1
421
+
405
422
  if "QRACK_QUNIT_SEPARABILITY_THRESHOLD" in os.environ:
406
423
  self._sdrp = min(1, float(os.environ["QRACK_QUNIT_SEPARABILITY_THRESHOLD"]))
407
424
  else:
@@ -1397,7 +1414,48 @@ class QrackAceBackend:
1397
1414
  for q2 in qb2:
1398
1415
  b2 = hq2[q2]
1399
1416
  if b1[0] == b2[0]:
1400
- gate_fn([b1[1]], b2[1])
1417
+ if self.is_error_detection:
1418
+ # Error-DETECTION gadget (not correction), directly
1419
+ # post-selected via force_m rather than requiring
1420
+ # real repeated shots: b1 is always the CONTROL of
1421
+ # this gate (by construction -- gate_fn is always
1422
+ # called as gate_fn([b1[1]], b2[1])), and a
1423
+ # control's Z value is exactly invariant under a
1424
+ # controlled-Pauli gate in the noiseless case,
1425
+ # regardless of anti/regular control convention or
1426
+ # which Pauli. So: XOR b1's value into the patch's
1427
+ # shared ancilla immediately before the gate, XOR
1428
+ # it in again immediately after -- if nothing
1429
+ # disturbed b1 (no injected noise on the gate
1430
+ # itself or on either sandwiching CNOT), those two
1431
+ # XORs exactly cancel and the ancilla is back to
1432
+ # |0>. force_m(ancilla, False) then directly
1433
+ # projects the whole simulated state onto that
1434
+ # "no disturbance detected" branch and renormalizes
1435
+ # -- this is the exact numerical equivalent of what
1436
+ # a real experiment gets from measure + discard +
1437
+ # repeat, done in one step because the simulator
1438
+ # has the full state to project, not just samples
1439
+ # from it. The same ancilla is reused for every
1440
+ # gate touching this simulator: each round-trip is
1441
+ # self-contained and leaves the ancilla at |0>
1442
+ # again whenever nothing was detected, so there's
1443
+ # no cross-gate bookkeeping needed.
1444
+ #
1445
+ # Scope: this only covers the mcx/mcy/mcz path
1446
+ # (_cpauli / _apply_coupling). swap/iswap/pswap/etc.
1447
+ # exchange both qubits' values rather than leaving
1448
+ # either invariant, so this specific gadget doesn't
1449
+ # apply to them directly -- left as a documented
1450
+ # gap for a later pass, not silently unhandled.
1451
+ anc = self._detect_ancilla[b1[0]]
1452
+ sim = self.sim[b1[0]]
1453
+ sim.mcx([b1[1]], anc)
1454
+ gate_fn([b1[1]], b2[1])
1455
+ sim.mcx([b1[1]], anc)
1456
+ sim.force_m(anc, False)
1457
+ else:
1458
+ gate_fn([b1[1]], b2[1])
1401
1459
  elif lq1_lr or (b1[1] == b2[1]) or ((len(qb1) == 2) and (b1[1] == (b2[1] & 1))):
1402
1460
  shadow_fn(b1, b2)
1403
1461
  shadow_targets.append(b2)
@@ -1428,6 +1486,24 @@ class QrackAceBackend:
1428
1486
  hist.append(entry)
1429
1487
  self._coupling_history_rev[lq2] = lq1
1430
1488
 
1489
+ # A "coupled twirling" scheme was tried here -- after every real
1490
+ # inter-logical-qubit coupling gate, SWAP which physical qubit is
1491
+ # registered as hq[side] with one of its level-0 scratch qubits, to
1492
+ # spread the extra gate/noise exposure that coupling gates put on
1493
+ # hq[side] (and never on its scratch pair) around the triple instead
1494
+ # of always landing on the same physical qubit. Measured head-to-head
1495
+ # against scheduled-only correction across a repeated-coupling
1496
+ # scenario and multiple noise levels: it made the logical error rate
1497
+ # WORSE at every noise level tested, roughly 2x at the low end --
1498
+ # each twirl's own 3 extra CNOTs cost more than the exposure
1499
+ # asymmetry it was meant to fix, and scheduled-only correction
1500
+ # already handles repeated real coupling gates well on its own (most
1501
+ # circuits don't leave a boundary qubit persistently entangled with
1502
+ # something external all the way into readout the way the theory
1503
+ # worried about). Removed rather than kept as an opt-in: it has no
1504
+ # regime found so far where it beats scheduled-only, so there's
1505
+ # nothing to gate it behind.
1506
+
1431
1507
  def _cpauli(self, lq1, lq2, anti, pauli):
1432
1508
  lq1_row = lq1 // self._row_length
1433
1509
  lq1_col = lq1 % self._row_length
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cpu
3
- Version: 2.17.2
3
+ Version: 2.18.0
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.17.2"
10
+ VERSION = "2.18.0"
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