# how to go from a stabilizer state to a graph

A comment (by Marcus Heinrich) in a previous post says :

"any stabiliser state is locally Clifford equivalent to a graph state and vice versa".

I can go from a graph (defined by its adjacency matrix) to a set of stabilizers and the corresponding state. My question is for the other direction : if I have a set of stabilizers that define a $$[[n,0,d]]$$ code; is there a procedure to get an adjacency matrix that would correspond to it?

See this paper for a proof, but I will sumamrize the idea below.

Suppose you have a stabilizer state $$|\psi\rangle$$ and a set $$\mathcal{S}$$ of Paulis that generate its stabilizer group, $$\langle S \rangle$$.

You can represent the generators by a pair of matrices, $$X$$ and $$Z$$, such that $$X[i, j] = 1$$ if the $$i$$-th generator has a tensor factor of $$\sigma_x$$ in the $$j$$-th position.

For example, if you have generators $$\sigma_x \otimes \sigma_x$$ and $$\sigma_z \otimes \sigma_z$$ for the bell state, then the matrix you obtain is $$X = \begin{pmatrix} 1 & 1 \\ 0 & 0 \end{pmatrix}$$ and $$Z = \begin{pmatrix} 0 & 0 \\ 1 & 1\end{pmatrix}$$. Of course, you can always choose different generators, so this depiction is not unique.

If you do this procedure for a graph state $$|G\rangle$$ by using the natural generators of the stabilizer group of the graph state, you always obtain matrices where $$X$$ is identity, and $$Z$$ is exactly the adjacency matrix of the graph.

The claim now is: We can take any two matrices $$X$$ and $$Z$$ that encode a stabilizer group, and transform them into $$X = I$$ and $$Z$$ into a adjacency matrix.

This is done using something similar to a binary RREF procedure, where the binary addition of two rows is like multiplying two group generators to form a new group generator, or by swapping columns of the two matrix via conjugation by $$H$$ gate. This way, we can reduce $$X$$ matrix, obtaining identity, and it can be shown that $$Z$$ becomes symmetric. There are some additional details, but due to the structure of the matrices, we can always obtain an $$X$$ and $$Z$$ of this form.

• Thanks for the answer...I experimented with this a little and I think I can just put the stabilizers into standard form. There are two identity matrices in that form : one on the left hand or X side and one on the right or Z side. Permuting the columns to move the Z side identity to the left gives the desired form in all the examples I tried. The column permutation should correspond to applying hadamard gates to the affected qubits. Nov 5, 2023 at 16:56
• @unknown Indeed. You can first bring the generator matrix into standard form, then transform it into the generator matrix of a graph state (adj. + identity matrix) by Hadamard gates (or you do it in opposite order, see Sec. III of the van den Nest et al. paper). Btw this reduction to graph states was already described by Schlingemann arxiv.org/abs/quant-ph/0111080 Nov 6, 2023 at 8:40
• @MarkusHeinrich glad to see the references to this construction. I already have code to construct the standard form so getting the adjacency matrix turned out to be a minor addition. In fusion based quantum computing they refer to graph states as "resource states" to add to the terminology soup. Also I think there's a third (standard?) form for a graph state...I might post another question about this once I catch up on the papers. Nov 6, 2023 at 15:55

You can use Stim to turn a stabilizer state into a graph state. Internally what it does is to decompose the stabilizer state into any circuit (it happens to do this by Gaussian elimination of the stabilizer tableau), then it feeds that circuit through a graph state simulator (relevant source code in stim), then it outputs the graph state as a circuit which has an RX layer followed by a CZ layer followed by a single qubit rotation layer.

For example, if you pick an arbitrary stabilizer state:

import stim

stabilizer_state = stim.Tableau.random(10)
for stabilizer in stabilizer_state.to_stabilizers():
print("stabilizer", stabilizer)
# prints (for example):
# stabilizer +XXY__XYZYZ
# stabilizer -ZZ___YX___
# stabilizer -_XXZX_YYXY
# stabilizer -__XXX_XY_Y
# stabilizer +XX__YY__XZ
# stabilizer +YZ_X_Z_Z_X
# stabilizer +XXZX_XZYZ_
# stabilizer -YYZYYYX_XZ
# stabilizer -XZZXXZX_YZ
# stabilizer +__Z_Z_XXZZ


You can get the graph state circuit for it:

graph_state_circuit = stabilizer_state.to_circuit("graph_state")
print(graph_state_circuit.diagram())
# prints (for example):
#         /-------------------------------------------\ /-----\
# q0: -RX-@-@-@-@-@-@-----------------------------------Z-H-----
#         | | | | | |
# q1: -RX-@-|-|-|-|-|-@-@-@-----------------------------S-H-----
#           | | | | | | | |
# q2: -RX---@-|-|-|-|-@-|-|-@-@-------------------------Z-H-----
#             | | | |   | | | |
# q3: -RX-----@-|-|-|---@-|-|-|-@-@-@---------------------H-----
#               | | |     | | | | | |
# q4: -RX-------|-|-|-----@-@-|-@-|-|-@-@-@-@-----------Z-H-----
#               | | |         |   | | | | | |
# q5: -RX-------|-|-|---------|---@-|-|-|-|-|-@-@---------H-----
#               | | |         |     | | | | | | |
# q6: -RX-------@-|-|---------|-----@-@-|-|-|-@-|-@-----X-S-H-S-
#                 | |         |         | | |   | |
# q7: -RX---------|-|---------|---------@-|-|---|-|-@-@-X---H---
#                 | |         |           | |   | | | |
# q8: -RX---------@-|---------|-----------@-|---|-@-@-|-X---H---
#                   |         |             |   |     |
# q9: -RX-----------@---------@-------------@---@-----@-Y---H---
#         \-------------------------------------------/ \-----/


Once you have the circuit, it's quite easy to get the graph into a more normal format such as networkx:

import networkx as nx
graph = nx.Graph()
for instruction in graph_state_circuit:
if instruction.name == 'CZ':
targets = instruction.targets_copy()
for a, b in zip(targets[::2], targets[1::2]):