Skip to content

Commit 17a458f

Browse files
add more methods for stabilizercircuit
1 parent ec3ffb5 commit 17a458f

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

docs/source/modules.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ tensorcircuit
2424
./api/results.rst
2525
./api/shadows.rst
2626
./api/simplify.rst
27+
./api/stabilizercircuit.rst
2728
./api/templates.rst
2829
./api/torchnn.rst
2930
./api/translation.rst

tensorcircuit/stabilizercircuit.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,18 @@ class StabilizerCircuit(AbstractCircuit):
3131
"sd": "S_DAG",
3232
}
3333

34-
def __init__(self, nqubits: int, inputs: Tensor = None) -> None:
34+
def __init__(
35+
self, nqubits: int, inputs: Tensor = None, tableau_inputs: Tensor = None
36+
) -> None:
3537
"""
3638
``StabilizerCircuit`` class based on stim package
3739
3840
:param nqubits: Number of qubits
3941
:type nqubits: int
4042
:param inputs: initial state by stabilizers, defaults to None
4143
:type inputs: Tensor, optional
44+
:param tableau_inputs: initial state by **inverse** tableau, defaults to None
45+
:type tableau_inputs: Tensor, optional
4246
"""
4347
self._nqubits = nqubits
4448
self._stim_circuit = stim.Circuit()
@@ -49,6 +53,8 @@ def __init__(self, nqubits: int, inputs: Tensor = None) -> None:
4953
self.current_sim = stim.TableauSimulator()
5054
if inputs:
5155
self.current_sim.set_state_from_stabilizers(inputs)
56+
if tableau_inputs:
57+
self.current_sim.set_inverse_tableau(tableau_inputs)
5258

5359
def apply_general_gate(
5460
self,
@@ -123,6 +129,22 @@ def random_gate(self, *index: int, recorded: bool = False) -> None:
123129
if recorded:
124130
self._stim_circuit += t.to_circuit()
125131

132+
def tableau_gate(self, *index: int, tableau: Any, recorded: bool = False) -> None:
133+
"""
134+
Apply a gate indicated by tableau to the circuit.
135+
This operation will not record in qir
136+
137+
:param index: Qubit indices to apply the gate to
138+
:type index: int
139+
:param tableau: stim.Tableau representation of the gate
140+
:type tableau: Any
141+
:param recorded: Whether the gate is recorded in ``stim.Circuit``, defaults to False
142+
:type recorded: bool, optional
143+
"""
144+
self.current_sim.do_tableau(tableau, index)
145+
if recorded:
146+
self._stim_circuit += tableau.to_circuit()
147+
126148
def measure(self, *index: int, with_prob: bool = False) -> Tensor:
127149
"""
128150
Measure qubits in Z basis.
@@ -167,6 +189,27 @@ def cond_measurement(self, index: int) -> Tensor:
167189

168190
cond_measure = cond_measurement
169191

192+
def cond_measure_many(self, *index: int) -> Tensor:
193+
"""
194+
Measure qubits in Z basis with state collapse.
195+
196+
:param index: Index of qubit to measure
197+
:type index: int
198+
:return: Measurement results and probability (if with_prob=True)
199+
:rtype: Union[np.ndarray, Tuple[np.ndarray, float]]
200+
"""
201+
# Convert negative indices
202+
203+
# Add measurement instructions
204+
self._stim_circuit.append_from_stim_program_text(
205+
"M " + " ".join(map(str, index))
206+
)
207+
# self.current_sim = None
208+
m = self.current_simulator().measure_many(*index)
209+
# Sample once from the circuit using sampler
210+
211+
return m
212+
170213
def sample(
171214
self,
172215
batch: Optional[int] = None,
@@ -346,6 +389,12 @@ def current_tableau(self) -> stim.Tableau:
346389
"""
347390
return self.current_simulator().current_inverse_tableau() ** -1
348391

392+
def current_inverse_tableau(self) -> stim.Tableau:
393+
"""
394+
Return the current inverse tableau of the circuit.
395+
"""
396+
return self.current_simulator().current_inverse_tableau()
397+
349398
def entanglement_entropy(self, cut: Sequence[int]) -> float:
350399
"""
351400
Calculate the entanglement entropy for a subset of qubits using stabilizer formalism.

tests/test_stabilizer.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,33 @@ def test_depolarize():
185185
c.h(0)
186186
r.append(c.expectation_ps(z=[0]))
187187
assert 10 < np.sum(r) < 20
188+
189+
190+
def test_tableau_inputs():
191+
c = tc.StabilizerCircuit(2)
192+
c.x(1)
193+
c.s(1)
194+
it = c.current_inverse_tableau()
195+
c1 = tc.StabilizerCircuit(2, tableau_inputs=it)
196+
c1.s(1)
197+
c1.x(1)
198+
np.testing.assert_allclose(c1.state()[0], 1, atol=1e-6)
199+
200+
201+
def test_mipt():
202+
resource = [stim.Tableau.random(2) for _ in range(1000)]
203+
204+
def ruc(n, nlayer, p):
205+
c = tc.StabilizerCircuit(n)
206+
status = np.random.choice(1000, size=[n, nlayer], replace=True)
207+
for j in range(nlayer):
208+
for i in range(0, n, 2):
209+
c.tableau_gate(i, (i + 1) % n, tableau=resource[status[i, j]])
210+
for i in range(1, n, 2):
211+
c.tableau_gate(i, (i + 1) % n, tableau=resource[status[i, j]])
212+
mask = np.random.random(n) < p
213+
ids = list(np.where(mask)[0])
214+
c.cond_measure_many(*ids)
215+
return c.entanglement_entropy(list(range(n // 2)))
216+
217+
print(ruc(50, 10, 0.1))

0 commit comments

Comments
 (0)