pyqrack-cpu-complex128 2.1.0__tar.gz → 2.1.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_cpu_complex128-2.1.0/pyqrack_cpu_complex128.egg-info → pyqrack_cpu_complex128-2.1.2}/PKG-INFO +1 -1
  2. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_ace_backend.py +81 -29
  3. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2/pyqrack_cpu_complex128.egg-info}/PKG-INFO +1 -1
  4. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/setup.py +1 -1
  5. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/LICENSE +0 -0
  6. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/MANIFEST.in +0 -0
  7. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/Makefile +0 -0
  8. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/README.md +0 -0
  9. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyproject.toml +0 -0
  10. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/__init__.py +0 -0
  11. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/neuron_activation_fn.py +0 -0
  12. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/pauli.py +0 -0
  13. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_circuit.py +0 -0
  14. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
  15. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_neuron.py +0 -0
  16. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  17. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_simulator.py +0 -0
  18. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_stabilizer.py +0 -0
  19. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_system/__init__.py +0 -0
  20. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/qrack_system/qrack_system.py +0 -0
  21. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/quimb_circuit_type.py +0 -0
  22. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/stats/__init__.py +0 -0
  23. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/stats/load_quantized_data.py +0 -0
  24. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack/stats/quantize_by_range.py +0 -0
  25. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack_cpu_complex128.egg-info/SOURCES.txt +0 -0
  26. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack_cpu_complex128.egg-info/dependency_links.txt +0 -0
  27. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack_cpu_complex128.egg-info/not-zip-safe +0 -0
  28. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack_cpu_complex128.egg-info/requires.txt +0 -0
  29. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/pyqrack_cpu_complex128.egg-info/top_level.txt +0 -0
  30. {pyqrack_cpu_complex128-2.1.0 → pyqrack_cpu_complex128-2.1.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cpu-complex128
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -2,6 +2,8 @@
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style license that can be
4
4
  # found in the LICENSE file or at https://opensource.org/licenses/MIT.
5
+ #
6
+ # Produced with input from (OpenAI) ChatGPT and (Anthropic) Claude
5
7
  import math
6
8
  import os
7
9
  import random
@@ -332,6 +334,50 @@ class QrackAceBackend:
332
334
  def clone(self):
333
335
  return QrackAceBackend(to_clone=self)
334
336
 
337
+ def measure_shots_consensus(self, q, s, n_instances=3, threshold=0.1):
338
+ # Consensus measurement across n_instances independent clones.
339
+ #
340
+ # For each shot, run n_instances clones of the current state and
341
+ # compare their marginal probabilities on every logical qubit via
342
+ # prob(). For each qubit, take the majority vote over all instances:
343
+ # if the average marginal >= 0.5, force_m to |1>; else to |0>.
344
+ #
345
+ # This resolves the parity ambiguity that causes XEB flip-flopping:
346
+ # a bit-flip on a boundary qubit appears as disagreement between
347
+ # instances (one sees p~0.9, another sees p~0.1). The majority vote
348
+ # across n_instances corrects isolated odd-parity errors without
349
+ # requiring a second full circuit run — just cheap prob() queries.
350
+ #
351
+ # threshold: minimum spread in marginals to trigger consensus
352
+ # correction (below threshold, instances agree and no correction needed).
353
+ n_qubits = self.num_qubits()
354
+ samples = []
355
+ for _ in range(s):
356
+ # Run n_instances clones, collect marginals for every qubit
357
+ clones = [self.clone() for _ in range(n_instances)]
358
+ marginals = [
359
+ [c.prob(lq) for lq in range(n_qubits)]
360
+ for c in clones
361
+ ]
362
+ # Majority vote: average marginal across instances per qubit
363
+ avg_marginals = [
364
+ sum(marginals[i][lq] for i in range(n_instances)) / n_instances
365
+ for lq in range(n_qubits)
366
+ ]
367
+ # Force all qubits in first clone to majority-vote outcome
368
+ primary = clones[0]
369
+ for lq in range(n_qubits):
370
+ result = avg_marginals[lq] >= 0.5
371
+ primary.force_m(lq, result)
372
+ # Read out requested qubits
373
+ _sample = primary.m_all()
374
+ sample = 0
375
+ for i in range(len(q)):
376
+ if (_sample >> q[i]) & 1:
377
+ sample |= 1 << i
378
+ samples.append(sample)
379
+ return samples
380
+
335
381
  def num_qubits(self):
336
382
  return self._row_length * self._col_length
337
383
 
@@ -672,8 +718,7 @@ class QrackAceBackend:
672
718
  b = hq[lhv]
673
719
  b.u(th, ph, lm)
674
720
 
675
- self._correct(lq, False, True)
676
- self._correct(lq, True, False)
721
+ # Correction deferred to next 2-qubit gate (_cpauli calls _correct)
677
722
 
678
723
  def r(self, p, th, lq):
679
724
  hq = self._unpack(lq)
@@ -696,10 +741,7 @@ class QrackAceBackend:
696
741
  elif p == Pauli.PauliZ:
697
742
  b.rz(th)
698
743
 
699
- if p != Pauli.PauliZ:
700
- self._correct(lq, False, p != Pauli.PauliX)
701
- if p != Pauli.PauliX:
702
- self._correct(lq, True)
744
+ # Correction deferred to next 2-qubit gate (_cpauli calls _correct)
703
745
 
704
746
  def h(self, lq):
705
747
  hq = self._unpack(lq)
@@ -719,7 +761,7 @@ class QrackAceBackend:
719
761
  b = hq[lhv]
720
762
  b.h()
721
763
 
722
- self._correct(lq)
764
+ # Correction deferred to next 2-qubit gate (_cpauli calls _correct)
723
765
 
724
766
  def s(self, lq):
725
767
  hq = self._unpack(lq)
@@ -1475,38 +1517,48 @@ class QrackAceBackend:
1475
1517
  return self._coupling_map
1476
1518
 
1477
1519
  # Designed by Dan, and implemented by Elara:
1478
- def create_noise_model(self, x=0.25, y=0.25):
1520
+ def create_noise_model(self, x=0.125, y=0.25):
1479
1521
  if not _IS_QISKIT_AER_AVAILABLE:
1480
1522
  raise RuntimeError(
1481
1523
  "Before trying to run_qiskit_circuit() with QrackAceBackend, you must install Qiskit Aer!"
1482
1524
  )
1483
1525
  noise_model = NoiseModel()
1484
1526
 
1527
+ # Single-qubit depolarizing only on boundary qubits
1528
+ boundary_qubits = set()
1529
+ for a, b in self.get_logical_coupling_map():
1530
+ col_a = a % self._row_length
1531
+ col_b = b % self._row_length
1532
+ is_long_a = self._is_col_long_range[col_a]
1533
+ is_long_b = self._is_col_long_range[col_b]
1534
+ if not (is_long_a and is_long_b):
1535
+ if not is_long_a:
1536
+ boundary_qubits.add(a)
1537
+ if not is_long_b:
1538
+ boundary_qubits.add(b)
1539
+
1540
+ for q in boundary_qubits:
1541
+ for gate in ["u", "u1", "u2", "u3", "h", "x", "y", "z",
1542
+ "s", "sdg", "t", "tdg", "rx", "ry", "rz"]:
1543
+ noise_model.add_quantum_error(
1544
+ depolarizing_error(x, 1), gate, [q])
1545
+
1546
+ # Two-qubit depolarizing on boundary-crossing and boundary-adjacent gates
1485
1547
  for a, b in self.get_logical_coupling_map():
1486
- col_a, col_b = a % self._row_length, b % self._row_length
1487
- row_a, row_b = a // self._row_length, b // self._row_length
1548
+ col_a = a % self._row_length
1549
+ col_b = b % self._row_length
1488
1550
  is_long_a = self._is_col_long_range[col_a]
1489
1551
  is_long_b = self._is_col_long_range[col_b]
1490
1552
 
1491
1553
  if is_long_a and is_long_b:
1492
- continue # No noise on long-to-long
1493
-
1494
- if (col_a == col_b) or (row_a == row_b):
1495
- continue # No noise for same column
1496
-
1497
- if is_long_a or is_long_b:
1498
- y_cy = 1 - (1 - y) ** 2
1499
- y_swap = 1 - (1 - y) ** 3
1500
- noise_model.add_quantum_error(depolarizing_error(y, 2), "cx", [a, b])
1501
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
1502
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
1503
- noise_model.add_quantum_error(depolarizing_error(y_swap, 2), "swap", [a, b])
1504
- else:
1505
- y_cy = 1 - (1 - y) ** 2
1506
- y_swap = 1 - (1 - y) ** 3
1507
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cx", [a, b])
1508
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
1509
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
1510
- noise_model.add_quantum_error(depolarizing_error(y_swap, 2), "swap", [a, b])
1554
+ continue
1555
+
1556
+ p2 = 1 - (1 - y) ** 2 if (is_long_a or is_long_b) else y
1557
+ p3 = 1 - (1 - y) ** 3 if (is_long_a or is_long_b) else 1 - (1 - y) ** 2
1558
+
1559
+ for gate in ["cx", "cy", "cz"]:
1560
+ noise_model.add_quantum_error(depolarizing_error(p2, 2), gate, [a, b])
1561
+ for gate in ["swap", "iswap"]:
1562
+ noise_model.add_quantum_error(depolarizing_error(p3, 2), gate, [a, b])
1511
1563
 
1512
1564
  return noise_model
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-cpu-complex128
3
- Version: 2.1.0
3
+ Version: 2.1.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.1.0"
10
+ VERSION = "2.1.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')