> ## Documentation Index
> Fetch the complete documentation index at: https://tsim.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# From Stim to Tsim

```python theme={null}
import tsim
import stim
```

If you have been using Stim, using Tsim should feel very similar. In many cases, replacing `stim` with `tsim` should just work.

If you're not yet familiar with Stim, there are lots of resources out there: For example, [Stim's getting\_started notebook](https://github.com/quantumlib/Stim/blob/main/doc/getting_started.ipynb), [Craig Gidney's Stim tutorial on YouTube](https://www.youtube.com/watch?v=sprDaLxPVNI), [Google's course on QEC](https://www.coursera.org/learn/quantum-error-correction#modules), or [this Stim 101 tutorial](https://www.youtube.com/watch?v=LiT6NDQcOm0).

### Non-Clifford instructions

Tsim extends the Stim text format with the non-Clifford instructions `T`, `T_DAG`, `R_X`, `R_Y`, and `R_Z`, `U3`. Rotation angles are specified in units of π.

```python theme={null}
c = tsim.Circuit("""
    T 0
    T_DAG 0
    R_X(0.1) 0
    R_Y(0.2) 0
    R_Z(0.3) 0
    U3(0.1, 0.2, 0.3) 0
""")
c.diagram(height=150)
```

<iframe
  srcDoc="<!doctype html><html><head><meta charset=&#x22;utf-8&#x22;><style>html,body{margin:0;padding:0;height:100%;overflow:hidden;}</style></head><body><div data-tsim-zoom=&#x22;tsim-zoom-001&#x22; style=&#x22;width:100%; height:100%; box-sizing:border-box; font-size:0; line-height:0; overflow:auto; background:white; border:none; position:relative;&#x22;>
<div style=&#x22;display:inline-block; overflow:hidden; width:450.0px; height:150.0px;&#x22;>
<div style=&#x22;transform-origin:0 0; display:block; width:480.0px; height:160.0px; transform:scale(0.9375);&#x22;>
<svg width=&#x22;480.0&#x22; height=&#x22;160.0&#x22; xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 480 160&#x22; version=&#x22;1.1&#x22;>
<g id=&#x22;qubit_lines&#x22;>
<path id=&#x22;qubit_line:0&#x22; d=&#x22;M64,64 L448,64 &#x22; stroke=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;end&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;12&#x22; x=&#x22;64&#x22; y=&#x22;64&#x22;>q0</text>
</g>
<rect x=&#x22;80&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;96&#x22; y=&#x22;64&#x22;>T</text><rect x=&#x22;144&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;160&#x22; y=&#x22;64&#x22;>T<tspan baseline-shift=&#x22;super&#x22; font-size=&#x22;14&#x22;>†</tspan></text><rect x=&#x22;208&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;224&#x22; y=&#x22;64&#x22;>R<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;14&#x22;>X</tspan></text><text dominant-baseline=&#x22;hanging&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;10&#x22; stroke=&#x22;black&#x22; x=&#x22;224&#x22; y=&#x22;84&#x22;>0.1π</text>
<rect x=&#x22;272&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;288&#x22; y=&#x22;64&#x22;>R<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;14&#x22;>Y</tspan></text><text dominant-baseline=&#x22;hanging&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;10&#x22; stroke=&#x22;black&#x22; x=&#x22;288&#x22; y=&#x22;84&#x22;>0.2π</text>
<rect x=&#x22;336&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;352&#x22; y=&#x22;64&#x22;>R<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;14&#x22;>Z</tspan></text><text dominant-baseline=&#x22;hanging&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;10&#x22; stroke=&#x22;black&#x22; x=&#x22;352&#x22; y=&#x22;84&#x22;>0.3π</text>
<rect x=&#x22;400&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;416&#x22; y=&#x22;64&#x22;>U<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;14&#x22;>3</tspan></text></svg>
</div>
</div>
</div>
<script>
(function() {
var wrap = document.querySelector('[data-tsim-zoom=&#x22;tsim-zoom-001&#x22;]');
if (!wrap || wrap.dataset.tsimZoomInit) return;
wrap.dataset.tsimZoomInit = &#x22;1&#x22;;
var size = wrap.firstElementChild;
var xform = size.firstElementChild;
var natW = 480.0;
var natH = 160.0;
var scale = 0.9375;
var cw = wrap.clientWidth;
if (cw > 0 && natW > 0) {
/* keep height-fit initial scale */
}
function apply() {
xform.style.transform = 'scale(' + scale + ')';
size.style.width = (natW * scale) + 'px';
size.style.height = (natH * scale) + 'px';
}
apply();
wrap.addEventListener('wheel', function(e) {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
var rect = wrap.getBoundingClientRect();
var mx = e.clientX - rect.left + wrap.scrollLeft;
var my = e.clientY - rect.top + wrap.scrollTop;
var factor = Math.exp(-e.deltaY * 0.01);
var newScale = Math.min(Math.max(0.02, scale * factor), 40);
var ratio = newScale / scale;
scale = newScale;
apply();
wrap.scrollLeft = mx * ratio - (e.clientX - rect.left);
wrap.scrollTop = my * ratio - (e.clientY - rect.top);
}
}, { passive: false });
})();
</script></body></html>"
  width="100%"
  height="154"
  style={{border: "1px solid #eee", borderRadius: "0.5rem"}}
  title="Circuit diagram 1"
  loading="lazy"
/>

### Detector Reference Samples

There are a few differences between the two packages. For example, Stim's detector sampler will output results relative to a noiseless reference sample. For example, in the following circuit, detector and observable bits will always be `False`:

```python theme={null}
circuit_str = """
    X 0
    M 0
    DETECTOR rec[-1]
    OBSERVABLE_INCLUDE(0) rec[-1]
    """
c = stim.Circuit(circuit_str)
stim_sampler = c.compile_detector_sampler(seed=None)
samples = stim_sampler.sample(shots=5, append_observables=True)
print(samples)
```

```text title="Output" theme={null}
[[False False]
 [False False]
 [False False]
 [False False]
 [False False]]
```

By default, Tsim reports actual detector and observable bits. To match Stim's behavior, set `use_detector_reference_sample=True` and `use_observable_reference_sample=True`. This computes a noiseless reference sample and XORs it with the results.

```python theme={null}
c = tsim.Circuit(circuit_str)
tsim_sampler = c.compile_detector_sampler(seed=0)

# Without reference sample (default): actual detector/observable values
samples = tsim_sampler.sample(shots=5, append_observables=True)
print("Without reference sample:")
print(samples)

# With reference sample: matches Stim behavior
samples_ref = tsim_sampler.sample(
    shots=5,
    append_observables=True,
    use_detector_reference_sample=True,
    use_observable_reference_sample=True,
)
print("\nWith reference sample:")
print(samples_ref)
```

```text title="Output" theme={null}
Without reference sample:
[[ True  True]
 [ True  True]
 [ True  True]
 [ True  True]
 [ True  True]]



With reference sample:
[[False False]
 [False False]
 [False False]
 [False False]
 [False False]]
```

### Batch size and just-in-time compilation

Tsim's samplers also have a `batch_size` argument, which does not exist in Stim. This parameter controls the number of shots sampled in parallel.

When `batch_size` is not specified, it is automatically chosen based on available device memory (GPU VRAM or system RAM). To achieve maximum performance on a GPU, you can also set `batch_size` explicitly.

```python theme={null}
tsim_sampler.sample(shots=1_000_000, batch_size=100_000)
```

```text title="Output" theme={null}
array([[ True],
       [ True],
       [ True],
       ...,
       [ True],
       [ True],
       [ True]], shape=(1000000, 1))
```

Tsim uses `jax` just-in-time compilation, which is triggered upon first execution of the `sample` function. This means that subsequent calls to `sample` with the same parameters will be faster. Note that recompilation is triggered whenever the `batch_size` is changed.

### Decomposition strategies

Tsim supports three stabilizer rank decomposition strategies: `"cat5"` (default), `"bss"`, and `"cutting"`. The strategy can be passed to `compile_sampler` or `compile_detector_sampler`:

```python theme={null}
c.compile_detector_sampler(strategy="cutting")
```

```text title="Output" theme={null}
CompiledDetectorSampler(0 direct, 4 graphs, 0 error channel bits, 1 outputs for largest cc, ≤ 1 parameters, 2 A terms, 0 B terms, 0 C terms, 0 D terms, 152 B)
```

Different strategies can yield different performance depending on the circuit structure. If sampling is slow, it can be worth trying an alternative strategy.

### Visualization methods

Tsim supports a subset of Stim's visualization methods. Since Tsim is based on ZX diagrams, it also provides visualization via `pyzx`.

```python theme={null}
c = tsim.Circuit("""
    RX 0 1
    TICK
    T 0
    TICK
    CNOT 0 1
    TICK
    U3(0.1, 0.2, 0.3) 1
    TICK
    M 0 1
""")
c.diagram("timeline-svg", height=150)
```

<iframe
  srcDoc="<!doctype html><html><head><meta charset=&#x22;utf-8&#x22;><style>html,body{margin:0;padding:0;height:100%;overflow:hidden;}</style></head><body><div data-tsim-zoom=&#x22;tsim-zoom-002&#x22; style=&#x22;width:100%; height:100%; box-sizing:border-box; font-size:0; line-height:0; overflow:auto; background:white; border:none; position:relative;&#x22;>
