stabtab 0.1.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.
stabtab-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.4
2
+ Name: stabtab
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.14
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: numpy>=2.5.3
8
+
9
+ Stabilizer library based on https://arxiv.org/pdf/quant-ph/0406196
@@ -0,0 +1 @@
1
+ Stabilizer library based on https://arxiv.org/pdf/quant-ph/0406196
@@ -0,0 +1,18 @@
1
+ [project]
2
+ name = "stabtab"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.14"
7
+ dependencies = [
8
+ "numpy>=2.5.3",
9
+ ]
10
+
11
+ [dependency-groups]
12
+ dev = [
13
+ "pyrefly>=1.3.0",
14
+ "ruff>=0.16.7",
15
+ ]
16
+
17
+ [tool.ruff.lint]
18
+ extend-select = ["I"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ from stabtab.tableau import Tableau as Tableau
@@ -0,0 +1,116 @@
1
+ import numpy as np
2
+
3
+
4
+ class Tableau:
5
+ type QubitIdx = int
6
+ type TableauIdx = int
7
+ type MeasurementRes = int
8
+
9
+ def __init__(self, n_qubits: QubitIdx):
10
+ self.n_qubits = n_qubits
11
+ self.two_n_qubits = 2 * self.n_qubits
12
+ self.tableau = self._init_tableau()
13
+ self.rng = np.random.default_rng()
14
+
15
+ def _init_tableau(self):
16
+ tableau = np.eye(self.two_n_qubits, self.two_n_qubits + 1, dtype=np.bool)
17
+ scratchpad = np.zeros((1, tableau[0].size), dtype=np.bool)
18
+ return np.vstack((tableau, scratchpad), dtype=np.bool)
19
+
20
+ def apply_cx(self, a: QubitIdx, b: QubitIdx):
21
+ self._validate_qubit(a)
22
+ self._validate_qubit(b)
23
+ for i in range(self.two_n_qubits):
24
+ self.tableau[i][-1] ^= (
25
+ self.tableau[i][a]
26
+ * self.tableau[i][b + self.n_qubits]
27
+ * (self.tableau[i][b] ^ self.tableau[i][a + self.n_qubits] ^ 1)
28
+ )
29
+ self.tableau[i][b] ^= self.tableau[i][a]
30
+ self.tableau[i][a + self.n_qubits] ^= self.tableau[i][b + self.n_qubits]
31
+
32
+ def apply_h(self, a: QubitIdx):
33
+ self._validate_qubit(a)
34
+ for i in range(self.two_n_qubits):
35
+ self.tableau[i][-1] ^= (
36
+ self.tableau[i][a] * self.tableau[i][a + self.n_qubits]
37
+ )
38
+ self.tableau[i][a], self.tableau[i][a + self.n_qubits] = (
39
+ self.tableau[i][a + self.n_qubits],
40
+ self.tableau[i][a],
41
+ )
42
+
43
+ def apply_s(self, a: QubitIdx):
44
+ self._validate_qubit(a)
45
+ for i in range(self.two_n_qubits):
46
+ self.tableau[i][-1] ^= (
47
+ self.tableau[i][a] * self.tableau[i][a + self.n_qubits]
48
+ )
49
+ self.tableau[i][a + self.n_qubits] ^= self.tableau[i][a]
50
+
51
+ def _g(self, x1: np.int8, z1: np.int8, x2: np.int8, z2: np.int8):
52
+ if x1 == z1 == 0:
53
+ return 0
54
+ if x1 == z1 == 1:
55
+ return z2 - x2
56
+ if x1 == 1 and z1 == 0:
57
+ return z2 * (2 * x2 - 1)
58
+ return x2 * (1 - 2 * z2)
59
+
60
+ def _rowsum(self, h: TableauIdx, i: TableauIdx):
61
+ val = 2 * self.tableau[h][-1] + 2 * self.tableau[i][-1]
62
+ for j in range(self.n_qubits):
63
+ val += self._g(
64
+ self.tableau[i][j],
65
+ self.tableau[i][j + self.n_qubits],
66
+ self.tableau[h][j],
67
+ self.tableau[h][j + self.n_qubits],
68
+ )
69
+
70
+ self.tableau[h][-1] = val % 4 == 2
71
+
72
+ for j in range(self.n_qubits):
73
+ self.tableau[h][j] ^= self.tableau[i][j]
74
+ self.tableau[h][j + self.n_qubits] ^= self.tableau[i][j + self.n_qubits]
75
+
76
+ def measure_z(self, a: QubitIdx) -> MeasurementRes:
77
+ self._validate_qubit(a)
78
+ p = None
79
+ for p_cand in range(self.n_qubits, self.two_n_qubits):
80
+ if self.tableau[p_cand][a] == 1:
81
+ p = p_cand
82
+ break
83
+
84
+ if p:
85
+ return self._random_z_measurement(a, p)
86
+ return self._deterministic_z_measurement(a)
87
+
88
+ def _random_z_measurement(self, a: QubitIdx, p: TableauIdx) -> MeasurementRes:
89
+ for i in range(self.two_n_qubits):
90
+ if i == p or self.tableau[i][a] != 1:
91
+ continue
92
+ self._rowsum(i, p)
93
+
94
+ self.tableau[p - self.n_qubits] = self.tableau[p]
95
+
96
+ self.tableau[p][:] = 0
97
+ self.tableau[p][a + self.n_qubits] = 1
98
+ self.tableau[p][-1] = self.rng.integers(low=0, high=2)
99
+
100
+ return self.tableau[p][-1]
101
+
102
+ def _deterministic_z_measurement(self, a: QubitIdx) -> MeasurementRes:
103
+ self.tableau[-1][:] = 0
104
+ for i in range(self.n_qubits):
105
+ if self.tableau[i][a] != 1:
106
+ continue
107
+ self._rowsum(self.two_n_qubits, i + self.n_qubits)
108
+
109
+ return self.tableau[-1][-1]
110
+
111
+ def _validate_qubit(self, a: QubitIdx):
112
+ if not 0 <= a < self.n_qubits:
113
+ raise ValueError(f"Qubit idx {a} out of range [0..{self.n_qubits}]")
114
+
115
+ def __repr__(self):
116
+ return str(self.tableau.view(np.uint8))
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.4
2
+ Name: stabtab
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.14
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: numpy>=2.5.3
8
+
9
+ Stabilizer library based on https://arxiv.org/pdf/quant-ph/0406196
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ stabtab/__init__.py
4
+ stabtab/tableau.py
5
+ stabtab.egg-info/PKG-INFO
6
+ stabtab.egg-info/SOURCES.txt
7
+ stabtab.egg-info/dependency_links.txt
8
+ stabtab.egg-info/requires.txt
9
+ stabtab.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ numpy>=2.5.3
@@ -0,0 +1 @@
1
+ stabtab