Crumble is an in-development tool for exploring and inspecting 2D stabilizer circuits, with a focus on quantum error correction. In particular, crumble automates the process of propagating and verifying the flow of Pauli products across the layers of the circuit.
Crumble is still being prototyped and developed. Crumble is not stable. Crumble is not polished.
Crumble can be accessed by installing stim 1.11 or later (e.g. by pip install stim~=1.11), printing the output of stim.Circuit().diagram("interactive") to an HTML file, and then opening the HTML file in a browser.
Crumble can also be accessed by building it.
There are two core pieces to using crumble effectively: (1) editing the circuit and (2) propagating Paulis.
Editing the circuit is done by selecting qubits with the mouse and hitting keyboard keys to place gates. The layers of the circuit can be navigated using the Q/E keys.
Propagating Paulis is done by placing markers to indicate where to add terms.
Each marker has a type (X, Y, or Z) and an index (0-9) indicating which indexed
Pauli product the marker is modifying.
For example, to place a Z term after a reset gate into the Pauli product with
index 1, select the reset gate and press Z+1. This introduces a Z term into
the Pauli product, and advancing through the circuit will show how the now
non-empty Pauli product changes as it is rewritten by the circuit's stabilizer
operations.
The simplest way to use markers is as a method for seeing how errors propagate through the circuit. But the far more useful case is for seeing how knowledge propagates through the circuit. After a qubit is reset, its Z observable is in a known state. As the circuit executes, this piece of knowledge is transformed into different forms; it may later correspond to knowing a multi-qubit Pauli product or to knowing what the result of a measurement must be. Pauli propagation shows how these pieces of knowledge move through the circuit.
Of particular interest is finding small sets of resets that match small sets of nearby measurements (i.e. resets that prepare knowledge predicting the parity of a set of measurements). These local reset-vs-measurement tautologies correspond to detectors, which can be used to correct errors. The path that the Pauli product takes, starting from the various resets and terminating on the various measurements, forms the detecting region of the detector.
- Bookmarking:
As crumble runs, it constantly updates the web page's address so that it encodes
the current circuit.
For example, for an empty circuit, the URL will end with
#circuit=whereas a circuit with a single Hadamard gate would end with#circuit=Q(0,0)0;H_0. Thus, the current circuit can be saved by bookmarking the page and loaded again later by opening the bookmark. - Importing and Exporting: In the top left of the page, there is a button "Show Import/Export". Clicking this button will reveal a large textbox containing the current circuit encoded as a Stim circuit. To save the circuit, copy this text and write it to a text file on your computer. The saved circuit can later be loaded by copying the file's contents to your clipboard, pasting over the contents of the textbox, and hitting the "↓ Import from Stim Circuit ↓" button below the textbox. The import/export text box can be hidden by clicking the "Show Import/Export" button (now labelled "Hide Import/Export") again.
Pauli Propagation
spacebar: Clear all Pauli propagation markers at current selection.#: Puts a Pauli propagation marker at the current selection for the indexed Pauli product.#can be any of 1, 2, 3, etc and determines which of the tracked Pauli products the marker goes into. For example,2will place a marker that multiplies a Pauli term into tracked Pauli product #2. The basis of the marker is inferred from context (e.g. if anRXgate is selected, it will be anXmarker).x+#: Put an X-type Pauli propagation marker at the current selection for the indexed Pauli product.y+#: Put a Y-type Pauli propagation marker at the current selection for the indexed Pauli product.z+#: Put a Z-type Pauli propagation marker at the current selection for the indexed Pauli product.d+#: Converts the indexed Pauli product into a circuitDETECTORdeclaration.o+#: Converts the indexed Pauli product into a circuitOBSERVABLE_INCLUDEdeclaration.j+#: Picks aDETECTORorOBSERVABLE_INCLUDEdeclaration touching the current selection and converts it into a tracked Pauli product.k+#: Add a marker to any dissipative gate that the indexed Pauli product overlaps in the current layer.
Editing
p: Add a background polygon with corners at the current selection. The color of the polygon is affected by modifier keys: X, Y, Z, alt, shift.e: Move to next layer.q: Move to previous layer.shift+e: Move forward 5 layers.shift+q: Move backward 5 layers.escape: Unselect. Set current selection to the empty set.delete: Delete gates at current selection.backspace: Delete gates at current selection.ctrl+delete: Delete current circuit layer.ctrl+backspace: Delete current circuit layer.ctrl+insert: Insert empty layer at current circuit layer, pushing current circuit layer ahead in time.ctrl+z: Undoctrl+y: Redoctrl+shift+z: Redoctrl+c: Copy selection to clipboard (or entire layer if nothing selected).ctrl+v: Past clipboard contents at current selection (or entire layer if nothing selected).ctrl+x: Cut selection to clipboard (or entire layer if nothing selected).f: Reverse direction of selected two qubit gates (e.g. exchange the controls and targets of a CNOT).g: Reverse order of circuit layers, from the current layer to the next empty layer.home: Jump to the first layer of the circuit.end: Jump to the last layer of the circuit.t: Rotate circuit 45 degrees clockwise.shift+t: Rotate circuit 45 degrees counter-clockwise.v: Translate circuit down one step.^: Translate circuit up one step.>: Translate circuit right one step.<: Translate circuit left one step..: Translate circuit down and right by a half step.
Single Qubit Gates
Note: use shift to get the inverse of a gate.
h: Overwrite selection withHgates: Overwrite selection withSQRT_Zgater: Overwrite selection withRgatem: Overwrite selection withMgateh+zorh+x+y: Overwrite selection withH_XYgateh+xorh+y+z: Overwrite selection withH_YZgates+x: Overwrite selection withSQRT_Xgates+y: Overwrite selection withSQRT_Ygater+x: Overwrite selection withRXgater+y: Overwrite selection withRYgatem+x: Overwrite selection withMXgatem+y: Overwrite selection withMYgatem+r+x: Overwrite selection withMRXgatem+r+y: Overwrite selection withMRYgatem+r: Overwrite selection withMRgatec+t: Overwrite selection withC_XYZgatej+x: Overwrite selection with just a PauliXgatej+y: Overwrite selection with just a PauliYgatej+z: Overwrite selection with just a PauliZgateshift+c+t: Overwrite selection withC_ZYXgate
Two Qubit Gates
Note: when a single qubit is selected and a two qubit gate is placed, the gate spans between the selected qubit and the qubit the mouse is hovering over. When multiple qubits are selected, the difference between the topmost leftmost qubit and the qubit the mouse is hovering over is computed, and then each selected qubit targets its position offset by that difference.
Note: use shift to get the inverse of a gate.
w: Overwrite selection withSWAPgate targeting mousew+i: Overwrite selection withISWAPgate targeting mousew+x: Overwrite selection withCXSWAPgate targeting mousec+x: Overwrite selection withCXgate targeting mousec+y: Overwrite selection withCYgate targeting mousec+z: Overwrite selection withCZgate targeting mousec+x+y: Overwrite selection withXCYgate targeting mousealt+c+x: Overwrite selection withXCXgate targeting mousealt+c+y: Overwrite selection withYCYgate targeting mousec+s+x: Overwrite selection withSQRT_XXgate targeting mousec+s+y: Overwrite selection withSQRT_YYgate targeting mousec+s+z: Overwrite selection withSQRT_ZZgate targeting mousec+m+x: Overwrite selection withMXXgate targeting mousec+m+y: Overwrite selection withMYYgate targeting mousec+m+z: Overwrite selection withMZZgate targeting mouse
Multi Qubit Gates
m+p+x: Overwrite selection with a singleMPPgate targeting the tensor product of X on each selected qubit.m+p+y: Overwrite selection with a singleMPPgate targeting the tensor product of Y on each selected qubit.m+p+z: Overwrite selection with a singleMPPgate targeting the tensor product of Z on each selected qubit.
Keyboard Buttons as Gate Adjectives
Roughly speaking, the "keyboard language" for gates used by Crumble has the following "adjectives":
xmeans "X basis"ymeans "Y basis"zmeans "Z basis"shiftmeans "inverse"cmeans "controlled gate" or more generally "two qubit variant of gate"smeans "square root"mmeans "measure"rmeans "reset"wmeans "swap"altmeans "no not that one, a different one"
Here are some examples:
r+xis the X basis variant of the reset operation (i.e. the gateRX 0).m+ris the measure (m) and reset (r) operation (i.e. the gateMR 0).m+r+yis the Y basis variant of the measure (m) and reset (r) operation (i.e. the gateMRY 0).c+m+xis the two qubit variant (c) of measurement (m) in the X basis (x) (i.e. the gateMXX 1 2).shift+c+s+yis the inverse (shift) of the two qubit variant (c) of the square root (s) of the Y gate (y) (i.e. the gateSQRT_YY_DAG 1 2).
Note: to BoxSelect means to press down the left mouse button, drag the mouse
while holding the button down to outline a rectangular region, and then release
the mouse button.
Note: using shift modifies how the mouse updates the current selection. When
shift is being held and selection S1 would be replaced by selection S2, the new
selection will instead be set to the union of S1 and S2.
Note: using ctrl modifies how the mouse updates the current selection. When
ctrl is being held and selection S1 would be replaced by selection S2, the new
selection will instead be set to the symmetric difference of S1 and S2.
LeftClick: Set current selection to clicked qubit (or to nothing, if clicking empty space).BoxSelect: Set current selection to boxed area.Alt+BoxSelect: Set current selection to boxed area, but only including the qubits with the same parity as the initially clicked qubit at the start of the box selection action. The specific parity being used depends on context. For example, when selecting a column of qubits, the row parity is used. When selecting a 2d region, the subgrid parity is used.
Crumble's source code can be served directly by a webserver. For example, serve crumble using python's built-in web server:
# from the root of Stim's git repository:
python -m http.server --directory glue/crumblethen open http://localhost:8000/crumble.html in a web browser.
A single-page version of crumble can be created using rollup-js and uglify-js:
# npm install -g rollup uglify-js
# from the root of Stim's git repository:
{
cat glue/crumble/crumble.html | grep -v "^<script";
echo "<script>";
rollup glue/crumble/main.js | uglifyjs -c -m --mangle-props --toplevel;
echo "</script>";
} > crumble_single_page.html
Crumble's unit tests can be executed by opening the page test/test.html in a
web browser:
# from the root of Stim's git repository:
python -m http.server --directory glue/crumble &
firefox localhost:8000/test/test.html
# if page says "All X tests passed" then tests passed.
# see the browser console for a log of tests that were runUnit tests can also be run headless using NodeJS. Unit tests for functionality such as canvas drawing will be skipped when running headless:
# from the root of Stim's git repository:
node glue/crumble/run_tests_headless.js
# will end with 'all tests passed' if all tests passed