<div style=&#x22;display:inline-block; overflow:hidden; width:278.57142857142856px; height:150.0px;&#x22;>
<div style=&#x22;transform-origin:0 0; display:block; width:416.0px; height:224.0px; transform:scale(0.6696428571428571);&#x22;>
<svg width=&#x22;416.0&#x22; height=&#x22;224.0&#x22; xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 416 224&#x22; version=&#x22;1.1&#x22;>
<g id=&#x22;qubit_lines&#x22;>
<path id=&#x22;qubit_line:0&#x22; d=&#x22;M64,64 L384,64 &#x22; stroke=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;end&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;12&#x22; x=&#x22;64&#x22; y=&#x22;64&#x22;>q0</text>
<path id=&#x22;qubit_line:1&#x22; d=&#x22;M64,128 L384,128 &#x22; stroke=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;end&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;12&#x22; x=&#x22;64&#x22; y=&#x22;128&#x22;>q1</text>
</g>
<rect x=&#x22;80&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;26&#x22; x=&#x22;96&#x22; y=&#x22;64&#x22; fill=&#x22;white&#x22;>R<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;16&#x22;>X</tspan></text>
<rect x=&#x22;80&#x22; y=&#x22;112&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;26&#x22; x=&#x22;96&#x22; y=&#x22;128&#x22; fill=&#x22;white&#x22;>R<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;16&#x22;>X</tspan></text>
<rect x=&#x22;144&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;160&#x22; y=&#x22;64&#x22;>T</text><path d=&#x22;M224,64 L224,128 &#x22; stroke=&#x22;black&#x22;/>
<circle cx=&#x22;224&#x22; cy=&#x22;64&#x22; r=&#x22;12&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle cx=&#x22;224&#x22; cy=&#x22;128&#x22; r=&#x22;12&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<path d=&#x22;M212,128 L236,128 M224,116 L224,140 &#x22; stroke=&#x22;black&#x22;/>
<rect x=&#x22;272&#x22; y=&#x22;112&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;288&#x22; y=&#x22;128&#x22;>U<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;14&#x22;>3</tspan></text><rect x=&#x22;336&#x22; y=&#x22;48&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;352&#x22; y=&#x22;64&#x22; fill=&#x22;white&#x22;>M</text>
<text text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;8&#x22; x=&#x22;352&#x22; y=&#x22;44&#x22;>rec[0]</text>
<rect x=&#x22;336&#x22; y=&#x22;112&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;352&#x22; y=&#x22;128&#x22; fill=&#x22;white&#x22;>M</text>
<text text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;8&#x22; x=&#x22;352&#x22; y=&#x22;108&#x22;>rec[1]</text>
</svg>
</div>
</div>
</div>
<script>
(function() {
var wrap = document.querySelector('[data-tsim-zoom=&#x22;tsim-zoom-002&#x22;]');
if (!wrap || wrap.dataset.tsimZoomInit) return;
wrap.dataset.tsimZoomInit = &#x22;1&#x22;;
var size = wrap.firstElementChild;
var xform = size.firstElementChild;
var natW = 416.0;
var natH = 224.0;
var scale = 0.6696428571428571;
var cw = wrap.clientWidth;
if (cw > 0 && natW > 0) {
/* keep height-fit initial scale */
}
function apply() {
xform.style.transform = 'scale(' + scale + ')';
size.style.width = (natW * scale) + 'px';
size.style.height = (natH * scale) + 'px';
}
apply();
wrap.addEventListener('wheel', function(e) {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
var rect = wrap.getBoundingClientRect();
var mx = e.clientX - rect.left + wrap.scrollLeft;
var my = e.clientY - rect.top + wrap.scrollTop;
var factor = Math.exp(-e.deltaY * 0.01);
var newScale = Math.min(Math.max(0.02, scale * factor), 40);
var ratio = newScale / scale;
scale = newScale;
apply();
wrap.scrollLeft = mx * ratio - (e.clientX - rect.left);
wrap.scrollTop = my * ratio - (e.clientY - rect.top);
}
}, { passive: false });
})();
</script></body></html>"
  width="100%"
  height="154"
  style={{border: "1px solid #eee", borderRadius: "0.5rem"}}
  title="Circuit diagram 2"
  loading="lazy"
/>

```python theme={null}
c.diagram("timeslice-svg", height=80, rows=1)
```

<iframe
  srcDoc="<!doctype html><html><head><meta charset=&#x22;utf-8&#x22;><style>html,body{margin:0;padding:0;height:100%;overflow:hidden;}</style></head><body><div data-tsim-zoom=&#x22;tsim-zoom-003&#x22; style=&#x22;width:100%; height:100%; box-sizing:border-box; font-size:0; line-height:0; overflow:auto; background:white; border:none; position:relative;&#x22;>
<div style=&#x22;display:inline-block; overflow:hidden; width:604.8px; height:80.0px;&#x22;>
<div style=&#x22;transform-origin:0 0; display:block; width:1209.6px; height:160.0px; transform:scale(0.5);&#x22;>
<svg width=&#x22;1209.6&#x22; height=&#x22;160.0&#x22; xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 1209.6 160&#x22; version=&#x22;1.1&#x22;>
<g id=&#x22;qubit_dots&#x22;>
<circle id=&#x22;qubit_dot:0:0&#x22; cx=&#x22;80&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:1:0&#x22; cx=&#x22;144&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:0:1&#x22; cx=&#x22;326.4&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:1:1&#x22; cx=&#x22;390.4&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:0:2&#x22; cx=&#x22;572.8&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:1:2&#x22; cx=&#x22;636.8&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:0:3&#x22; cx=&#x22;819.2&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:1:3&#x22; cx=&#x22;883.2&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:0:4&#x22; cx=&#x22;1065.6&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle id=&#x22;qubit_dot:1:4&#x22; cx=&#x22;1129.6&#x22; cy=&#x22;80&#x22; r=&#x22;2&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
</g>
<rect x=&#x22;64&#x22; y=&#x22;64&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;26&#x22; x=&#x22;80&#x22; y=&#x22;80&#x22; fill=&#x22;white&#x22;>R<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;16&#x22;>X</tspan></text>
<rect x=&#x22;128&#x22; y=&#x22;64&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;26&#x22; x=&#x22;144&#x22; y=&#x22;80&#x22; fill=&#x22;white&#x22;>R<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;16&#x22;>X</tspan></text>
<rect x=&#x22;310.4&#x22; y=&#x22;64&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;326.4&#x22; y=&#x22;80&#x22;>T</text><path d=&#x22;M572.8,80 L636.8,80 &#x22; fill=&#x22;none&#x22; stroke=&#x22;black&#x22; stroke-width=&#x22;5&#x22;/>
<circle cx=&#x22;572.8&#x22; cy=&#x22;80&#x22; r=&#x22;12&#x22; stroke=&#x22;none&#x22; fill=&#x22;black&#x22;/>
<circle cx=&#x22;636.8&#x22; cy=&#x22;80&#x22; r=&#x22;12&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<path d=&#x22;M624.8,80 L648.8,80 M636.8,68 L636.8,92 &#x22; stroke=&#x22;black&#x22;/>
<rect x=&#x22;867.2&#x22; y=&#x22;64&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;white&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;883.2&#x22; y=&#x22;80&#x22;>U<tspan baseline-shift=&#x22;sub&#x22; font-size=&#x22;14&#x22;>3</tspan></text><rect x=&#x22;1049.6&#x22; y=&#x22;64&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;1065.6&#x22; y=&#x22;80&#x22; fill=&#x22;white&#x22;>M</text>
<rect x=&#x22;1113.6&#x22; y=&#x22;64&#x22; width=&#x22;32&#x22; height=&#x22;32&#x22; stroke=&#x22;black&#x22; fill=&#x22;black&#x22;/>
<text dominant-baseline=&#x22;central&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;monospace&#x22; font-size=&#x22;30&#x22; x=&#x22;1129.6&#x22; y=&#x22;80&#x22; fill=&#x22;white&#x22;>M</text>
<g id=&#x22;tick_borders&#x22;>
<text dominant-baseline=&#x22;hanging&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;serif&#x22; font-size=&#x22;18&#x22; transform=&#x22;rotate(90)&#x22; x=&#x22;80&#x22; y=&#x22;-218&#x22;>Tick 0</text>
<rect id=&#x22;tick_border:0:0_0:0&#x22; x=&#x22;0&#x22; y=&#x22;0&#x22; width=&#x22;224&#x22; height=&#x22;160&#x22; stroke=&#x22;black&#x22; fill=&#x22;none&#x22;/>
<text dominant-baseline=&#x22;hanging&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;serif&#x22; font-size=&#x22;18&#x22; transform=&#x22;rotate(90)&#x22; x=&#x22;80&#x22; y=&#x22;-464.4&#x22;>Tick 1</text>
<rect id=&#x22;tick_border:1:0_1:1&#x22; x=&#x22;246.4&#x22; y=&#x22;0&#x22; width=&#x22;224&#x22; height=&#x22;160&#x22; stroke=&#x22;black&#x22; fill=&#x22;none&#x22;/>
<text dominant-baseline=&#x22;hanging&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;serif&#x22; font-size=&#x22;18&#x22; transform=&#x22;rotate(90)&#x22; x=&#x22;80&#x22; y=&#x22;-710.8&#x22;>Tick 2</text>
<rect id=&#x22;tick_border:2:0_2:2&#x22; x=&#x22;492.8&#x22; y=&#x22;0&#x22; width=&#x22;224&#x22; height=&#x22;160&#x22; stroke=&#x22;black&#x22; fill=&#x22;none&#x22;/>
<text dominant-baseline=&#x22;hanging&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;serif&#x22; font-size=&#x22;18&#x22; transform=&#x22;rotate(90)&#x22; x=&#x22;80&#x22; y=&#x22;-957.2&#x22;>Tick 3</text>
<rect id=&#x22;tick_border:3:0_3:3&#x22; x=&#x22;739.2&#x22; y=&#x22;0&#x22; width=&#x22;224&#x22; height=&#x22;160&#x22; stroke=&#x22;black&#x22; fill=&#x22;none&#x22;/>
<text dominant-baseline=&#x22;hanging&#x22; text-anchor=&#x22;middle&#x22; font-family=&#x22;serif&#x22; font-size=&#x22;18&#x22; transform=&#x22;rotate(90)&#x22; x=&#x22;80&#x22; y=&#x22;-1203.6&#x22;>Tick 4</text>
<rect id=&#x22;tick_border:4:0_4:4&#x22; x=&#x22;985.6&#x22; y=&#x22;0&#x22; width=&#x22;224&#x22; height=&#x22;160&#x22; stroke=&#x22;black&#x22; fill=&#x22;none&#x22;/>
</g>
</svg>
</div>
</div>
</div>
<script>
(function() {
var wrap = document.querySelector('[data-tsim-zoom=&#x22;tsim-zoom-003&#x22;]');
if (!wrap || wrap.dataset.tsimZoomInit) return;
wrap.dataset.tsimZoomInit = &#x22;1&#x22;;
var size = wrap.firstElementChild;
var xform = size.firstElementChild;
var natW = 1209.6;
var natH = 160.0;
var scale = 0.5;
var cw = wrap.clientWidth;
if (cw > 0 && natW > 0) {
/* keep height-fit initial scale */
}
function apply() {
xform.style.transform = 'scale(' + scale + ')';
size.style.width = (natW * scale) + 'px';
size.style.height = (natH * scale) + 'px';
}
apply();
wrap.addEventListener('wheel', function(e) {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
var rect = wrap.getBoundingClientRect();
var mx = e.clientX - rect.left + wrap.scrollLeft;
var my = e.clientY - rect.top + wrap.scrollTop;
var factor = Math.exp(-e.deltaY * 0.01);
var newScale = Math.min(Math.max(0.02, scale * factor), 40);
var ratio = newScale / scale;
scale = newScale;
apply();
wrap.scrollLeft = mx * ratio - (e.clientX - rect.left);
wrap.scrollTop = my * ratio - (e.clientY - rect.top);
}
}, { passive: false });
})();
</script></body></html>"
  width="100%"
  height="84"
  style={{border: "1px solid #eee", borderRadius: "0.5rem"}}
  title="Circuit diagram 3"
  loading="lazy"
