# How to convert stim encoder circuit to a parity check matrix?

I would like to take an encoding noiseless circuit and output the corresponding parity check matrix in the the binary symplectic format $$(H_x | H_z)$$

I'm aware of the related question: How to get parity check matrix from a circuit in stim

However, the belief-matching solution first converts the circuit to detector error model which I would like to omit since I'm only interested in the encoding circuits.

I was thinking of first converting to tableau using stim.Tableau.from_circuit function and then using stim.Tableau.to_numpy function but I can't figure out how the output of to_numpy corresponds to parity check matrices entries.

I was also thinking of using stim.Tableau.to_stabilizers but was getting 'stim._stim_polyfill.Tableau' object has no attribute 'to_stabilizers' error.

PS: I'm also aware of the two threads going from check matrix to circuit:

How to get parity check matrix from a circuit in stim

Given a list of stabilizers (or parity check matrix), find an encoding circuit

Using the same example as the last link, for an input of an encoding circuit for 2x2 surface code:

stim.Circuit('''
H 0
CX 0 2 2 1 1 2 2 1 3 1
H 2
CX 2 3
''')


the output will be

np.array([
[1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1],
])


Edit: Here is my attempt to answer this using to_stabilizers:

def circuit_to_pcmatrix(circuit: stim.Circuit) -> np.array:
tableau = stim.Tableau.from_circuit(circuit)
stabilizers = tableau.to_stabilizers() # create a list of stabilizers/Pauli strings from tableau
not_stabilizer = stabilizers.pop() # delete last element which is not actually a stabilizer generator but an observable?
Hx = []
Hz = []
for stabilizer in stabilizers:
xs, zs = stim.PauliString(stabilizer).to_numpy()
xs, zs = xs*1, zs*1 # convert True/False to 1/0
Hx.append(xs)
Hz.append(zs)
Hx = np.asarray(Hx)
Hz = np.asarray(Hz)
return np.block([Hx, Hz])


## 1 Answer

I was also thinking of using stim.Tableau.to_stabilizers but was getting 'stim._stim_polyfill.Tableau' object has no attribute 'to_stabilizers' error.

This is probably because you have stim 1.12.0 installed, but to_stabilizers is a brand new method in the development version. If you install 1.13.dev1700545551 (or just the latest ~=1.13.dev) you will gain access to it.

In 1.12 you can do this:

sim = stim.TableauSimulator()
sim.do(encoding_circuit)
mixed_stabilizers_and_observable = [sim.z_output(k) for k in range(len(sim))]


Beware that, just because you have an encoding circuit, that doesn't mean the stabilizer generators chosen by stim will always match the stabilizer generators you intended. Stim may mix generators together compared to your expectation; it might even mix stabilizers with the observable. This is why in general Stim requires the user to annotate detectors and observables.

If you did annotate the detectors and observables into the circuit, then circuit.diagram("detslice-text") is surprisingly close to what you want. It will give you, for each TICK, which stabilizers the detectors correspond to. At the tick between encoding and decoding, that would correspond to the stabilizers of your code. It's not really in a convenient output format, though...

• Thank you so much! I ended up using to_stabilizers which seemed to give the expected generators with an additional element (which I guess is the observable?). Anyway, it seemed to be always at the of the list of generators so I just disregard it. Nov 23, 2023 at 23:20