pyqrack-complex128 2.1.1__tar.gz → 2.2.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_complex128-2.1.1 → pyqrack_complex128-2.2.0}/Makefile +1 -1
  2. {pyqrack_complex128-2.1.1/pyqrack_complex128.egg-info → pyqrack_complex128-2.2.0}/PKG-INFO +1 -1
  3. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_ace_backend.py +76 -22
  4. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_simulator.py +19 -6
  5. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_system/qrack_system.py +2 -0
  6. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0/pyqrack_complex128.egg-info}/PKG-INFO +1 -1
  7. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/setup.py +1 -1
  8. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/LICENSE +0 -0
  9. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/MANIFEST.in +0 -0
  10. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/README.md +0 -0
  11. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyproject.toml +0 -0
  12. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/__init__.py +0 -0
  13. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/neuron_activation_fn.py +0 -0
  14. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/pauli.py +0 -0
  15. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_circuit.py +0 -0
  16. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
  17. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_neuron.py +0 -0
  18. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
  19. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_stabilizer.py +0 -0
  20. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/qrack_system/__init__.py +0 -0
  21. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/quimb_circuit_type.py +0 -0
  22. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/stats/__init__.py +0 -0
  23. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/stats/load_quantized_data.py +0 -0
  24. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack/stats/quantize_by_range.py +0 -0
  25. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack_complex128.egg-info/SOURCES.txt +0 -0
  26. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack_complex128.egg-info/dependency_links.txt +0 -0
  27. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack_complex128.egg-info/not-zip-safe +0 -0
  28. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack_complex128.egg-info/requires.txt +0 -0
  29. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.0}/pyqrack_complex128.egg-info/top_level.txt +0 -0
  30. {pyqrack_complex128-2.1.1 → pyqrack_complex128-2.2.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 7df813ab81978d06decac14b1744b19a9b0cadee; cd ..
33
+ git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout 4d603e03c8f8dc7ee60e0438042b53a1343443be; 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-complex128
3
- Version: 2.1.1
3
+ Version: 2.2.0
4
4
  Summary: pyqrack - Pure Python vm6502q/qrack Wrapper
5
5
  Home-page: https://github.com/vm6502q/pyqrack
6
6
  Author: Daniel Strano
@@ -334,6 +334,50 @@ class QrackAceBackend:
334
334
  def clone(self):
335
335
  return QrackAceBackend(to_clone=self)
336
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
+
337
381
  def num_qubits(self):
338
382
  return self._row_length * self._col_length
339
383
 
@@ -1473,38 +1517,48 @@ class QrackAceBackend:
1473
1517
  return self._coupling_map
1474
1518
 
1475
1519
  # Designed by Dan, and implemented by Elara:
1476
- def create_noise_model(self, x=0.25, y=0.25):
1520
+ def create_noise_model(self, x=0.125, y=0.25):
1477
1521
  if not _IS_QISKIT_AER_AVAILABLE:
1478
1522
  raise RuntimeError(
1479
1523
  "Before trying to run_qiskit_circuit() with QrackAceBackend, you must install Qiskit Aer!"
1480
1524
  )
1481
1525
  noise_model = NoiseModel()
1482
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
1483
1547
  for a, b in self.get_logical_coupling_map():
1484
- col_a, col_b = a % self._row_length, b % self._row_length
1485
- 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
1486
1550
  is_long_a = self._is_col_long_range[col_a]
1487
1551
  is_long_b = self._is_col_long_range[col_b]
1488
1552
 
1489
1553
  if is_long_a and is_long_b:
1490
- continue # No noise on long-to-long
1491
-
1492
- if (col_a == col_b) or (row_a == row_b):
1493
- continue # No noise for same column
1494
-
1495
- if is_long_a or is_long_b:
1496
- y_cy = 1 - (1 - y) ** 2
1497
- y_swap = 1 - (1 - y) ** 3
1498
- noise_model.add_quantum_error(depolarizing_error(y, 2), "cx", [a, b])
1499
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
1500
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
1501
- noise_model.add_quantum_error(depolarizing_error(y_swap, 2), "swap", [a, b])
1502
- else:
1503
- y_cy = 1 - (1 - y) ** 2
1504
- y_swap = 1 - (1 - y) ** 3
1505
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cx", [a, b])
1506
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
1507
- noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
1508
- 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])
1509
1563
 
1510
1564
  return noise_model