/>

```python theme={null}
c.diagram("pyzx");
```

<iframe
  srcDoc="<!doctype html><html><head><meta charset=&#x22;utf-8&#x22;><style>html,body{margin:0;padding:0;height:100%;overflow:hidden;}[id^=&#x22;graph-output-&#x22;]{width:100%;height:100%;overflow:auto;box-sizing:border-box;}</style></head><body><div style=&#x22;overflow:auto; background-color: white&#x22; id=&#x22;graph-output-001&#x22;></div><script type=&#x22;module&#x22;>
var d3;
if (d3 == null) { d3 = await import(&#x22;https://esm.sh/d3@5&#x22;); }
var _settings_colors = JSON.parse('{&#x22;edge&#x22;: &#x22;#000000&#x22;, &#x22;Hedge&#x22;: &#x22;#0088ff&#x22;, &#x22;Xedge&#x22;: &#x22;#999999&#x22;, &#x22;Bedge&#x22;: &#x22;#000000&#x22;, &#x22;HBedge&#x22;: &#x22;#0088ff&#x22;, &#x22;boundary&#x22;: &#x22;#000000&#x22;, &#x22;X&#x22;: &#x22;#ff8888&#x22;, &#x22;Y&#x22;: &#x22;#aabbff&#x22;, &#x22;Z&#x22;: &#x22;#ccffcc&#x22;, &#x22;H&#x22;: &#x22;#ffff66&#x22;, &#x22;W&#x22;: &#x22;#000000&#x22;, &#x22;Zalt&#x22;: &#x22;#ccffcc&#x22;, &#x22;Walt&#x22;: &#x22;#000000&#x22;, &#x22;Zbold&#x22;: &#x22;#ccffcc&#x22;, &#x22;Xbold&#x22;: &#x22;#ff8888&#x22;, &#x22;Xdark&#x22;: &#x22;#ff8888&#x22;, &#x22;Ydark&#x22;: &#x22;#aabbff&#x22;, &#x22;Zdark&#x22;: &#x22;#99dd99&#x22;}');
// PyZX - Python library for quantum circuit rewriting 
//        and optimisation using the ZX-calculus
// Copyright (C) 2018 - Aleks Kissinger and John van de Wetering

// Licensed under the Apache License, Version 2.0 (the &#x22;License&#x22;);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//    http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an &#x22;AS IS&#x22; BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// styling functions
function nodeColor(t) {
if (t == 0) return _settings_colors['boundary'];
else if (t == 1) return _settings_colors['Z']; // &#x22;#ccffcc&#x22;;
else if (t == 2) return _settings_colors['X']; // &#x22;#ff8888&#x22;;
else if (t == 3) return _settings_colors['H']; // &#x22;yellow&#x22;;
else if (t == 4) return _settings_colors['W']; // &#x22;black&#x22;;
else if (t == 5) return _settings_colors['Walt']; // &#x22;black&#x22;;
else if (t == 6) return _settings_colors['Zalt']; // &#x22;#ccffcc&#x22;;
else if (t == 7) return _settings_colors['Zbold']; // &#x22;#ccffcc&#x22; bold Z
else if (t == 8) return _settings_colors['Xbold']; // &#x22;#ff8888&#x22; bold X
}

function edgeColor(t) {
if (t == 1) return _settings_colors['edge']; //&#x22;black&#x22;;
else if (t == 2) return _settings_colors['Hedge']; // &#x22;#08f&#x22;;
else if (t == 3) return _settings_colors['Xedge']; // &#x22;gray&#x22;;
else if (t == 4) return _settings_colors['Bedge']; // &#x22;black&#x22; bold
else if (t == 5) return _settings_colors['HBedge']; // &#x22;#0088ff&#x22; bold hadamard
}

function isBoldEdge(t) {
return t == 4 || t == 5;
}

function webColor(t) {
if (t == 'X') return _settings_colors['Xdark'];
else if (t == 'Y') return _settings_colors['Ydark'];
else if (t == 'Z') return _settings_colors['Zdark'];
else if (t == 'I') return '#dddddd';
}

function nodeStyle(selected, t) {
var bold = (t == 7 || t == 8);
if (selected) return &#x22;stroke-width: &#x22; + (bold ? &#x22;4&#x22; : &#x22;2&#x22;) + &#x22;px; stroke: #00f&#x22;;
return &#x22;stroke-width: &#x22; + (bold ? &#x22;3&#x22; : &#x22;1.5&#x22;) + &#x22;px&#x22;;
}

var symbolGround = {
draw: function(context, size){
let s = size/2;

context.moveTo(0,-s);
context.lineTo(0,0);

context.moveTo(-s,0);
context.lineTo(s,0);

context.moveTo(-2*s/3,s/3);
context.lineTo(2*s/3,s/3);

context.moveTo(-s/3,2*s/3);
context.lineTo(s/3,2*s/3);
}
}

function showGraph(tag, graph, width, height, scale, node_size, auto_hbox, show_labels, scalar_str) {
var ntab = {};

var groundOffset = 2.5 * node_size;

graph.nodes.forEach(function(d) {
ntab[d.name] = d;
d.selected = false;
d.previouslySelected = false;
d.nhd = [];
});

var spiders_and_boundaries = graph.nodes.filter(function(d) {
return d.t != 3;
});

graph.links.forEach(function(d) {
var s = ntab[d.source];
var t = ntab[d.target];
d.source = s;
d.target = t;
s.nhd.push(t);
t.nhd.push(s);
});

graph.pauli_web.forEach(function(d) {
var s = ntab[d.source];
var t = ntab[d.target];
d.source = s;
d.target = t;
});

var shiftKey;

// SETUP SVG ITEMS

var svg = d3.select(tag)
//.attr(&#x22;tabindex&#x22;, 1)
.on(&#x22;keydown.brush&#x22;, function() {shiftKey = d3.event.shiftKey || d3.event.metaKey;})
.on(&#x22;keyup.brush&#x22;, function() {shiftKey = d3.event.shiftKey || d3.event.metaKey;})
//.each(function() { this.focus(); })
.append(&#x22;svg&#x22;)
.attr(&#x22;style&#x22;, &#x22;max-width: none; max-height: none&#x22;)
.attr(&#x22;width&#x22;, width)
.attr(&#x22;height&#x22;, height);

var web = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;web&#x22;)
.selectAll(&#x22;line&#x22;)
.data(graph.pauli_web)
.enter().append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, function(d) { return webColor(d.t); })
.attr(&#x22;fill&#x22;, &#x22;transparent&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 7px&#x22;);

var link = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;link&#x22;)
.selectAll(&#x22;line&#x22;)
.data(graph.links)
.enter().append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, function(d) { return edgeColor(d.t); })
.attr(&#x22;fill&#x22;, &#x22;transparent&#x22;)
.attr(&#x22;style&#x22;, function(d) { return isBoldEdge(d.t) ? &#x22;stroke-width: 3.5px&#x22; : &#x22;stroke-width: 1.5px&#x22;; });

var brush = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;brush&#x22;);

var node = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;node&#x22;)
.selectAll(&#x22;g&#x22;)
.data(graph.nodes)
.enter().append(&#x22;g&#x22;)
.attr(&#x22;transform&#x22;, function(d) {
return &#x22;translate(&#x22; + d.x + &#x22;,&#x22; + d.y +&#x22;)&#x22;;
});

// Draw a ground symbol connected to the node.
node.filter(function(d) { return d.ground; })
.append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 1.5px&#x22;)
.attr(&#x22;fill&#x22;, &#x22;none&#x22;)
.attr(&#x22;d&#x22;, &#x22;M 0 0 L 0 &#x22;+(groundOffset))
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);
node.filter(function(d) { return d.ground; })
.append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 1.5px&#x22;)
.attr(&#x22;fill&#x22;, &#x22;none&#x22;)
.attr(&#x22;d&#x22;, d3.symbol().type(symbolGround).size(node_size*1.5))
.attr(&#x22;transform&#x22;, &#x22;translate(0,&#x22;+groundOffset+&#x22;)&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

node.filter(function(d) { return d.t != 3 && d.t != 5 && d.t != 6; })
.append(&#x22;circle&#x22;)
.attr(&#x22;r&#x22;, function(d) {
if (d.t == 0) return 0.5 * node_size;
else if (d.t == 4) return 0.25 * node_size;
else return node_size;
})
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;stroke-width&#x22;, function(d) { return (d.t == 7 || d.t == 8) ? 3 : 1.5; })
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

var hbox = node.filter(function(d) { return d.t == 3; });

hbox.append(&#x22;rect&#x22;)
.attr(&#x22;x&#x22;, -0.75 * node_size).attr(&#x22;y&#x22;, -0.75 * node_size)
.attr(&#x22;width&#x22;, node_size * 1.5).attr(&#x22;height&#x22;, node_size * 1.5)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

// draw a triangle for d.t == 5
node.filter(function(d) { return d.t == 5; })
.append(&#x22;path&#x22;)
.attr(&#x22;d&#x22;, &#x22;M 0 0 L &#x22;+node_size+&#x22; &#x22;+node_size+&#x22; L -&#x22;+node_size+&#x22; &#x22;+node_size+&#x22; Z&#x22;)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;)
.attr(&#x22;transform&#x22;, &#x22;translate(&#x22; + (-node_size/2) + &#x22;, 0) rotate(-90)&#x22;);

// draw a square for Z box: d.t == 6
node.filter(function(d) { return d.t == 6; })
.append(&#x22;rect&#x22;)
.attr(&#x22;x&#x22;, -0.75 * node_size).attr(&#x22;y&#x22;, -0.75 * node_size)
.attr(&#x22;width&#x22;, node_size * 1.5).attr(&#x22;height&#x22;, node_size * 1.5)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

node.filter(function(d) { return d.phase != '' && d.phase.indexOf('[') === -1; })
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, 0.7 * node_size + 14)
.text(function (d) { return d.phase })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;12px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#00d&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');

node.filter(function(d) { return d.phase != '' && d.phase.indexOf('[') !== -1; })
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, -0.7 * node_size - 8)
.text(function (d) { return d.phase })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;12px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;black&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');

if (show_labels) {
node.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, -0.7 * node_size - 8)
.text(function (d) { return d.name; })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;10px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#999&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');
}

// Display the chosen data fields over the node.
node.filter(d => d.vdata.length > 0)
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, d => -0.7 * node_size - 14 - 10 * d.vdata.length)
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;8px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#c66&#x22;)
.attr('style', 'pointer-events: none; user-select: none;')
.selectAll(&#x22;tspan&#x22;)
.data(d => d.vdata)
.enter()
.append(&#x22;tspan&#x22;)
.attr(&#x22;x&#x22;, &#x22;0&#x22;)
.attr(&#x22;dy&#x22;, &#x22;1.2em&#x22;)
.text(x => x.join(&#x22;: &#x22;));

if (scalar_str != &#x22;&#x22;) {
svg.append(&#x22;text&#x22;)
.text(scalar_str)
.attr(&#x22;x&#x22;, 60).attr(&#x22;y&#x22;, 40)
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
}

function update_hboxes() {
if (auto_hbox) {
var pos = {};
hbox.attr(&#x22;transform&#x22;, function(d) {
// calculate barycenter of non-hbox neighbours, then nudge a bit
// to the NE.
var x=0,y=0,sz=0;
for (var i = 0; i < d.nhd.length; ++i) {
if (d.nhd[i].t != 3) {
sz++;
x += d.nhd[i].x;
y += d.nhd[i].y;
}
}

offset = 0.25 * scale;

if (sz != 0) {
x = (x/sz) + offset;
y = (y/sz) - offset;

while (pos[[x,y]]) {
x += offset;
}
d.x = x;
d.y = y;
pos[[x,y]] = true;
}

return &#x22;translate(&#x22;+d.x+&#x22;,&#x22;+d.y+&#x22;)&#x22;;
});
}
}

update_hboxes();

var link_curve = function(d) {
var x1 = d.source.x, x2 = d.target.x, y1 = d.source.y, y2 = d.target.y;
if (x1 == x2 && y1 == y2 && d.num_parallel == 1) {
var cx1 = x1 - 40;
var cy1 = y1 - 40;
var cx2 = x1 + 40;
var cy2 = y1 - 40;
return `M ${x1} ${y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x2} ${y2}`;
} else if (x1 == x2 && y1 == y2) {
var pos = d.index + 1;
var cx1 = x1 - 20 - pos * 10;
var cy1 = y1 - 20 - pos * 10;
var cx2 = x1 + 20 + pos * 10;
var cy2 = y1 - 20 - pos * 10;
return `M ${x1} ${y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x2} ${y2}`;
} else if (d.num_parallel == 1) {
return `M ${x1} ${y1} L ${x2} ${y2}`;
} else {
var dx = x2 - x1, dy = y2 - y1;
var midx = 0.5 * (x1 + x2), midy = 0.5 * (y1 + y2);
var pos = (d.index / (d.num_parallel-1)) - 0.5;
var cx = midx - pos * dy;
var cy = midy + pos * dx;
return `M ${x1} ${y1} Q ${cx} ${cy}, ${x2} ${y2}`;
// return `M ${x1} ${y1} L ${x2} ${y2}`;
}
};
link.attr(&#x22;d&#x22;, link_curve);


var web_curve = function(d) {
var x1 = d.source.x, x2 = (x1 + d.target.x)/2, y1 = d.source.y, y2 = (y1 + d.target.y)/2;
return `M ${x1} ${y1} L ${x2} ${y2}`;
}
web.attr(&#x22;d&#x22;, web_curve);

// EVENTS FOR DRAGGING AND SELECTION

node.on(&#x22;mousedown&#x22;, function(d) {
if (shiftKey) {
d3.select(this).selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, nodeStyle(d.selected = !d.selected, d.t));
d3.event.stopImmediatePropagation();
} else if (!d.selected) {
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(p) { return nodeStyle(p.selected = d === p, p.t); });
}
})
.call(d3.drag().on(&#x22;drag&#x22;, function(d) {
var dx = d3.event.dx;
var dy = d3.event.dy;
// node.filter(function(d) { return d.selected; })
//     .attr(&#x22;cx&#x22;, function(d) { return d.x += dx; })
//     .attr(&#x22;cy&#x22;, function(d) { return d.y += dy; });
node.filter(function(d) { return d.selected; })
.attr(&#x22;transform&#x22;, function(d) {
d.x += dx;
d.y += dy;
return &#x22;translate(&#x22; + d.x + &#x22;,&#x22; + d.y +&#x22;)&#x22;;
});

update_hboxes();

link.filter(function(d) { return d.source.selected || d.target.selected ||
(auto_hbox && d.source.t == 3); })
.attr(&#x22;d&#x22;, link_curve);
web.filter(function(d) { return d.source.selected || d.target.selected; })
.attr(&#x22;d&#x22;, web_curve);
}));

brush.call(d3.brush().keyModifiers(false)
.extent([[0, 0], [width, height]])
.on(&#x22;start&#x22;, function() {
if (d3.event.sourceEvent.type !== &#x22;end&#x22;) {
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(d) {
return nodeStyle(
d.selected = d.previouslySelected = shiftKey &&
d.selected, d.t);
});
}
})
.on(&#x22;brush&#x22;, function() {
if (d3.event.sourceEvent.type !== &#x22;end&#x22;) {
var selection = d3.event.selection;
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(d) {
return nodeStyle(d.selected = d.previouslySelected ^
(selection != null
&& selection[0][0] <= d.x && d.x < selection[1][0]
&& selection[0][1] <= d.y && d.y < selection[1][1]), d.t);
});
}
})
.on(&#x22;end&#x22;, function() {
if (d3.event.selection != null) {
d3.select(this).call(d3.event.target.move, null);
}
}));
}


showGraph('#graph-output-001',
JSON.parse('{&#x22;nodes&#x22;: [{&#x22;name&#x22;: &#x22;0&#x22;, &#x22;x&#x22;: 50.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 8, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;1&#x22;, &#x22;x&#x22;: 100.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;2&#x22;, &#x22;x&#x22;: 50.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 8, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;3&#x22;, &#x22;x&#x22;: 150.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 8, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;4&#x22;, &#x22;x&#x22;: 150.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;5&#x22;, &#x22;x&#x22;: 550.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 1, &#x22;phase&#x22;: &#x22;rec[0]&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;6&#x22;, &#x22;x&#x22;: 200.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;3\u03c0/10&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;7&#x22;, &#x22;x&#x22;: 250.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 8, &#x22;phase&#x22;: &#x22;\u03c0/2&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;8&#x22;, &#x22;x&#x22;: 300.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;9&#x22;, &#x22;x&#x22;: 350.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/10&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;10&#x22;, &#x22;x&#x22;: 400.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 8, &#x22;phase&#x22;: &#x22;\u03c0/2&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;11&#x22;, &#x22;x&#x22;: 450.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;12&#x22;, &#x22;x&#x22;: 500.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/5&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;13&#x22;, &#x22;x&#x22;: 550.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 1, &#x22;phase&#x22;: &#x22;rec[1]&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;14&#x22;, &#x22;x&#x22;: 600.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 0, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;15&#x22;, &#x22;x&#x22;: 600.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 0, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}], &#x22;links&#x22;: [{&#x22;source&#x22;: &#x22;0&#x22;, &#x22;target&#x22;: &#x22;1&#x22;, &#x22;t&#x22;: 5, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;1&#x22;, &#x22;target&#x22;: &#x22;4&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;2&#x22;, &#x22;target&#x22;: &#x22;3&#x22;, &#x22;t&#x22;: 5, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;3&#x22;, &#x22;target&#x22;: &#x22;6&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;3&#x22;, &#x22;target&#x22;: &#x22;4&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;4&#x22;, &#x22;target&#x22;: &#x22;5&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;5&#x22;, &#x22;target&#x22;: &#x22;14&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;6&#x22;, &#x22;target&#x22;: &#x22;7&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;7&#x22;, &#x22;target&#x22;: &#x22;8&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;8&#x22;, &#x22;target&#x22;: &#x22;9&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;9&#x22;, &#x22;target&#x22;: &#x22;10&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;10&#x22;, &#x22;target&#x22;: &#x22;11&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;11&#x22;, &#x22;target&#x22;: &#x22;12&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;12&#x22;, &#x22;target&#x22;: &#x22;13&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;13&#x22;, &#x22;target&#x22;: &#x22;15&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}], &#x22;pauli_web&#x22;: []}'), 650, 200, 50,
10.0, false, false, '');
</script></body></html>"
  width="100%"
  height="212"
  style={{border: "1px solid #eee", borderRadius: "0.5rem"}}
  title="ZX diagram 1"
  loading="lazy"
/>

It can be interesting to look at the ZX diagram of more advanced Stim programs. For example, the following program measures a qubit and records the flipped measurement outcome. Based on this outcome, an X gate is applied to a different qubit:

```python theme={null}
tsim.Circuit("""
M !0
CNOT rec[-1] 1
""").diagram("pyzx");
```

<iframe
  srcDoc="<!doctype html><html><head><meta charset=&#x22;utf-8&#x22;><style>html,body{margin:0;padding:0;height:100%;overflow:hidden;}[id^=&#x22;graph-output-&#x22;]{width:100%;height:100%;overflow:auto;box-sizing:border-box;}</style></head><body><div style=&#x22;overflow:auto; background-color: white&#x22; id=&#x22;graph-output-002&#x22;></div><script type=&#x22;module&#x22;>
var d3;
if (d3 == null) { d3 = await import(&#x22;https://esm.sh/d3@5&#x22;); }
var _settings_colors = JSON.parse('{&#x22;edge&#x22;: &#x22;#000000&#x22;, &#x22;Hedge&#x22;: &#x22;#0088ff&#x22;, &#x22;Xedge&#x22;: &#x22;#999999&#x22;, &#x22;Bedge&#x22;: &#x22;#000000&#x22;, &#x22;HBedge&#x22;: &#x22;#0088ff&#x22;, &#x22;boundary&#x22;: &#x22;#000000&#x22;, &#x22;X&#x22;: &#x22;#ff8888&#x22;, &#x22;Y&#x22;: &#x22;#aabbff&#x22;, &#x22;Z&#x22;: &#x22;#ccffcc&#x22;, &#x22;H&#x22;: &#x22;#ffff66&#x22;, &#x22;W&#x22;: &#x22;#000000&#x22;, &#x22;Zalt&#x22;: &#x22;#ccffcc&#x22;, &#x22;Walt&#x22;: &#x22;#000000&#x22;, &#x22;Zbold&#x22;: &#x22;#ccffcc&#x22;, &#x22;Xbold&#x22;: &#x22;#ff8888&#x22;, &#x22;Xdark&#x22;: &#x22;#ff8888&#x22;, &#x22;Ydark&#x22;: &#x22;#aabbff&#x22;, &#x22;Zdark&#x22;: &#x22;#99dd99&#x22;}');
// PyZX - Python library for quantum circuit rewriting 
//        and optimisation using the ZX-calculus
// Copyright (C) 2018 - Aleks Kissinger and John van de Wetering

// Licensed under the Apache License, Version 2.0 (the &#x22;License&#x22;);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//    http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an &#x22;AS IS&#x22; BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// styling functions
function nodeColor(t) {
if (t == 0) return _settings_colors['boundary'];
else if (t == 1) return _settings_colors['Z']; // &#x22;#ccffcc&#x22;;
else if (t == 2) return _settings_colors['X']; // &#x22;#ff8888&#x22;;
else if (t == 3) return _settings_colors['H']; // &#x22;yellow&#x22;;
else if (t == 4) return _settings_colors['W']; // &#x22;black&#x22;;
else if (t == 5) return _settings_colors['Walt']; // &#x22;black&#x22;;
else if (t == 6) return _settings_colors['Zalt']; // &#x22;#ccffcc&#x22;;
else if (t == 7) return _settings_colors['Zbold']; // &#x22;#ccffcc&#x22; bold Z
else if (t == 8) return _settings_colors['Xbold']; // &#x22;#ff8888&#x22; bold X
}

function edgeColor(t) {
if (t == 1) return _settings_colors['edge']; //&#x22;black&#x22;;
else if (t == 2) return _settings_colors['Hedge']; // &#x22;#08f&#x22;;
else if (t == 3) return _settings_colors['Xedge']; // &#x22;gray&#x22;;
else if (t == 4) return _settings_colors['Bedge']; // &#x22;black&#x22; bold
else if (t == 5) return _settings_colors['HBedge']; // &#x22;#0088ff&#x22; bold hadamard
}

function isBoldEdge(t) {
return t == 4 || t == 5;
}

function webColor(t) {
if (t == 'X') return _settings_colors['Xdark'];
else if (t == 'Y') return _settings_colors['Ydark'];
else if (t == 'Z') return _settings_colors['Zdark'];
else if (t == 'I') return '#dddddd';
}

function nodeStyle(selected, t) {
var bold = (t == 7 || t == 8);
if (selected) return &#x22;stroke-width: &#x22; + (bold ? &#x22;4&#x22; : &#x22;2&#x22;) + &#x22;px; stroke: #00f&#x22;;
return &#x22;stroke-width: &#x22; + (bold ? &#x22;3&#x22; : &#x22;1.5&#x22;) + &#x22;px&#x22;;
}

var symbolGround = {
draw: function(context, size){
let s = size/2;

context.moveTo(0,-s);
context.lineTo(0,0);

context.moveTo(-s,0);
context.lineTo(s,0);

context.moveTo(-2*s/3,s/3);
context.lineTo(2*s/3,s/3);

context.moveTo(-s/3,2*s/3);
context.lineTo(s/3,2*s/3);
}
}

function showGraph(tag, graph, width, height, scale, node_size, auto_hbox, show_labels, scalar_str) {
var ntab = {};

var groundOffset = 2.5 * node_size;

graph.nodes.forEach(function(d) {
ntab[d.name] = d;
d.selected = false;
d.previouslySelected = false;
d.nhd = [];
});

var spiders_and_boundaries = graph.nodes.filter(function(d) {
return d.t != 3;
});

graph.links.forEach(function(d) {
var s = ntab[d.source];
var t = ntab[d.target];
d.source = s;
d.target = t;
s.nhd.push(t);
t.nhd.push(s);
});

graph.pauli_web.forEach(function(d) {
var s = ntab[d.source];
var t = ntab[d.target];
d.source = s;
d.target = t;
});

var shiftKey;

// SETUP SVG ITEMS

var svg = d3.select(tag)
//.attr(&#x22;tabindex&#x22;, 1)
.on(&#x22;keydown.brush&#x22;, function() {shiftKey = d3.event.shiftKey || d3.event.metaKey;})
.on(&#x22;keyup.brush&#x22;, function() {shiftKey = d3.event.shiftKey || d3.event.metaKey;})
//.each(function() { this.focus(); })
.append(&#x22;svg&#x22;)
.attr(&#x22;style&#x22;, &#x22;max-width: none; max-height: none&#x22;)
.attr(&#x22;width&#x22;, width)
.attr(&#x22;height&#x22;, height);

var web = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;web&#x22;)
.selectAll(&#x22;line&#x22;)
.data(graph.pauli_web)
.enter().append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, function(d) { return webColor(d.t); })
.attr(&#x22;fill&#x22;, &#x22;transparent&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 7px&#x22;);

var link = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;link&#x22;)
.selectAll(&#x22;line&#x22;)
.data(graph.links)
.enter().append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, function(d) { return edgeColor(d.t); })
.attr(&#x22;fill&#x22;, &#x22;transparent&#x22;)
.attr(&#x22;style&#x22;, function(d) { return isBoldEdge(d.t) ? &#x22;stroke-width: 3.5px&#x22; : &#x22;stroke-width: 1.5px&#x22;; });

var brush = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;brush&#x22;);

var node = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;node&#x22;)
.selectAll(&#x22;g&#x22;)
.data(graph.nodes)
.enter().append(&#x22;g&#x22;)
.attr(&#x22;transform&#x22;, function(d) {
return &#x22;translate(&#x22; + d.x + &#x22;,&#x22; + d.y +&#x22;)&#x22;;
});

// Draw a ground symbol connected to the node.
node.filter(function(d) { return d.ground; })
.append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 1.5px&#x22;)
.attr(&#x22;fill&#x22;, &#x22;none&#x22;)
.attr(&#x22;d&#x22;, &#x22;M 0 0 L 0 &#x22;+(groundOffset))
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);
node.filter(function(d) { return d.ground; })
.append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 1.5px&#x22;)
.attr(&#x22;fill&#x22;, &#x22;none&#x22;)
.attr(&#x22;d&#x22;, d3.symbol().type(symbolGround).size(node_size*1.5))
.attr(&#x22;transform&#x22;, &#x22;translate(0,&#x22;+groundOffset+&#x22;)&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

node.filter(function(d) { return d.t != 3 && d.t != 5 && d.t != 6; })
.append(&#x22;circle&#x22;)
.attr(&#x22;r&#x22;, function(d) {
if (d.t == 0) return 0.5 * node_size;
else if (d.t == 4) return 0.25 * node_size;
else return node_size;
})
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;stroke-width&#x22;, function(d) { return (d.t == 7 || d.t == 8) ? 3 : 1.5; })
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

var hbox = node.filter(function(d) { return d.t == 3; });

hbox.append(&#x22;rect&#x22;)
.attr(&#x22;x&#x22;, -0.75 * node_size).attr(&#x22;y&#x22;, -0.75 * node_size)
.attr(&#x22;width&#x22;, node_size * 1.5).attr(&#x22;height&#x22;, node_size * 1.5)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

// draw a triangle for d.t == 5
node.filter(function(d) { return d.t == 5; })
.append(&#x22;path&#x22;)
.attr(&#x22;d&#x22;, &#x22;M 0 0 L &#x22;+node_size+&#x22; &#x22;+node_size+&#x22; L -&#x22;+node_size+&#x22; &#x22;+node_size+&#x22; Z&#x22;)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;)
.attr(&#x22;transform&#x22;, &#x22;translate(&#x22; + (-node_size/2) + &#x22;, 0) rotate(-90)&#x22;);

// draw a square for Z box: d.t == 6
node.filter(function(d) { return d.t == 6; })
.append(&#x22;rect&#x22;)
.attr(&#x22;x&#x22;, -0.75 * node_size).attr(&#x22;y&#x22;, -0.75 * node_size)
.attr(&#x22;width&#x22;, node_size * 1.5).attr(&#x22;height&#x22;, node_size * 1.5)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

node.filter(function(d) { return d.phase != '' && d.phase.indexOf('[') === -1; })
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, 0.7 * node_size + 14)
.text(function (d) { return d.phase })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;12px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#00d&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');

node.filter(function(d) { return d.phase != '' && d.phase.indexOf('[') !== -1; })
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, -0.7 * node_size - 8)
.text(function (d) { return d.phase })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;12px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;black&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');

if (show_labels) {
node.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, -0.7 * node_size - 8)
.text(function (d) { return d.name; })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;10px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#999&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');
}

// Display the chosen data fields over the node.
node.filter(d => d.vdata.length > 0)
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, d => -0.7 * node_size - 14 - 10 * d.vdata.length)
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;8px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#c66&#x22;)
.attr('style', 'pointer-events: none; user-select: none;')
.selectAll(&#x22;tspan&#x22;)
.data(d => d.vdata)
.enter()
.append(&#x22;tspan&#x22;)
.attr(&#x22;x&#x22;, &#x22;0&#x22;)
.attr(&#x22;dy&#x22;, &#x22;1.2em&#x22;)
.text(x => x.join(&#x22;: &#x22;));

if (scalar_str != &#x22;&#x22;) {
svg.append(&#x22;text&#x22;)
.text(scalar_str)
.attr(&#x22;x&#x22;, 60).attr(&#x22;y&#x22;, 40)
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
}

function update_hboxes() {
if (auto_hbox) {
var pos = {};
hbox.attr(&#x22;transform&#x22;, function(d) {
// calculate barycenter of non-hbox neighbours, then nudge a bit
// to the NE.
var x=0,y=0,sz=0;
for (var i = 0; i < d.nhd.length; ++i) {
if (d.nhd[i].t != 3) {
sz++;
x += d.nhd[i].x;
y += d.nhd[i].y;
}
}

offset = 0.25 * scale;

if (sz != 0) {
x = (x/sz) + offset;
y = (y/sz) - offset;

while (pos[[x,y]]) {
x += offset;
}
d.x = x;
d.y = y;
pos[[x,y]] = true;
}

return &#x22;translate(&#x22;+d.x+&#x22;,&#x22;+d.y+&#x22;)&#x22;;
});
}
}

update_hboxes();

var link_curve = function(d) {
var x1 = d.source.x, x2 = d.target.x, y1 = d.source.y, y2 = d.target.y;
if (x1 == x2 && y1 == y2 && d.num_parallel == 1) {
var cx1 = x1 - 40;
var cy1 = y1 - 40;
var cx2 = x1 + 40;
var cy2 = y1 - 40;
return `M ${x1} ${y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x2} ${y2}`;
} else if (x1 == x2 && y1 == y2) {
var pos = d.index + 1;
var cx1 = x1 - 20 - pos * 10;
var cy1 = y1 - 20 - pos * 10;
var cx2 = x1 + 20 + pos * 10;
var cy2 = y1 - 20 - pos * 10;
return `M ${x1} ${y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x2} ${y2}`;
} else if (d.num_parallel == 1) {
return `M ${x1} ${y1} L ${x2} ${y2}`;
} else {
var dx = x2 - x1, dy = y2 - y1;
var midx = 0.5 * (x1 + x2), midy = 0.5 * (y1 + y2);
var pos = (d.index / (d.num_parallel-1)) - 0.5;
var cx = midx - pos * dy;
var cy = midy + pos * dx;
return `M ${x1} ${y1} Q ${cx} ${cy}, ${x2} ${y2}`;
// return `M ${x1} ${y1} L ${x2} ${y2}`;
}
};
link.attr(&#x22;d&#x22;, link_curve);


var web_curve = function(d) {
var x1 = d.source.x, x2 = (x1 + d.target.x)/2, y1 = d.source.y, y2 = (y1 + d.target.y)/2;
return `M ${x1} ${y1} L ${x2} ${y2}`;
}
web.attr(&#x22;d&#x22;, web_curve);

// EVENTS FOR DRAGGING AND SELECTION

node.on(&#x22;mousedown&#x22;, function(d) {
if (shiftKey) {
d3.select(this).selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, nodeStyle(d.selected = !d.selected, d.t));
d3.event.stopImmediatePropagation();
} else if (!d.selected) {
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(p) { return nodeStyle(p.selected = d === p, p.t); });
}
})
.call(d3.drag().on(&#x22;drag&#x22;, function(d) {
var dx = d3.event.dx;
var dy = d3.event.dy;
// node.filter(function(d) { return d.selected; })
//     .attr(&#x22;cx&#x22;, function(d) { return d.x += dx; })
//     .attr(&#x22;cy&#x22;, function(d) { return d.y += dy; });
node.filter(function(d) { return d.selected; })
.attr(&#x22;transform&#x22;, function(d) {
d.x += dx;
d.y += dy;
return &#x22;translate(&#x22; + d.x + &#x22;,&#x22; + d.y +&#x22;)&#x22;;
});

update_hboxes();

link.filter(function(d) { return d.source.selected || d.target.selected ||
(auto_hbox && d.source.t == 3); })
.attr(&#x22;d&#x22;, link_curve);
web.filter(function(d) { return d.source.selected || d.target.selected; })
.attr(&#x22;d&#x22;, web_curve);
}));

brush.call(d3.brush().keyModifiers(false)
.extent([[0, 0], [width, height]])
.on(&#x22;start&#x22;, function() {
if (d3.event.sourceEvent.type !== &#x22;end&#x22;) {
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(d) {
return nodeStyle(
d.selected = d.previouslySelected = shiftKey &&
d.selected, d.t);
});
}
})
.on(&#x22;brush&#x22;, function() {
if (d3.event.sourceEvent.type !== &#x22;end&#x22;) {
var selection = d3.event.selection;
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(d) {
return nodeStyle(d.selected = d.previouslySelected ^
(selection != null
&& selection[0][0] <= d.x && d.x < selection[1][0]
&& selection[0][1] <= d.y && d.y < selection[1][1]), d.t);
});
}
})
.on(&#x22;end&#x22;, function() {
if (d3.event.selection != null) {
d3.select(this).call(d3.event.target.move, null);
}
}));
}


showGraph('#graph-output-002',
JSON.parse('{&#x22;nodes&#x22;: [{&#x22;name&#x22;: &#x22;0&#x22;, &#x22;x&#x22;: 50.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 0, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;1&#x22;, &#x22;x&#x22;: 100.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 8, &#x22;phase&#x22;: &#x22;\u03c0&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;2&#x22;, &#x22;x&#x22;: 150.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 1, &#x22;phase&#x22;: &#x22;rec[0]&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;3&#x22;, &#x22;x&#x22;: 200.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 8, &#x22;phase&#x22;: &#x22;\u03c0&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;4&#x22;, &#x22;x&#x22;: 250.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;5&#x22;, &#x22;x&#x22;: 50.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 0, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;6&#x22;, &#x22;x&#x22;: 250.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 8, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;7&#x22;, &#x22;x&#x22;: 300.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 0, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;8&#x22;, &#x22;x&#x22;: 300.0, &#x22;y&#x22;: 150.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 0, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}], &#x22;links&#x22;: [{&#x22;source&#x22;: &#x22;0&#x22;, &#x22;target&#x22;: &#x22;1&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;1&#x22;, &#x22;target&#x22;: &#x22;2&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;2&#x22;, &#x22;target&#x22;: &#x22;3&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;2&#x22;, &#x22;target&#x22;: &#x22;6&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;3&#x22;, &#x22;target&#x22;: &#x22;4&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;4&#x22;, &#x22;target&#x22;: &#x22;7&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;5&#x22;, &#x22;target&#x22;: &#x22;6&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;6&#x22;, &#x22;target&#x22;: &#x22;8&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}], &#x22;pauli_web&#x22;: []}'), 350, 200, 50,
10.0, false, false, '');
</script></body></html>"
  width="100%"
  height="212"
  style={{border: "1px solid #eee", borderRadius: "0.5rem"}}
  title="ZX diagram 2"
  loading="lazy"
/>

### `REPEAT` instructions are flattened

Tsim does not support `REPEAT` instructions. Any `REPEAT` instructions will be flattened.

```python theme={null}
c = tsim.Circuit("""
    REPEAT 10 {
        T 0
    }
""")
c.diagram("pyzx");
```

<iframe
  srcDoc="<!doctype html><html><head><meta charset=&#x22;utf-8&#x22;><style>html,body{margin:0;padding:0;height:100%;overflow:hidden;}[id^=&#x22;graph-output-&#x22;]{width:100%;height:100%;overflow:auto;box-sizing:border-box;}</style></head><body><div style=&#x22;overflow:auto; background-color: white&#x22; id=&#x22;graph-output-003&#x22;></div><script type=&#x22;module&#x22;>
var d3;
if (d3 == null) { d3 = await import(&#x22;https://esm.sh/d3@5&#x22;); }
var _settings_colors = JSON.parse('{&#x22;edge&#x22;: &#x22;#000000&#x22;, &#x22;Hedge&#x22;: &#x22;#0088ff&#x22;, &#x22;Xedge&#x22;: &#x22;#999999&#x22;, &#x22;Bedge&#x22;: &#x22;#000000&#x22;, &#x22;HBedge&#x22;: &#x22;#0088ff&#x22;, &#x22;boundary&#x22;: &#x22;#000000&#x22;, &#x22;X&#x22;: &#x22;#ff8888&#x22;, &#x22;Y&#x22;: &#x22;#aabbff&#x22;, &#x22;Z&#x22;: &#x22;#ccffcc&#x22;, &#x22;H&#x22;: &#x22;#ffff66&#x22;, &#x22;W&#x22;: &#x22;#000000&#x22;, &#x22;Zalt&#x22;: &#x22;#ccffcc&#x22;, &#x22;Walt&#x22;: &#x22;#000000&#x22;, &#x22;Zbold&#x22;: &#x22;#ccffcc&#x22;, &#x22;Xbold&#x22;: &#x22;#ff8888&#x22;, &#x22;Xdark&#x22;: &#x22;#ff8888&#x22;, &#x22;Ydark&#x22;: &#x22;#aabbff&#x22;, &#x22;Zdark&#x22;: &#x22;#99dd99&#x22;}');
// PyZX - Python library for quantum circuit rewriting 
//        and optimisation using the ZX-calculus
// Copyright (C) 2018 - Aleks Kissinger and John van de Wetering

// Licensed under the Apache License, Version 2.0 (the &#x22;License&#x22;);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//    http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an &#x22;AS IS&#x22; BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// styling functions
function nodeColor(t) {
if (t == 0) return _settings_colors['boundary'];
else if (t == 1) return _settings_colors['Z']; // &#x22;#ccffcc&#x22;;
else if (t == 2) return _settings_colors['X']; // &#x22;#ff8888&#x22;;
else if (t == 3) return _settings_colors['H']; // &#x22;yellow&#x22;;
else if (t == 4) return _settings_colors['W']; // &#x22;black&#x22;;
else if (t == 5) return _settings_colors['Walt']; // &#x22;black&#x22;;
else if (t == 6) return _settings_colors['Zalt']; // &#x22;#ccffcc&#x22;;
else if (t == 7) return _settings_colors['Zbold']; // &#x22;#ccffcc&#x22; bold Z
else if (t == 8) return _settings_colors['Xbold']; // &#x22;#ff8888&#x22; bold X
}

function edgeColor(t) {
if (t == 1) return _settings_colors['edge']; //&#x22;black&#x22;;
else if (t == 2) return _settings_colors['Hedge']; // &#x22;#08f&#x22;;
else if (t == 3) return _settings_colors['Xedge']; // &#x22;gray&#x22;;
else if (t == 4) return _settings_colors['Bedge']; // &#x22;black&#x22; bold
else if (t == 5) return _settings_colors['HBedge']; // &#x22;#0088ff&#x22; bold hadamard
}

function isBoldEdge(t) {
return t == 4 || t == 5;
}

function webColor(t) {
if (t == 'X') return _settings_colors['Xdark'];
else if (t == 'Y') return _settings_colors['Ydark'];
else if (t == 'Z') return _settings_colors['Zdark'];
else if (t == 'I') return '#dddddd';
}

function nodeStyle(selected, t) {
var bold = (t == 7 || t == 8);
if (selected) return &#x22;stroke-width: &#x22; + (bold ? &#x22;4&#x22; : &#x22;2&#x22;) + &#x22;px; stroke: #00f&#x22;;
return &#x22;stroke-width: &#x22; + (bold ? &#x22;3&#x22; : &#x22;1.5&#x22;) + &#x22;px&#x22;;
}

var symbolGround = {
draw: function(context, size){
let s = size/2;

context.moveTo(0,-s);
context.lineTo(0,0);

context.moveTo(-s,0);
context.lineTo(s,0);

context.moveTo(-2*s/3,s/3);
context.lineTo(2*s/3,s/3);

context.moveTo(-s/3,2*s/3);
context.lineTo(s/3,2*s/3);
}
}

function showGraph(tag, graph, width, height, scale, node_size, auto_hbox, show_labels, scalar_str) {
var ntab = {};

var groundOffset = 2.5 * node_size;

graph.nodes.forEach(function(d) {
ntab[d.name] = d;
d.selected = false;
d.previouslySelected = false;
d.nhd = [];
});

var spiders_and_boundaries = graph.nodes.filter(function(d) {
return d.t != 3;
});

graph.links.forEach(function(d) {
var s = ntab[d.source];
var t = ntab[d.target];
d.source = s;
d.target = t;
s.nhd.push(t);
t.nhd.push(s);
});

graph.pauli_web.forEach(function(d) {
var s = ntab[d.source];
var t = ntab[d.target];
d.source = s;
d.target = t;
});

var shiftKey;

// SETUP SVG ITEMS

var svg = d3.select(tag)
//.attr(&#x22;tabindex&#x22;, 1)
.on(&#x22;keydown.brush&#x22;, function() {shiftKey = d3.event.shiftKey || d3.event.metaKey;})
.on(&#x22;keyup.brush&#x22;, function() {shiftKey = d3.event.shiftKey || d3.event.metaKey;})
//.each(function() { this.focus(); })
.append(&#x22;svg&#x22;)
.attr(&#x22;style&#x22;, &#x22;max-width: none; max-height: none&#x22;)
.attr(&#x22;width&#x22;, width)
.attr(&#x22;height&#x22;, height);

var web = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;web&#x22;)
.selectAll(&#x22;line&#x22;)
.data(graph.pauli_web)
.enter().append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, function(d) { return webColor(d.t); })
.attr(&#x22;fill&#x22;, &#x22;transparent&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 7px&#x22;);

var link = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;link&#x22;)
.selectAll(&#x22;line&#x22;)
.data(graph.links)
.enter().append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, function(d) { return edgeColor(d.t); })
.attr(&#x22;fill&#x22;, &#x22;transparent&#x22;)
.attr(&#x22;style&#x22;, function(d) { return isBoldEdge(d.t) ? &#x22;stroke-width: 3.5px&#x22; : &#x22;stroke-width: 1.5px&#x22;; });

var brush = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;brush&#x22;);

var node = svg.append(&#x22;g&#x22;)
.attr(&#x22;class&#x22;, &#x22;node&#x22;)
.selectAll(&#x22;g&#x22;)
.data(graph.nodes)
.enter().append(&#x22;g&#x22;)
.attr(&#x22;transform&#x22;, function(d) {
return &#x22;translate(&#x22; + d.x + &#x22;,&#x22; + d.y +&#x22;)&#x22;;
});

// Draw a ground symbol connected to the node.
node.filter(function(d) { return d.ground; })
.append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 1.5px&#x22;)
.attr(&#x22;fill&#x22;, &#x22;none&#x22;)
.attr(&#x22;d&#x22;, &#x22;M 0 0 L 0 &#x22;+(groundOffset))
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);
node.filter(function(d) { return d.ground; })
.append(&#x22;path&#x22;)
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;style&#x22;, &#x22;stroke-width: 1.5px&#x22;)
.attr(&#x22;fill&#x22;, &#x22;none&#x22;)
.attr(&#x22;d&#x22;, d3.symbol().type(symbolGround).size(node_size*1.5))
.attr(&#x22;transform&#x22;, &#x22;translate(0,&#x22;+groundOffset+&#x22;)&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

node.filter(function(d) { return d.t != 3 && d.t != 5 && d.t != 6; })
.append(&#x22;circle&#x22;)
.attr(&#x22;r&#x22;, function(d) {
if (d.t == 0) return 0.5 * node_size;
else if (d.t == 4) return 0.25 * node_size;
else return node_size;
})
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;stroke-width&#x22;, function(d) { return (d.t == 7 || d.t == 8) ? 3 : 1.5; })
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

var hbox = node.filter(function(d) { return d.t == 3; });

hbox.append(&#x22;rect&#x22;)
.attr(&#x22;x&#x22;, -0.75 * node_size).attr(&#x22;y&#x22;, -0.75 * node_size)
.attr(&#x22;width&#x22;, node_size * 1.5).attr(&#x22;height&#x22;, node_size * 1.5)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

// draw a triangle for d.t == 5
node.filter(function(d) { return d.t == 5; })
.append(&#x22;path&#x22;)
.attr(&#x22;d&#x22;, &#x22;M 0 0 L &#x22;+node_size+&#x22; &#x22;+node_size+&#x22; L -&#x22;+node_size+&#x22; &#x22;+node_size+&#x22; Z&#x22;)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;)
.attr(&#x22;transform&#x22;, &#x22;translate(&#x22; + (-node_size/2) + &#x22;, 0) rotate(-90)&#x22;);

// draw a square for Z box: d.t == 6
node.filter(function(d) { return d.t == 6; })
.append(&#x22;rect&#x22;)
.attr(&#x22;x&#x22;, -0.75 * node_size).attr(&#x22;y&#x22;, -0.75 * node_size)
.attr(&#x22;width&#x22;, node_size * 1.5).attr(&#x22;height&#x22;, node_size * 1.5)
.attr(&#x22;fill&#x22;, function(d) { return nodeColor(d.t); })
.attr(&#x22;stroke&#x22;, &#x22;black&#x22;)
.attr(&#x22;class&#x22;, &#x22;selectable&#x22;);

node.filter(function(d) { return d.phase != '' && d.phase.indexOf('[') === -1; })
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, 0.7 * node_size + 14)
.text(function (d) { return d.phase })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;12px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#00d&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');

node.filter(function(d) { return d.phase != '' && d.phase.indexOf('[') !== -1; })
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, -0.7 * node_size - 8)
.text(function (d) { return d.phase })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;12px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;black&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');

if (show_labels) {
node.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, -0.7 * node_size - 8)
.text(function (d) { return d.name; })
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;10px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#999&#x22;)
.attr('style', 'pointer-events: none; user-select: none;');
}

// Display the chosen data fields over the node.
node.filter(d => d.vdata.length > 0)
.append(&#x22;text&#x22;)
.attr(&#x22;y&#x22;, d => -0.7 * node_size - 14 - 10 * d.vdata.length)
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
.attr(&#x22;font-size&#x22;, &#x22;8px&#x22;)
.attr(&#x22;font-family&#x22;, &#x22;monospace&#x22;)
.attr(&#x22;fill&#x22;, &#x22;#c66&#x22;)
.attr('style', 'pointer-events: none; user-select: none;')
.selectAll(&#x22;tspan&#x22;)
.data(d => d.vdata)
.enter()
.append(&#x22;tspan&#x22;)
.attr(&#x22;x&#x22;, &#x22;0&#x22;)
.attr(&#x22;dy&#x22;, &#x22;1.2em&#x22;)
.text(x => x.join(&#x22;: &#x22;));

if (scalar_str != &#x22;&#x22;) {
svg.append(&#x22;text&#x22;)
.text(scalar_str)
.attr(&#x22;x&#x22;, 60).attr(&#x22;y&#x22;, 40)
.attr(&#x22;text-anchor&#x22;, &#x22;middle&#x22;)
}

function update_hboxes() {
if (auto_hbox) {
var pos = {};
hbox.attr(&#x22;transform&#x22;, function(d) {
// calculate barycenter of non-hbox neighbours, then nudge a bit
// to the NE.
var x=0,y=0,sz=0;
for (var i = 0; i < d.nhd.length; ++i) {
if (d.nhd[i].t != 3) {
sz++;
x += d.nhd[i].x;
y += d.nhd[i].y;
}
}

offset = 0.25 * scale;

if (sz != 0) {
x = (x/sz) + offset;
y = (y/sz) - offset;

while (pos[[x,y]]) {
x += offset;
}
d.x = x;
d.y = y;
pos[[x,y]] = true;
}

return &#x22;translate(&#x22;+d.x+&#x22;,&#x22;+d.y+&#x22;)&#x22;;
});
}
}

update_hboxes();

var link_curve = function(d) {
var x1 = d.source.x, x2 = d.target.x, y1 = d.source.y, y2 = d.target.y;
if (x1 == x2 && y1 == y2 && d.num_parallel == 1) {
var cx1 = x1 - 40;
var cy1 = y1 - 40;
var cx2 = x1 + 40;
var cy2 = y1 - 40;
return `M ${x1} ${y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x2} ${y2}`;
} else if (x1 == x2 && y1 == y2) {
var pos = d.index + 1;
var cx1 = x1 - 20 - pos * 10;
var cy1 = y1 - 20 - pos * 10;
var cx2 = x1 + 20 + pos * 10;
var cy2 = y1 - 20 - pos * 10;
return `M ${x1} ${y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x2} ${y2}`;
} else if (d.num_parallel == 1) {
return `M ${x1} ${y1} L ${x2} ${y2}`;
} else {
var dx = x2 - x1, dy = y2 - y1;
var midx = 0.5 * (x1 + x2), midy = 0.5 * (y1 + y2);
var pos = (d.index / (d.num_parallel-1)) - 0.5;
var cx = midx - pos * dy;
var cy = midy + pos * dx;
return `M ${x1} ${y1} Q ${cx} ${cy}, ${x2} ${y2}`;
// return `M ${x1} ${y1} L ${x2} ${y2}`;
}
};
link.attr(&#x22;d&#x22;, link_curve);


var web_curve = function(d) {
var x1 = d.source.x, x2 = (x1 + d.target.x)/2, y1 = d.source.y, y2 = (y1 + d.target.y)/2;
return `M ${x1} ${y1} L ${x2} ${y2}`;
}
web.attr(&#x22;d&#x22;, web_curve);

// EVENTS FOR DRAGGING AND SELECTION

node.on(&#x22;mousedown&#x22;, function(d) {
if (shiftKey) {
d3.select(this).selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, nodeStyle(d.selected = !d.selected, d.t));
d3.event.stopImmediatePropagation();
} else if (!d.selected) {
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(p) { return nodeStyle(p.selected = d === p, p.t); });
}
})
.call(d3.drag().on(&#x22;drag&#x22;, function(d) {
var dx = d3.event.dx;
var dy = d3.event.dy;
// node.filter(function(d) { return d.selected; })
//     .attr(&#x22;cx&#x22;, function(d) { return d.x += dx; })
//     .attr(&#x22;cy&#x22;, function(d) { return d.y += dy; });
node.filter(function(d) { return d.selected; })
.attr(&#x22;transform&#x22;, function(d) {
d.x += dx;
d.y += dy;
return &#x22;translate(&#x22; + d.x + &#x22;,&#x22; + d.y +&#x22;)&#x22;;
});

update_hboxes();

link.filter(function(d) { return d.source.selected || d.target.selected ||
(auto_hbox && d.source.t == 3); })
.attr(&#x22;d&#x22;, link_curve);
web.filter(function(d) { return d.source.selected || d.target.selected; })
.attr(&#x22;d&#x22;, web_curve);
}));

brush.call(d3.brush().keyModifiers(false)
.extent([[0, 0], [width, height]])
.on(&#x22;start&#x22;, function() {
if (d3.event.sourceEvent.type !== &#x22;end&#x22;) {
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(d) {
return nodeStyle(
d.selected = d.previouslySelected = shiftKey &&
d.selected, d.t);
});
}
})
.on(&#x22;brush&#x22;, function() {
if (d3.event.sourceEvent.type !== &#x22;end&#x22;) {
var selection = d3.event.selection;
node.selectAll(&#x22;.selectable&#x22;).attr(&#x22;style&#x22;, function(d) {
return nodeStyle(d.selected = d.previouslySelected ^
(selection != null
&& selection[0][0] <= d.x && d.x < selection[1][0]
&& selection[0][1] <= d.y && d.y < selection[1][1]), d.t);
});
}
})
.on(&#x22;end&#x22;, function() {
if (d3.event.selection != null) {
d3.select(this).call(d3.event.target.move, null);
}
}));
}


showGraph('#graph-output-003',
JSON.parse('{&#x22;nodes&#x22;: [{&#x22;name&#x22;: &#x22;0&#x22;, &#x22;x&#x22;: 50.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 0, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;1&#x22;, &#x22;x&#x22;: 100.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;2&#x22;, &#x22;x&#x22;: 150.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;3&#x22;, &#x22;x&#x22;: 200.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;4&#x22;, &#x22;x&#x22;: 250.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;5&#x22;, &#x22;x&#x22;: 300.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;6&#x22;, &#x22;x&#x22;: 350.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;7&#x22;, &#x22;x&#x22;: 400.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;8&#x22;, &#x22;x&#x22;: 450.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;9&#x22;, &#x22;x&#x22;: 500.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;10&#x22;, &#x22;x&#x22;: 550.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 7, &#x22;phase&#x22;: &#x22;\u03c0/4&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}, {&#x22;name&#x22;: &#x22;11&#x22;, &#x22;x&#x22;: 600.0, &#x22;y&#x22;: 100.0, &#x22;z&#x22;: 0.0, &#x22;t&#x22;: 0, &#x22;phase&#x22;: &#x22;&#x22;, &#x22;ground&#x22;: false, &#x22;vdata&#x22;: []}], &#x22;links&#x22;: [{&#x22;source&#x22;: &#x22;0&#x22;, &#x22;target&#x22;: &#x22;1&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;1&#x22;, &#x22;target&#x22;: &#x22;2&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;2&#x22;, &#x22;target&#x22;: &#x22;3&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;3&#x22;, &#x22;target&#x22;: &#x22;4&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;4&#x22;, &#x22;target&#x22;: &#x22;5&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;5&#x22;, &#x22;target&#x22;: &#x22;6&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;6&#x22;, &#x22;target&#x22;: &#x22;7&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;7&#x22;, &#x22;target&#x22;: &#x22;8&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;8&#x22;, &#x22;target&#x22;: &#x22;9&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;9&#x22;, &#x22;target&#x22;: &#x22;10&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}, {&#x22;source&#x22;: &#x22;10&#x22;, &#x22;target&#x22;: &#x22;11&#x22;, &#x22;t&#x22;: 4, &#x22;index&#x22;: 0, &#x22;num_parallel&#x22;: 1}], &#x22;pauli_web&#x22;: []}'), 650, 150, 50,
10.0, false, false, '');
</script></body></html>"
  width="100%"
  height="162"
  style={{border: "1px solid #eee", borderRadius: "0.5rem"}}
  title="ZX diagram 3"
  loading="lazy"
/>
