stabtab 0.1.0__py3-none-any.whl
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/__init__.py +1 -0
- stabtab/tableau.py +116 -0
- stabtab-0.1.0.dist-info/METADATA +9 -0
- stabtab-0.1.0.dist-info/RECORD +6 -0
- stabtab-0.1.0.dist-info/WHEEL +5 -0
- stabtab-0.1.0.dist-info/top_level.txt +1 -0
stabtab/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from stabtab.tableau import Tableau as Tableau
|
stabtab/tableau.py
ADDED
|
@@ -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,6 @@
|
|
|
1
|
+
stabtab/__init__.py,sha256=rv3eePiL7-e3yLZTvq7Craertg5eRBotXOuUvo5IsIw,47
|
|
2
|
+
stabtab/tableau.py,sha256=quiDktXTtuNJH43t86LbAMPhSq2X2959WfOZVG2iHzk,4068
|
|
3
|
+
stabtab-0.1.0.dist-info/METADATA,sha256=WnDkMANCBFDlAz5flCauKtw42DLatKZNVvZ82d438nM,247
|
|
4
|
+
stabtab-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
5
|
+
stabtab-0.1.0.dist-info/top_level.txt,sha256=IBQ1RC_Fu-4gLbJHkl8ClMemRMfQew-4iAqtgxnEnd8,8
|
|
6
|
+
stabtab-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
stabtab
|