@@ -554,8 +554,8 @@ class QrackSimulator:
554
554
  Qrack.qrack_lib.MCAdjT(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
555
555
  self._throw_if_error()
556
556
 
557
- def mcu(self, c, q, th, ph, la):
558
- """Multi-controlled arbitraty unitary
557
+ def mcu(self, c, q, th, ph, la, gm=0.0):
558
+ """Multi-controlled arbitrary unitary
559
559
 
560
560
  If all controlled qubits are `|1>` then the unitary gate described by
561
561
  parameters is applied to the target qubit.
@@ -566,6 +566,7 @@ class QrackSimulator:
566
566
  th: theta
567
567
  ph: phi
568
568
  la: lambda
569
+ gm: gamma
569
570
 
570
571
  Raises:
571
572
  RuntimeError: QrackSimulator raised an exception.
@@ -578,6 +579,7 @@ class QrackSimulator:
578
579
  ctypes.c_double(th),
579
580
  ctypes.c_double(ph),
580
581
  ctypes.c_double(la),
582
+ ctypes.c_double(gm),
581
583
  )
582
584
  self._throw_if_error()
583
585
 
@@ -736,8 +738,8 @@ class QrackSimulator:
736
738
  Qrack.qrack_lib.MACAdjT(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
737
739
  self._throw_if_error()
738
740
 
739
- def macu(self, c, q, th, ph, la):
740
- """Anti multi-controlled arbitraty unitary
741
+ def macu(self, c, q, th, ph, la, gm=0.0):
742
+ """Anti multi-controlled arbitrary unitary
741
743
 
742
744
  If all controlled qubits are `|0>` then the unitary gate described by
743
745
  parameters is applied to the target qubit.
@@ -748,6 +750,7 @@ class QrackSimulator:
748
750
  th: theta
749
751
  ph: phi
750
752
  la: lambda
753
+ gm: gamma
751
754
 
752
755
  Raises:
753
756
  RuntimeError: QrackSimulator raised an exception.
@@ -760,11 +763,12 @@ class QrackSimulator:
760
763
  ctypes.c_double(th),
761
764
  ctypes.c_double(ph),
762
765
  ctypes.c_double(la),
766
+ ctypes.c_double(gm),
763
767
  )
764
768
  self._throw_if_error()
765
769
 
766
770
  def macmtrx(self, c, m, q):
767
- """Anti multi-controlled arbitraty operator
771
+ """Anti multi-controlled arbitrary operator
768
772
 
769
773
  If all controlled qubits are `|0>` then the arbitrary operation by
770
774
  parameters is applied to the target qubit.
@@ -4194,7 +4198,7 @@ class QrackSimulator:
4194
4198
  float(operation.params[0]),
4195
4199
  float(operation.params[1]),
4196
4200
  )
4197
- elif (name == "cu3") or (name == "cu"):
4201
+ elif name == "cu3":
4198
4202
  self._sim.mcu(
4199
4203
  [q._index for q in operation.qubits[0:1]],
4200
4204
  operation.qubits[1]._index,
@@ -4202,6 +4206,15 @@ class QrackSimulator:
4202
4206
  float(operation.params[1]),
4203
4207
  float(operation.params[2]),
4204
4208
  )
4209
+ elif name == "cu":
4210
+ self._sim.mcu(
4211
+ [q._index for q in operation.qubits[0:1]],
4212
+ operation.qubits[1]._index,
4213
+ float(operation.params[0]),
4214
+ float(operation.params[1]),
4215
+ float(operation.params[2]),
4216
+ float(operation.params[3]),
4217
+ )
4205
4218
  elif name == "cx":
4206
4219
  self._sim.mcx([q._index for q in operation.qubits[0:1]], operation.qubits[1]._index)
4207
4220
  elif name == "cy":
@@ -629,6 +629,7 @@ class QrackSystem:
629
629
  c_double,
630
630
  c_double,
631
631
  c_double,
632
+ c_double,
632
633
  ]
633
634
 
634
635
  self.qrack_lib.MCMtrx.restype = None
@@ -715,6 +716,7 @@ class QrackSystem:
715
716
  c_double,
716
717
  c_double,
717
718
  c_double,
719
+ c_double,
718
720
  ]
719
721
 
720
722
  self.qrack_lib.MACMtrx.restype = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrack-complex128
3
- Version: 2.1.1
3
+ Version: 2.2.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.1.1"
10
+ VERSION = "2.2.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')