Dist m4ri 0.16.1
Computing distance of a classical or quantum CSS code
Loading...
Searching...
No Matches
make_yarn_mitten_circuits.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Memory-experiment Stim circuits for the mitten codes of a7b/yarn (arXiv:2607.28795), with the published hook-free
3syndrome-extraction schedule (processor_codes/<family>/[[n,k,d]]/hook_free_SE_cycle_schedule.json).
4
5Each cycle: reset the X- and Z-check ancillas; the 12 layers of the X-check round (CX from the X-check ancilla to the
6data qubit for every listed pair [check row of Hx, data column]); MX of the X-check ancillas; the 12 layers of the
7Z-check round (CX from the data qubit to the Z-check ancilla); M of the Z-check ancillas. The cycles after the first are
8in a REPEAT block. The data qubits start in |0> (Z basis) or |+> (X basis) and are measured in that basis at the end.
9Detectors: the checks of the memory basis in the first cycle, every check in the later cycles (compared with the
10previous cycle), and the checks of the memory basis from the final data measurements; observables: the rows of Lz
11(Z basis) or Lx (X basis). Noise: uniform circuit-level noise of dist_m4ri.add_noise(p) (DEPOLARIZE2 after each CX,
12DEPOLARIZE1(p/10) on idle qubits at each TICK, flips of resets and measurements).
13
14Usage, from a checkout of https://github.com/a7b/yarn (commit 1b58edd24e19b6b5da6814fd3a74ebb376b6e90f):
15 python3 benchmark/stim_mitten/make_yarn_mitten_circuits.py "YARN/processor_codes/mitten/[[150,30,10]]" \
16 benchmark/stim_mitten [--rounds R] [--p P] [--basis X|Z|XZ] [--check-rounds R]
17(R = 0: the d of the code name). Output: yarn_<family>_<n>_<k>_<d>_hookfree_r<R>_<basis>.stim.
18"""
19import argparse
20import json
21import os
22import re
23import sys
24
25import numpy as np
26import stim
27
28sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..")))
29import dist_m4ri # noqa: E402 (add_noise)
30
31
32def load(code_dir):
33 m = {k: np.load(os.path.join(code_dir, k + ".npy")).astype(np.uint8) for k in ("Hx", "Hz", "Lx", "Lz")}
34 sched = json.load(open(os.path.join(code_dir, "hook_free_SE_cycle_schedule.json")))
35 return m, sched
36
37
38def layers_of(sched, key, h, nq_data):
39 """The layers of one check round as lists of (check row, data column); checks against h and qubit conflicts."""
40 layers, seen = [], np.zeros_like(h)
41 for layer in sched[key]["layers"]:
42 pairs = [(int(i), int(j)) for mv in layer["moves"] for i, j in mv["cz_gates"]]
43 checks = [i for i, _ in pairs]
44 datas = [j for _, j in pairs]
45 assert len(set(checks)) == len(checks) and len(set(datas)) == len(datas), f"qubit used twice in a layer"
46 for i, j in pairs:
47 assert h[i, j] == 1, f"{key}: pair ({i}, {j}) is not in the check matrix"
48 assert seen[i, j] == 0, f"{key}: pair ({i}, {j}) listed twice"
49 seen[i, j] = 1
50 layers.append(pairs)
51 assert (seen == h).all(), f"{key}: the layers do not cover the check matrix"
52 return layers
53
54
55def build(m, sched, basis, rounds):
56 """The noiseless memory circuit: the first cycle, then the other rounds - 1 cycles in a REPEAT block."""
57 hx, hz = m["Hx"], m["Hz"]
58 n, mx, mz = hx.shape[1], hx.shape[0], hz.shape[0]
59 xl = layers_of(sched, "X_layers", hx, n)
60 zl = layers_of(sched, "Z_layers", hz, n)
61 xa = [n + i for i in range(mx)]
62 za = [n + mx + i for i in range(mz)]
63 mt = mx + mz # measurements per cycle: X checks (lookbacks -mt .. -mz-1), then Z checks (-mz .. -1)
64
65 def cycle(first):
66 c = stim.Circuit()
67 c.append("RX", xa)
68 c.append("R", za)
69 c.append("TICK")
70 for pairs in xl:
71 c.append("CX", [q for i, j in pairs for q in (xa[i], j)])
72 c.append("TICK")
73 c.append("MX", xa)
74 c.append("TICK")
75 for pairs in zl:
76 c.append("CX", [q for i, j in pairs for q in (j, za[i])])
77 c.append("TICK")
78 c.append("M", za)
79 for typ, num, off in (("X", mx, -mt), ("Z", mz, -mz)):
80 if first and typ != basis:
81 continue
82 for i in range(num):
83 targets = [stim.target_rec(off + i)] + ([] if first else [stim.target_rec(off + i - mt)])
84 c.append("DETECTOR", targets, [i, 0, 0 if typ == "X" else 1])
85 c.append("SHIFT_COORDS", [], [0, 1])
86 c.append("TICK")
87 return c
88
89 c = stim.Circuit()
90 c.append("RX" if basis == "X" else "R", range(n))
91 c += cycle(True)
92 if rounds > 1:
93 c.append(stim.CircuitRepeatBlock(rounds - 1, cycle(False)))
94 c.append("MX" if basis == "X" else "M", range(n))
95 h, lo = (hx, m["Lx"]) if basis == "X" else (hz, m["Lz"])
96 last = -n - mt if basis == "X" else -n - mz # lookback of check 0 of the memory basis in the last cycle
97 for i in range(h.shape[0]):
98 targets = [stim.target_rec(-n + j) for j in np.nonzero(h[i])[0]] + [stim.target_rec(last + i)]
99 c.append("DETECTOR", targets, [i, 0, 0 if basis == "X" else 1])
100 for k in range(lo.shape[0]):
101 c.append("OBSERVABLE_INCLUDE", [stim.target_rec(-n + j) for j in np.nonzero(lo[k])[0]], k)
102 return c
103
104
105def main():
106 ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
107 ap.add_argument("code_dir")
108 ap.add_argument("out_dir")
109 ap.add_argument("--rounds", type=int, default=0)
110 ap.add_argument("--p", type=float, default=0.001)
111 ap.add_argument("--basis", default="XZ")
112 ap.add_argument("--check-rounds", type=int, default=2, help="rounds of the noisy test circuit for the DEM check")
113 a = ap.parse_args()
114 m, sched = load(a.code_dir)
115 nkd = [int(x) for x in re.findall(r"\d+", os.path.basename(os.path.normpath(a.code_dir)))]
116 fam = os.path.basename(os.path.dirname(os.path.normpath(a.code_dir)))
117 prefix = {"mitten": "mitten", "structured_mitten": "smitten"}.get(fam, fam)
118 rounds = a.rounds or nkd[2]
119 os.makedirs(a.out_dir, exist_ok=True)
120 for basis in a.basis:
121 # determinism of all detectors and observables: stim raises otherwise
122 test = dist_m4ri.add_noise(build(m, sched, basis, a.check_rounds), p=a.p)
123 dem = test.detector_error_model(decompose_errors=False)
124 c = dist_m4ri.add_noise(build(m, sched, basis, rounds), p=a.p)
125 name = f"yarn_{prefix}_{nkd[0]}_{nkd[1]}_{nkd[2]}_hookfree_r{rounds}_{basis}.stim"
126 header = (f"# [[{nkd[0]},{nkd[1]},{nkd[2]}]] {fam} code of a7b/yarn (arXiv:2607.28795), group "
127 f"{sched['code'].get('group')}; {basis}-basis memory, {rounds} rounds, published hook-free SE "
128 f"schedule (X-check round, then Z-check round, 12 CX layers each); dist_m4ri.add_noise(p={a.p})\n")
129 with open(os.path.join(a.out_dir, name), "w") as f:
130 f.write(header + str(c) + "\n")
131 print(json.dumps({"file": name, "qubits": c.num_qubits, "detectors": c.num_detectors,
132 "observables": c.num_observables, f"dem_errors_r{a.check_rounds}": dem.num_errors}),
133 flush=True)
134
135
136if __name__ == "__main__":
137 main()
Any add_noise(Any circuit, float p=0.001, bool force=False)
layers_of(sched, key, h, nq_data)