Skip to content

Commit

Permalink
add more methods for stabilizercircuit
Browse files Browse the repository at this point in the history
  • Loading branch information
refraction-ray committed Jan 30, 2025
1 parent ec3ffb5 commit 17a458f
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/source/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ tensorcircuit
./api/results.rst
./api/shadows.rst
./api/simplify.rst
./api/stabilizercircuit.rst
./api/templates.rst
./api/torchnn.rst
./api/translation.rst
Expand Down
51 changes: 50 additions & 1 deletion tensorcircuit/stabilizercircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,18 @@ class StabilizerCircuit(AbstractCircuit):
"sd": "S_DAG",
}

def __init__(self, nqubits: int, inputs: Tensor = None) -> None:
def __init__(
self, nqubits: int, inputs: Tensor = None, tableau_inputs: Tensor = None
) -> None:
"""
``StabilizerCircuit`` class based on stim package
:param nqubits: Number of qubits
:type nqubits: int
:param inputs: initial state by stabilizers, defaults to None
:type inputs: Tensor, optional
:param tableau_inputs: initial state by **inverse** tableau, defaults to None
:type tableau_inputs: Tensor, optional
"""
self._nqubits = nqubits
self._stim_circuit = stim.Circuit()
Expand All @@ -49,6 +53,8 @@ def __init__(self, nqubits: int, inputs: Tensor = None) -> None:
self.current_sim = stim.TableauSimulator()
if inputs:
self.current_sim.set_state_from_stabilizers(inputs)
if tableau_inputs:
self.current_sim.set_inverse_tableau(tableau_inputs)

def apply_general_gate(
self,
Expand Down Expand Up @@ -123,6 +129,22 @@ def random_gate(self, *index: int, recorded: bool = False) -> None:
if recorded:
self._stim_circuit += t.to_circuit()

def tableau_gate(self, *index: int, tableau: Any, recorded: bool = False) -> None:
"""
Apply a gate indicated by tableau to the circuit.
This operation will not record in qir
:param index: Qubit indices to apply the gate to
:type index: int
:param tableau: stim.Tableau representation of the gate
:type tableau: Any
:param recorded: Whether the gate is recorded in ``stim.Circuit``, defaults to False
:type recorded: bool, optional
"""
self.current_sim.do_tableau(tableau, index)
if recorded:
self._stim_circuit += tableau.to_circuit()

def measure(self, *index: int, with_prob: bool = False) -> Tensor:
"""
Measure qubits in Z basis.
Expand Down Expand Up @@ -167,6 +189,27 @@ def cond_measurement(self, index: int) -> Tensor:

cond_measure = cond_measurement

def cond_measure_many(self, *index: int) -> Tensor:
"""
Measure qubits in Z basis with state collapse.
:param index: Index of qubit to measure
:type index: int
:return: Measurement results and probability (if with_prob=True)
:rtype: Union[np.ndarray, Tuple[np.ndarray, float]]
"""
# Convert negative indices

# Add measurement instructions
self._stim_circuit.append_from_stim_program_text(
"M " + " ".join(map(str, index))
)
# self.current_sim = None
m = self.current_simulator().measure_many(*index)
# Sample once from the circuit using sampler

return m

def sample(
self,
batch: Optional[int] = None,
Expand Down Expand Up @@ -346,6 +389,12 @@ def current_tableau(self) -> stim.Tableau:
"""
return self.current_simulator().current_inverse_tableau() ** -1

def current_inverse_tableau(self) -> stim.Tableau:
"""
Return the current inverse tableau of the circuit.
"""
return self.current_simulator().current_inverse_tableau()

def entanglement_entropy(self, cut: Sequence[int]) -> float:
"""
Calculate the entanglement entropy for a subset of qubits using stabilizer formalism.
Expand Down
30 changes: 30 additions & 0 deletions tests/test_stabilizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,33 @@ def test_depolarize():
c.h(0)
r.append(c.expectation_ps(z=[0]))
assert 10 < np.sum(r) < 20


def test_tableau_inputs():
c = tc.StabilizerCircuit(2)
c.x(1)
c.s(1)
it = c.current_inverse_tableau()
c1 = tc.StabilizerCircuit(2, tableau_inputs=it)
c1.s(1)
c1.x(1)
np.testing.assert_allclose(c1.state()[0], 1, atol=1e-6)


def test_mipt():
resource = [stim.Tableau.random(2) for _ in range(1000)]

def ruc(n, nlayer, p):
c = tc.StabilizerCircuit(n)
status = np.random.choice(1000, size=[n, nlayer], replace=True)
for j in range(nlayer):
for i in range(0, n, 2):
c.tableau_gate(i, (i + 1) % n, tableau=resource[status[i, j]])
for i in range(1, n, 2):
c.tableau_gate(i, (i + 1) % n, tableau=resource[status[i, j]])
mask = np.random.random(n) < p
ids = list(np.where(mask)[0])
c.cond_measure_many(*ids)
return c.entanglement_entropy(list(range(n // 2)))

print(ruc(50, 10, 0.1))

0 comments on commit 17a458f

Please sign in to comment.