目录Contents
速查回顾:五条随身规则Express recap: five rules to carry
《从高考数学到 Toric Code》与《Surface Code · 高中数学版》关于「警报与修复」的全部结论压缩成五条。任何一条觉得生疏,就回后者的对应章节重修;正文里引用定义的橙色虚线点一下即可原地弹出小卡片;希腊字母与新符号(浅灰点线)点一下会告诉你它怎么读,页尾附完整符号表。打开《Surface Code · 高中数学版》→ Everything “From High-School Math to the Toric Code” and “The Surface Code · High-School Edition” established about alarms and repairs, compressed to five lines. If any feels rusty, revisit its chapter in the latter; amber dashed citations pop up an in-place recap card; Greek letters and novel symbols (faint grey dotted) click to reveal how they are read, with a full table at the end. Open “The Surface Code · High-School Edition” →
② 成败只看 错误 ⊕ 修复(模 2 加法)属于哪一类:
横跨的串有偶数条(包括 0 条:只有圈、贴边的路)= 无事,奇数条 = 逻辑错误success depends only on the class of error ⊕ repair (mod-2 addition):
an even number of spanning strings (including 0: only loops and boundary-hugging paths) = harmless, an odd number = logical error
警报数 = 不在己方边界上的端点数on the plane a Z-chain may die on a rough boundary and an X-chain on a smooth one:
alarms = endpoints not on their own boundary
⑤ 压制律:suppression law: PL ≈ A(p/pth)⌈d/2⌉
⑤ 里的字母:PL = 一轮纠错后逻辑比特被改写的概率(逻辑失败率),p = 每个物理比特每轮出错的概率,pth = 阈值(《Surface Code · 高中数学版》6.2 节),A = 与 d 无关的常数因子,d = 码距,也是贴片的尺寸参数(《从高考数学到 Toric Code》5.8 节)。②③ 里的词:毛边界是贴片上伸出半截边的那两条边(本页的图里是左右两侧),一条 Z 链走到那里可以「出界」而不点亮警报;光边界是另外两条边,X 链在那里出界。可收缩指一条闭合的链圈住的是一块面积,可以由面检查拼出来;贴边指链的两端落在同一条毛边界上;横跨指链从一条毛边界连到另一条。
The letters in ⑤: PL = the probability that one correction round rewrites the logical qubit (logical failure rate), p = the per-qubit, per-round physical error probability, pth = the threshold (“The Surface Code · High-School Edition”, §6.2), A = a constant prefactor independent of d, d = the code distance, also the patch size parameter (“From High-School Math to the Toric Code”, §5.8). The words in ② and ③: a rough boundary is one of the two sides of the patch from which half-edges stick out (left and right in this page’s pictures); a Z-chain may leave the patch there without lighting an alarm. A smooth boundary is one of the other two sides, where X-chains leave. Contractible means a closed chain encloses an area and can be built from face checks; hugging a boundary means both ends of the chain sit on the same rough boundary; spanning means the chain runs from one rough boundary to the other.
《Surface Code · 高中数学版》的译码游戏教了你一条黄金法则:近的配近的,靠边的推出去。它好用,但它是经验。本教程要把它变成定理,再指出它在哪里失效、机器又是怎样做得更好的。先到沙盘里活动一下手脚:画几条链,看警报只亮在端点,再看一条贴边的链如何只亮一个警报。
The decoding game of “The Surface Code · High-School Edition” taught you a golden rule: pair the near ones, push the edge ones out. It works, but it is folklore. This tutorial turns it into a theorem, then shows where it fails and how machines do better. Warm up in the sandbox first: draw a few chains, watch alarms light only at endpoints, then see how a chain hugging a boundary lights just one.
① 多对才算对——「对」的定义是什么?(第 1 章)② 几十个警报有几亿种配法,怎样找到最轻的那一种?(第 2 章)③ 贪心为什么会输,「数链的条数」为什么能赢,以及一个几乎不需要算的更快算法(第 3、4 章)。④ 测量本身也会错时,怎样在时空里配对(第 5 章)。最后用一本账把文献里的阈值数字各归各位(第 6 章)。
① When is a pairing right — what does “right” even mean? (Ch. 1) ② With hundreds of millions of pairings for a few dozen alarms, how do we find the lightest? (Ch. 2) ③ Why greed loses, why counting chains wins, and a faster algorithm that barely computes at all (Ch. 3, 4). ④ How to pair in spacetime once measurements themselves fail (Ch. 5). Then a ledger puts every threshold number in the literature back in its place (Ch. 6).
译码器在决定什么What a decoder decides
译码器不是在猜「哪些比特错了」——那件事原则上不可知,也不必知。它决定的是一件粗得多、也可判的事:错误属于哪一类。把这句话写成数学,「最优译码」的定义就自动掉出来,「最轻的链最可能」也只是一道对数题。 A decoder does not guess which qubits failed — that is unknowable in principle and unnecessary in practice. It decides something far coarser and decidable: which class the error belongs to. Write that sentence in mathematics and the definition of “optimal decoding” falls out, while “the lightest chain is the likeliest” becomes an exercise in logarithms.
1.1从症状到类From syndrome to class
设真实错误是一批出错的比特 E(本章只看 Z 错误,X 错误的故事在另一副眼镜里完全对称)。我们看到的只有症状 s = ∂E。任何一个候选修复 C,只要 ∂C = s,施加后症状就清零。此时残留的是 E ⊕ C:一条不点亮任何警报的链——要么是闭合的圈,要么两端都落在毛边界上。《Surface Code · 高中数学版》第 3 章的二分法接管,但要数的是奇偶:数一数残留里有几段是从左毛边界一直连到右毛边界的(叫横跨的串)。偶数段(0、2、4…),残留是若干面检查的乘积,无事发生;奇数段,残留等于逻辑算符 Z̄ 乘上一些面检查,是一次逻辑错误。为什么两段会抵消?两条横跨的串之间夹着一条带子,把带子里所有面检查乘起来,内部的边各被相邻两个面碰到两次、消掉,剩下的正好是这两条串(贴着毛边界的面在边界那一侧是开口的,不贡献竖边)。见图 1.1 ②。对一块 k = 1 的贴片,Z 错误只有这两类。
Let the true error be a set E of failed qubits (this chapter follows Z errors; the X story is identical through the other lens). All we observe is the syndrome s = ∂E. Any candidate repair C with ∂C = s clears the syndrome, leaving the residual E ⊕ C: a chain that lights no alarm — either a closed loop or a path whose two ends both sit on rough boundaries. The dichotomy of “The Surface Code · High-School Edition”, Chapter 3 takes over, but what it counts is a parity: count the pieces of the residual that run all the way from the left rough boundary to the right one (spanning strings). An even number (0, 2, 4, …) means the residual is a product of plaquette checks and nothing happened; an odd number means the residual is the logical operator Z̄ times some plaquettes, a logical error. Why do two cancel? Two spanning strings enclose a strip between them; multiply all the plaquettes in that strip, and every inner edge is touched by two neighbouring plaquettes and drops out, leaving exactly the two strings (a plaquette at a rough boundary is open on that side and contributes no vertical edge there). See Fig. 1.1 ②. For a k = 1 patch, Z errors fall into exactly two classes.
实用的数法(本页所有实验台判输赢就是这么数的):数残留里有几个比特落在左边界那一列半截边上。每段横跨的串在那里占一个,两端都在左边界的路占两个,闭合的圈一个也不占,所以这个数的奇偶就是横跨串数的奇偶:奇数即输。
A practical count (it is how every bench on this page decides the verdict): count the residual qubits that lie on the column of half-edges at the left boundary. Each spanning string occupies one of them, a path with both ends on the left boundary occupies two, a closed loop none; so the parity of this count is the parity of the number of spanning strings, and odd means failure.
这里的「类」要说清楚。两条链 C、C′ 叫同一类,意思是它们的差 C ⊕ C′ 可以由面检查拼出来(闭合的圈、两端落在同一条毛边界上的路、偶数条横跨的串,都属于这种)。面检查作用在编码态上什么都不改变(编码态是每条检查的 +1 本征态),所以同类的两条链作为修复效果完全一样。例:两个警报在同一行、相距 2 步。修复甲是连接它们的直线(2 个比特);修复乙先向上一步、横走 2 步、再向下一步(4 个比特)。甲 ⊕ 乙 恰好是一个 1 × 2 小矩形的边框,由两个面检查拼成,所以甲乙同类。修复丙把左边的警报推向左毛边界、右边的警报推向右毛边界:甲 ⊕ 丙 从左边界连到右边界,是一条(奇数条)横跨的串,所以丙与甲不同类——若甲是对的,丙就造成逻辑错误。
“Class” needs a precise meaning. Two chains C and C′ are in the same class when their difference C ⊕ C′ can be built from face checks (closed loops, paths with both ends on the same rough boundary, and even numbers of spanning strings all qualify). A face check changes nothing on an encoded state (encoded states are +1 eigenstates of every check), so two chains of the same class act identically as repairs. Example: two alarms on one row, 2 steps apart. Repair A is the straight path between them (2 qubits); repair B steps up once, runs 2 steps across, and steps down (4 qubits). A ⊕ B is exactly the rim of a 1 × 2 rectangle, built from two face checks, so A and B are in one class. Repair C pushes the left alarm to the left rough boundary and the right alarm to the right one: A ⊕ C runs from the left boundary to the right, one (an odd number of) spanning string, so C is not in A’s class — if A is right, C causes a logical error.
于是所有满足 ∂C = s 的修复也分成两类:与 E 同类的(修复成功)和不同类的(修复失败)。译码器在两类之间选一类,然后在那一类里随便挑一条链施加——挑哪条无所谓。译码是二选一,不是大海捞针。
So all repairs with ∂C = s split into two classes as well: those in E's class (repair succeeds) and those in the other (repair fails). The decoder picks a class, then applies any chain from it — which one is irrelevant. Decoding is a binary choice, not a search for a needle.
1.2最优译码 = 押概率最大的那一类Optimal decoding = bet on the most probable class
既然是二选一,最好的策略就是:算出「真实错误属于第一类」和「属于第二类」的概率,押大的(下面的折叠块说明为什么没有更好的策略)。要算概率,先得说清错误怎么产生。本章和第 2 至 4 章都用最简单的码容量模型code-capacity noise:只有数据比特出错,每个比特独立地以概率 p 出错;症状测量本身完美无误。在这个模型下测得的阈值叫码容量阈值。:每个数据比特独立地以概率 p 出一个 Z 错误,而检查的读数完全可靠(测量出错的情形留到第 5 章)。于是一条具体的、长 ℓ 的链(ℓ = 链上的比特数)出现的概率是 pℓ(1−p)n−ℓ,n 是贴片上数据比特的总数:ℓ 个比特错,其余 n−ℓ 个没错。一类的概率,就是把这一类里所有链的概率加起来。这样定义的译码器叫最大似然译码器maximum-likelihood decoder:给定症状,选总概率最大的那一类。它是任何译码器能达到的上限,代价是要对一类里所有链求和。,它是一切译码器的上限。
With a binary choice the best strategy is: compute the probability that the true error lies in class one versus class two, and bet on the larger (the fold below explains why nothing does better). To compute probabilities we must say how errors arise. This chapter and Chapters 2 to 4 use the simplest code-capacity modelCode-capacity noise: only data qubits fail, each independently with probability p; syndrome measurement itself is perfect. A threshold measured in this model is a code-capacity threshold.: each data qubit independently suffers a Z error with probability p, and check readouts are perfectly reliable (faulty measurements wait until Chapter 5). One specific chain of length ℓ (ℓ = the number of qubits on it) then occurs with probability pℓ(1−p)n−ℓ, where n is the total number of data qubits on the patch: ℓ qubits failed, the other n−ℓ did not. The probability of a class is the sum over every chain in it. The decoder so defined is the maximum-likelihood decoderGiven the syndrome, pick the class with the largest total probability. It is the ceiling for any decoder; the price is a sum over every chain in a class., the ceiling for all decoders.
最优译码:选 P 最大的类optimal decoding: pick the class with the largest P
为什么「押概率最大的类」就是最优?Why is “bet on the most probable class” optimal?
固定一个症状 s。译码器的任何策略最终都是「看到 s 就押某一类」。它在这个 s 下成功的概率,等于真实错误恰好落在被押的那一类的条件概率。两类的条件概率之和是 1,押大的那个,成功概率就不小于 1/2,而且没有任何别的选择能更高——因为你只有两个选项,而两个选项的成功概率就是这两个数。对每一个症状都这样做,总的成功概率就被逐项最大化了。这就是贝叶斯意义下的最优,没有别的魔法。
Fix a syndrome s. Any decoder strategy amounts to “on seeing s, bet on some class”. Its success probability under this s equals the conditional probability that the true error lies in the class it bet on. The two conditional probabilities sum to 1; betting on the larger gives at least 1/2, and nothing can do better — there are only two options, and their success probabilities are exactly those two numbers. Do this for every syndrome and the total success probability is maximised term by term. That is Bayesian optimality; no further magic.
1.3对数把「乘」变成「加」:最轻的链最可能Logarithms turn products into sums: the lightest chain is the likeliest
pℓ(1−p)n−ℓ 里有一个与链无关的公因子 (1−p)n——所有候选链共享,比较大小时可以扔掉。剩下的是 (p/(1−p))ℓ:链每长一条边,概率就乘一次 p/(1−p)。取自然对数,「乘」变成「加」:
Inside pℓ(1−p)n−ℓ sits a chain-independent factor (1−p)n, shared by every candidate, so it can be dropped when comparing. What remains is (p/(1−p))ℓ: each extra edge multiplies the probability by p/(1−p). Take the natural logarithm and multiplication becomes addition:
p < 1/2 ⇒ w₀ > 0 ⇒ 越长越不可能longer means rarer
格点上的一条边就是一个数据比特,所以「链长一条边」就是「多错一个比特」。每条边分到同一个正的权重weight:给每条边分配的数 w₀ = ln((1−p)/p),使得一条链的对数概率 = −(总权重)。权重越大的链越不可能。 w₀,一条链的对数概率就是 −w₀ × 长度。于是在所有满足 ∂C = s 的单条链里,最可能的就是最短的。《Surface Code · 高中数学版》译码游戏的黄金法则「近的配近的」,说的正是这件事的一半:它在找最短的链。另一半是「一类里有多少条链」,匹配不管它,第 3 章会算它什么时候要紧。拖动下面的 p,看这条直线:
An edge of the lattice is a data qubit, so “one more edge” means “one more failed qubit”. With every edge assigned the same positive weightThe number w₀ = ln((1−p)/p) assigned to each edge, so that a chain's log-probability = −(total weight). Heavier chains are rarer. w₀, a chain's log-probability is −w₀ × length. Among all single chains with ∂C = s, the most probable is the shortest. The surface-code tutorial's golden rule “pair the near ones” states half of this: it is hunting for the shortest chain. The other half is “how many chains a class contains”, which matching ignores; Chapter 3 works out when it matters. Drag p below and watch the straight line:
译码器有两种「最好」。最大似然:把一类里所有链的概率加起来,押总和大的类——真正的最优,但要求和。最小重量:只找一条最可能(最短)的链,押它所在的类——把求和换成了求最短,快得多,偶尔会错在「一类链多、单条不长」的情形(第 3 章)。整篇教程就是这两种「最好」之间的拉锯。
A decoder has two kinds of “best”. Maximum likelihood: sum the probabilities of every chain in a class and bet on the larger sum — truly optimal, but it sums. Minimum weight: find one most probable (shortest) chain and bet on its class — a sum replaced by a shortest-path search, far faster, and occasionally wrong when a class has many chains, none of them long (Ch. 3). This whole tutorial is the tug-of-war between the two.
对。每多一条边乘一次 p/(1−p),对数概率每次减 w₀ = ln 9 ≈ 2.2。这也是为什么在低错误率下,「最短链」几乎总是压倒性地可能。
Right. Each extra edge costs one factor of p/(1−p); the log-probability drops by w₀ = ln 9 ≈ 2.2 every time. This is why at low error rates the shortest chain is almost always overwhelmingly likely.
用 (p/(1−p))ℓ:ℓ 从 1 变 3 多乘了两次。
Use (p/(1−p))ℓ: going from ℓ = 1 to ℓ = 3 multiplies twice.
最小重量完美匹配Minimum-weight perfect matching
「找最短的链」听起来像图论里的最短路,其实是另一个更巧的问题:把警报两两配对,使配对的路径总长最短。这一章给这个问题起名、数清它有多少种答案(多到吓人)、再说明为什么六十年前的一个算法能在多项式时间里找到最优解——以及本页的玩具版是怎么做的。 “Find the shortest chain” sounds like a shortest-path problem; it is really a subtler one: pair the alarms so that the total path length is minimal. This chapter names the problem, counts its candidate answers (frighteningly many), and explains why a sixty-year-old algorithm finds the optimum in polynomial time — and what this page's toy version does instead.
2.1症状图:警报是点,距离是边The syndrome graph: alarms as nodes, distances as edges
一条满足 ∂C = s 的链,就是若干段路径,每段连接两个警报(或连接一个警报与一段己方边界)。为什么?从任意一个警报出发,沿着链上的比特走:每经过一个不亮的检查,链在那里有偶数条边,进得去就出得来;所以只能停在另一个警报上,或者走出毛边界。把这段路径拿掉,剩下的链少了两个端点,再重复。拆到最后若还剩一些闭合的圈,它们不连任何警报,只会让链更重,最轻的链里不会有。把它反过来看:先决定谁和谁配对,再让每对之间走最短路——最短路的长度只取决于两个端点,可以预先算好。(两对的最短路若有重叠,重叠的比特错两次等于没错,⊕ 会把它们消掉,得到的链只会更轻;而这条更轻的链拆开来又是另一种配法,所以最轻的链一定是「某种配法 + 每对走最短路」。)于是问题只剩配对。画一张新图,叫症状图syndrome graph:顶点是全部警报(平面版再加一个「边界」虚拟顶点),任意两顶点之间连一条边,边的权重 = 两警报在格点上的最短距离乘 w₀。:顶点是警报,任意两点之间连一条边,权重是它们在格点上的最短距离(乘上 w₀,但同一个 p 下这是公因子,下面就用步数)。平面版再加一个虚拟顶点「边界」,每个警报到它的权重是到最近己方边界的步数。
A chain with ∂C = s is a bundle of paths, each joining two alarms (or one alarm to a boundary of its own kind). Why? Start at any alarm and walk along the chain’s qubits: at every unlit check the chain has an even number of edges, so whenever you get in you can get out; you can only stop at another alarm or leave through a rough boundary. Remove that path; the rest of the chain has two fewer endpoints; repeat. Any closed loops left over touch no alarm and only add weight, so the lightest chain has none. Flip the viewpoint: decide first who pairs with whom, then let each pair walk a shortest path — its length depends only on the two endpoints and can be precomputed. (If the shortest paths of two pairs overlap, a qubit flipped twice is not flipped at all, ⊕ cancels the overlap, and the chain only gets lighter; that lighter chain splits into another pairing, so the lightest chain is always “some pairing + a shortest path per pair”.) Only the pairing remains. Draw a new graph, the syndrome graphVertices are all alarms (plus one virtual “boundary” vertex on the plane); every two vertices are joined by an edge whose weight = their shortest lattice distance times w₀.: vertices are alarms, every pair joined by an edge weighted by their shortest lattice distance (times w₀, a common factor at fixed p, so we count steps below). The planar version adds a virtual “boundary” vertex, each alarm's weight to it being the steps to its nearest boundary of the right kind.
2.2完美匹配,与 (2m−1)!! 种配法Perfect matchings, and (2m−1)!! of them
在症状图上,一种「每个警报恰好属于一对」的配法叫一个完美匹配perfect matching:图中一组边,使每个顶点恰好被其中一条边覆盖。「完美」指没有顶点被漏掉。。总权重最小的那一个,就是最小重量完美匹配minimum-weight perfect matching,简称 MWPM:所有完美匹配中总权重最小者。它对应「最可能的一条修复链」。(MWPM)——它给出所有单条修复链里最可能的一条,正是 1.3 节要找的东西。
On the syndrome graph, a pairing in which every alarm belongs to exactly one pair is a perfect matchingA set of edges covering every vertex exactly once. “Perfect” means no vertex is left out.. The one with the smallest total weight is the minimum-weight perfect matchingMWPM for short: the perfect matching of smallest total weight. It corresponds to the single most probable repair chain. (MWPM) — the most probable single repair chain, exactly what §1.3 asked for.
有多少种完美匹配?2m 个警报,第一个警报有 2m−1 个可能的搭档;定下来后剩 2m−2 个警报,再递归。所以配法总数是 (2m−1)(2m−3)⋯3·1,记作 (2m−1)!!(隔一个乘一个的「双阶乘」)。它长得很快:
How many perfect matchings? With 2m alarms, the first alarm has 2m−1 possible partners; once fixed, 2m−2 alarms remain and we recurse. The total is (2m−1)(2m−3)⋯3·1, written (2m−1)!! (the “double factorial”, skipping every other factor). It grows fast:
| 警报数 2malarms 2m | 4 | 6 | 8 | 10 | 14 | 20 |
|---|---|---|---|---|---|---|
| 配法数 (2m−1)!!pairings (2m−1)!! | 3 | 15 | 105 | 945 | 135,135 | 654,729,075 |
| 白话in words | 警报数只要到 20 个,配法就有六亿多种;要在一微秒(芯片出一轮症状的时间量级)里逐一试遍,做不到。With only 20 alarms there are over 650 million pairings; trying them all within a microsecond (the time scale on which a chip produces one round of syndrome) is out of the question. | |||||
允许配到边界时有多少种?(电话号码数)And when the boundary is allowed? (telephone numbers)
平面版里每个警报还可以单独「配到边界」。记 m 个警报的配法数为 T(m):第一个警报要么独自去边界(剩 m−1 个,T(m−1) 种),要么与其余 m−1 个之一配对(剩 m−2 个,(m−1)·T(m−2) 种)。所以 T(m) = T(m−1) + (m−1)T(m−2),T(0) = T(1) = 1,得 1, 1, 2, 4, 10, 26, 76, 232, 764, …。这个数列在组合学里叫「电话号码数」(一群人两两通话或不通话的方式数)。实验台的读数用的就是它。
On the plane each alarm may also go to the boundary alone. Let T(m) count the pairings of m alarms: the first alarm either goes to the boundary (T(m−1) ways for the rest) or pairs with one of the other m−1 (then (m−1)·T(m−2) ways). So T(m) = T(m−1) + (m−1)T(m−2) with T(0) = T(1) = 1, giving 1, 1, 2, 4, 10, 26, 76, 232, 764, …. Combinatorialists call these the “telephone numbers” (ways a group can be on calls in pairs or not at all). The bench below reports exactly this count.
亲手比一比:下面的实验台给你一个随机症状,你像《Surface Code · 高中数学版》的译码游戏那样配对,但读数会同时算出你这种配法的总重量,以及所有配法里最轻的重量。多试几盘,你会发现「最轻」通常很容易凑到——但不总是;也会发现最轻的配法偶尔也会输给真实错误:它只是最可能,不是必然。
怎么读这张图(本页所有格点实验台都一样):这是一块 d = 5 的平面贴片。格线的交点是星检查,它们测 X 型算符,所以报告 Z 错误,警报(红点)就亮在交点上;每条格线段中间的小灰点是数据比特,一条链就是一串相邻的数据比特。左右两侧伸出去的半截边通向两条毛边界(灰色长虚线,标「毛边界」),Z 链可以在那里终止而不点亮警报;上下两条是光边界,与 Z 链无关。「重量」就是步数:两个警报之间最短要走过几个数据比特,或一个警报走到最近的毛边界要几个。
How to read the picture (the same in every lattice bench on this page): this is a d = 5 planar patch. The crossings of the grid lines are star checks; they measure X-type operators and therefore report Z errors, so alarms (red dots) light up on crossings. The small grey dot in the middle of each grid segment is a data qubit, and a chain is a run of neighbouring data qubits. The half-edges sticking out on the left and right lead to the two rough boundaries (long grey dashes, labelled “rough boundary”), where a Z-chain may end without lighting an alarm; the top and bottom are smooth boundaries, irrelevant for Z-chains. “Weight” is a step count: how many data qubits the shortest route between two alarms crosses, or from one alarm to its nearest rough boundary.
Try it: the bench hands you a random syndrome and you pair as in the surface-code tutorial's decoding game, but the readout also computes your pairing's total weight alongside the lightest weight over all pairings. A few rounds in, you will find the lightest is usually easy to hit — but not always; and that even the lightest pairing occasionally loses to the true error: it is the most probable, not certain.
2.3六十年前的算法:开花A sixty-year-old algorithm: blossoms
六亿种配法不能穷举,但 1965 年 Jack Edmonds 给出了一个算法,能在多项式时间内精确找出最小重量完美匹配:运行时间只随警报数按某个固定次方增长,而不是像双阶乘那样爆炸。按今天的写法,他的原始版本约需 V²E 步(V = 症状图的点数,E = 边数;每两点都连边时 E ≈ V²/2,所以约 V⁴),Gabow 后来把它改进到 V³。这个算法叫开花算法blossom algorithm(Edmonds 1965):沿「增广路」逐步增加配对数,同时用每个点上的「对偶变量」保证每一步都只用最便宜的边;遇到奇数长度的圈就把它缩成一个点(「花」),之后再展开。。它由四个想法拼成,下面逐个讲,每个想法都对应下面回放里的一种步骤。
Six hundred million pairings cannot be enumerated, but in 1965 Jack Edmonds gave an algorithm that finds the minimum-weight perfect matching exactly in polynomial time: its running time grows like a fixed power of the number of alarms, not explosively like the double factorial. In today’s terms his original version needs about V²E steps (V = nodes of the syndrome graph, E = edges; with every pair joined, E ≈ V²/2, so about V⁴), later improved by Gabow to V³. It is the blossom algorithmEdmonds 1965: raise the number of pairs one augmenting path at a time, while “dual variables” on the nodes guarantee that only the cheapest edges are ever used; an odd cycle is shrunk to one node (a “blossom”) and expanded later.. It is built from four ideas; we take them one at a time, and each matches one kind of step in the player below.
想法一 · 增广路:一次多配一对。一个匹配是一组互不相交的配对(每个警报最多出现在一对里),还没配上的警报叫未配点。一条增广路augmenting path:从一个未配点出发、到另一个未配点结束的路径,路上的边交替地「不在匹配里、在匹配里、不在匹配里……」。把路上每条边的身份对调,配对数就加一。从一个未配点出发,交替地走「不在匹配里的边」和「在匹配里的边」,到另一个未配点结束。把路上每条边的身份对调——在的变不在、不在的变在——两端的未配点就都配上了,中间的点仍然各配一个,配对数加一。例:四个警报 A1、A2、A3、A4 排成一行,现在只有 A2–A3 配着。路 A1 – A2 = A3 – A4(「–」不在匹配里,「=」在)是一条增广路;对调之后得到 A1 = A2、A3 = A4,从 1 对变成 2 对。
Idea 1 · Augmenting paths: one more pair at a time. A matching is a set of disjoint pairs (each alarm in at most one), and an alarm not yet paired is unmatched. An augmenting pathA path from one unmatched node to another whose edges alternate “not in the matching, in the matching, not in …”. Swapping the status of every edge on it adds one pair. starts at an unmatched node, alternates between edges not in the matching and edges in it, and ends at another unmatched node. Swap the status of every edge on it — in becomes out, out becomes in — and both end nodes get partners while every interior node still has exactly one: one pair more. Example: four alarms A1, A2, A3, A4 in a row, with only A2–A3 paired. The path A1 – A2 = A3 – A4 (“–” not in the matching, “=” in it) is augmenting; after the swap we have A1 = A2 and A3 = A4, two pairs instead of one.
想法二 · 菱形是一张「下界证书」。光会增加配对数还不够,还得保证最后的配法最轻。Edmonds 的办法是给每个点 v 一个数 yv,叫对偶变量dual variable,记作 yv:算法给每个点分配的一个数,画成以该点为中心、半径 yv 的菱形。规则是任意两点的菱形不重叠:yu + yv ≤ w(u, v)。没有花的时候,所有 y 的和就是任何配法总重量的下界(有花时的修正见 2.3 节想法四)。,画成以 v 为中心、半径 yv 的菱形(格点上只能横竖走,离一个点不超过 r 步的区域正好是菱形)。唯一的规则:任意两个菱形不重叠,即对每两点 u、v 都有 yu + yv ≤ w(u, v)。两者之差 w − yu − yv 叫这条边的松弛slack:w − yu − yv,两个菱形之间还剩的空隙,始终 ≥ 0。等于 0(两个菱形相碰)的边叫紧边,算法只沿紧边配对。,就是两个菱形之间还剩的空隙;空隙为 0、两个菱形正好相碰的边叫紧边。这些数买到的是一张证书:任取一种完美匹配,它的每一对 (u, v) 都满足 w(u, v) ≥ yu + yv;把所有对加起来,每个点恰好出现一次,所以任何配法的总重量 ≥ 所有 y 之和。如果我们找到一种配法,它的每一对都是紧边,那么它的重量恰好等于 y 之和——已经碰到下界,不可能有更轻的配法,而这个结论不需要去试那六亿种。算法的全部工作,就是一边把菱形撑大(抬高下界),一边只沿紧边配对。(这一段的规则和下界只在还没有花的时候原样成立;花出现后,记账要加一项,见想法四和它后面的折叠块。)
Idea 2 · The diamonds are a lower-bound certificate. Adding pairs is not enough; the final pairing must also be the lightest. Edmonds’ device is a number yv for every node v, its dual variableWritten yv: a number the algorithm assigns to each node, drawn as a diamond of radius yv centred on it. The rule is that no two diamonds overlap: yu + yv ≤ w(u, v). While there is no blossom, the sum of all y is then a lower bound on the weight of every pairing (the correction for blossoms is in Idea 4 of §2.3)., drawn as a diamond of radius yv centred on v (on a lattice you move only horizontally and vertically, so the points within r steps of a node form exactly a diamond). The one rule: no two diamonds overlap, i.e. yu + yv ≤ w(u, v) for every two nodes. The difference w − yu − yv is the edge’s slackw − yu − yv: the gap left between two diamonds, always ≥ 0. An edge with slack 0 (the diamonds touch) is tight; the algorithm pairs only along tight edges., the gap left between the two diamonds; an edge with zero gap, where the diamonds just touch, is tight. What these numbers buy is a certificate. Take any perfect matching: each of its pairs (u, v) has w(u, v) ≥ yu + yv; add over all pairs, every node appearing exactly once, and every pairing weighs at least the sum of all y. If we find a pairing whose every pair is tight, its weight equals the sum of the y — it has hit the lower bound, no pairing can be lighter, and we know it without trying six hundred million of them. The algorithm’s whole job is to inflate the diamonds (raising the bound) while pairing only along tight edges. (The rule and the bound of this paragraph hold as stated only while there is no blossom; once blossoms appear the bookkeeping gains a term, see Idea 4 and the fold after it.)
想法三 · 外点长、内点缩,直到有两块相碰。每一轮开始,每个未配点做一棵树的根,标为外点outer node(回放里橙色):树根,以及树里「与根隔偶数条边」的点。外点的菱形会长大。;已配上、此刻不在任何树里的点叫自由点(灰色)。所有外点的菱形一起长大同样的量 δ,δ 取到「下一件事发生」为止——也就是某个外点的菱形碰到别的菱形、某条边变紧。接下来看碰到的是谁:①碰到另一棵树的外点:从一个根经紧边走到另一个根,恰好是一条增广路,对调它(增广),配对数加一,所有标记清空,开始下一轮;②碰到一个自由点:把它挂进树里当内点inner node(回放里蓝色):树里「与根隔奇数条边」的点,它在树里的孩子就是它的配对伙伴。外点长 δ 时内点缩 δ,这样连着它的两条紧边都保持紧。(蓝色),它的配对伙伴随之进树当外点(长树)——从根到这个伙伴的路又是一条交替路,伙伴就像一个新的根,可以继续往外找。内点为什么要缩?内点一边连着树里的外点父亲,一边连着外点伙伴,两条边都是紧的;外点长 δ、内点缩 δ,两条边两端的半径和都不变,照样紧,也不会和别人重叠。没有花的时候,每长一次,y 的总和净增 δ ×(外点数 − 内点数);每棵树的外点恰好比内点多一个(根,加上每个内点下面的那个伙伴),所以净增 = δ × 树的棵数,下界稳步上升。
Idea 3 · Outer nodes grow, inner nodes shrink, until two touch. At the start of each stage every unmatched node becomes the root of a tree and is labelled outerOuter node (amber in the player): a tree root, and any node an even number of edges below the root. Outer diamonds grow.; a node already paired and in no tree at the moment is free (grey). All outer diamonds grow by the same amount δ, where δ is how far they can grow until the next event — some outer diamond touching another, some edge turning tight. What happens next depends on whom it touched: (1) an outer node of another tree: walking from one root through tight edges to the other root is exactly an augmenting path; swap it (augment), gaining one pair; all labels clear and a new stage begins; (2) a free node: hang it on the tree as an innerInner node (blue in the player): a node an odd number of edges below the root; its child in the tree is its matched partner. When outer nodes grow by δ inner nodes shrink by δ, so both tight edges at it stay tight. node (blue), and its partner follows into the tree as an outer node (grow the tree) — the path from the root to that partner is again alternating, so the partner acts like a new root and can keep searching. Why do inner nodes shrink? An inner node is joined by tight edges to its outer parent and to its outer partner; when the outer ones grow by δ and it shrinks by δ, the radius sums on both edges are unchanged, so both stay tight and nothing overlaps. With no blossoms around, each growth step raises the total of the y by δ × (outer − inner); every tree has exactly one more outer node than inner ones (the root, plus the partner below each inner node), so the gain is δ × (number of trees) and the bound climbs steadily.
把三个想法放在 3.1 节那个让贪心吃亏的例子上走一遍。四个警报排成一行,间距 3、2、3(没有边界)。图里一维的「菱形」就是以警报为中心、半径 y 的一段区间:
Run the three ideas on the example where greedy loses in §3.1: four alarms in a row, spaced 3, 2, 3 (no boundary). In one dimension a “diamond” is just an interval of radius y around the alarm:
注意第一轮它也先把 A2、A3 配在一起——和贪心一样。区别在第二轮:贪心配过的对永不拆开,而开花算法通过增广路把 A2–A3 拆掉、重组成两对更短的,而且菱形之和告诉它「6 已经是下界,可以停了」。
Note that in stage 1 it also pairs A2 with A3 first, just like greedy. The difference comes in stage 2: greedy never undoes a pair, whereas the blossom algorithm breaks A2–A3 through an augmenting path and regroups into two shorter pairs — and the diamond sum tells it that 6 is already the lower bound, so it may stop.
想法四 · 奇数圈缩成一朵花。还剩一种碰法没讲:③碰到的是同一棵树里的另一个外点。从这两个外点各自往上走到它们在树里的汇合点,再加上这条紧边,围成一个圈;两个外点到汇合点的边数都是偶数,加上这条边,圈的长度是奇数。奇数圈上的点没法两两配完——总有一个落单——于是沿它对调会卡住。Edmonds 的妙招是把整个圈缩成一个点,叫一朵花blossom:由奇数个点组成、被紧边连成一圈的一组点,被当作一个「超级点」处理。花作为整体继续生长,它有自己的对偶变量 z;当它是内点且 z 缩回 0 时要展开。,当作一个外点继续长;它有自己的对偶变量 z,记录整朵花一起长了多少。花里总有一个成员不在花内部配对(它还没配上,或者配给了花外的点),叫花的基点;其余成员在花内两两配好。增广路穿过一朵花时,花内部就地改配,让增广路经过的那个成员成为新的基点,花本身保留。花作为内点挂进一棵树时,树边从外点父亲连进花里的那个成员叫入口。内花会缩,缩到 z = 0 就不能再缩(z 不能为负,理由见下面的折叠块),这时要把它展开:从入口沿圈走到基点、走边数为偶数的那一边,这条路上的成员依次标成内、外、内……重新进树,其余成员变回自由点。记账上的一点修正:回放让花里每个成员的 y 都跟着花一起涨,所以 y 的总和会多算花的厚度,真正的下界是 Σy − ΣB (|B| − 1) zB/2(|B| 是花 B 的点数);两端都在同一朵花里的边,松弛要写成 w − yu − yv + zB。下面的折叠块先用一个三角形算出这两条式子从哪来,再加两个警报,看一朵内花缩到 z = 0 并展开。
Idea 4 · Odd cycles shrink into a blossom. One kind of touch is left: (3) the other diamond belongs to an outer node of the same tree. Walking up from both outer nodes to where their tree paths meet, plus the new tight edge, closes a cycle; each outer node is an even number of edges from the meeting point, so with the new edge the cycle has odd length. The nodes of an odd cycle cannot all be paired among themselves — one is always left over — so swapping along it gets stuck. Edmonds’ trick is to shrink the whole cycle to one node, a blossomAn odd set of nodes joined in a cycle by tight edges, handled as one “super-node”. The blossom keeps growing as a whole and has its own dual variable z; when it is inner and z shrinks back to 0 it must be expanded., and keep growing it as an outer node; it has its own dual variable z recording how much the blossom has grown as a whole. A blossom always has exactly one member that is not paired inside it (it is unmatched, or matched to a node outside); that member is the blossom’s base, and the other members are paired among themselves. When an augmenting path passes through a blossom, the blossom is re-paired in place so that the member the path passes through becomes the new base; the blossom itself stays. When a blossom hangs in a tree as an inner node, the member at which the tree edge from its outer parent arrives is its entry. An inner blossom shrinks, and once its z reaches 0 it may not shrink further (z cannot be negative; the fold below says why), so it is expanded: walk round the cycle from the entry to the base along the side with an even number of edges, label the members on that path inner, outer, inner, … back into the tree, and release the remaining members as free nodes. One correction to the bookkeeping: the player raises every member’s y together with its blossom, so the sum of the y over-counts the blossom’s thickness; the true lower bound is Σy − ΣB (|B| − 1) zB/2 (|B| = the number of nodes in blossom B), and an edge with both ends in the same blossom has slack w − yu − yv + zB. The fold below first derives both formulas on a triangle, then adds two alarms to watch an inner blossom shrink to z = 0 and expand.
补课 · 一朵花从出现到展开:一个三角形算到底Catch-up · A blossom from birth to expansion: a triangle worked to the end
四个警报:A = (0, 0),B = (1, 1),C = (2, 0),D = (6, 0)(坐标是格点步数)。格点距离 = 横向差 + 纵向差:A–B、A–C、B–C 都是 2,C–D = 4,A–D = B–D = 6。三种配法:A–B + C–D = 6,A–C + B–D = 8,A–D + B–C = 8,最优是 6。
Four alarms: A = (0, 0), B = (1, 1), C = (2, 0), D = (6, 0) (coordinates in lattice steps). Lattice distance = horizontal difference + vertical difference: A–B, A–C and B–C are all 2, C–D = 4, A–D = B–D = 6. The three pairings: A–B + C–D = 6, A–C + B–D = 8, A–D + B–C = 8; the optimum is 6.
第一轮。四个点都是外点,一起长。最先相碰的是三角形的边(2 = 1 + 1),δ = 1,四个 y 都是 1。A–B 连接两棵不同的树,增广:A = B。
Stage 1. All four are outer and grow together. The triangle edges touch first (2 = 1 + 1), so δ = 1 and all four y equal 1. A–B joins two different trees: augment, A = B.
第二轮。未配的 C、D 是根。C–A 已经紧(2 = 1 + 1),A 是自由点:挂进 C 的树当内点,它的伙伴 B 当外点。B–C 也紧,而 B、C 在同一棵树里:圈 C – A = B – C 长 3,是奇数圈,缩成一朵花 {A, B, C},z 从 0 开始。
Stage 2. The unmatched C and D are roots. C–A is already tight (2 = 1 + 1) and A is free: it hangs on C’s tree as inner, and its partner B becomes outer. B–C is tight too, and B and C are in the same tree: the cycle C – A = B – C has length 3, odd, so it shrinks into a blossom {A, B, C} with z starting at 0.
继续长。外点现在是这朵花和 D。最近的空隙是 C–D:4 − 1 − 1 = 2,两边各长 1 就碰上,δ = 1。花作为整体长了 1(在回放里,三个成员的菱形半径都变成 2,花的 z 记为 2δ = 2——实现里把 z 记成厚度的两倍),D 的 y 变成 2。C–D 连接两棵不同的树:增广。花在 C 处被打开,圈里剩下的 A、B 正好配成 A = B。结果 A–B + C–D,重量 6。
Keep growing. The outer nodes are now the blossom and D. The smallest gap is C–D: 4 − 1 − 1 = 2, closed when each side grows 1, so δ = 1. The blossom grows 1 as a whole (in the player all three members’ diamonds reach radius 2 and the blossom’s z shows 2δ = 2 — the implementation records z as twice the thickness), and D’s y becomes 2. C–D joins two different trees: augment. The blossom opens at C and the remaining A and B pair up as A = B. Result A–B + C–D, weight 6.
花为什么要有自己的对偶变量Why a blossom needs its own dual variable
此刻回放里画出的四个半径是 2、2、2、2,加起来是 8,比最优的 6 还大——所以画出来的半径之和不是下界,要换一种数法。把花一起长的那 1 看成一圈围着 {A, B, C} 的「护城河」,宽度 t = 1;每个点自己单独长的是 A、B、C 各 1(第一轮)、D 共 2。护城河里装着奇数个点。任取一种完美匹配,设它有 k 对从河里跨到河外:河里的 3 个点去掉这 k 个,剩下的要在河里两两配完,所以 3 − k 是偶数,k 是奇数,至少是 1。每跨一次付河宽 t,其余的长度由各点自己的菱形保证。于是任何配法的重量 ≥ 1 + 1 + 1 + 2(各点自己的)+ k·t ≥ 5 + t = 6,正好等于算法给出的重量,最优性得证。这就是 z 的用处:一朵花的厚度在下界里只算一次,因为只能保证有一对跨过它。
At this point the player draws radii 2, 2, 2, 2, adding up to 8 — more than the optimum 6 — so the sum of drawn radii is not a bound; we must count differently. Regard the 1 the blossom grew together as a “moat” of width t = 1 around {A, B, C}; what each node grew on its own is 1 each for A, B, C (stage 1) and 2 in total for D. The moat encloses an odd number of nodes. Take any perfect matching and let k of its pairs cross from inside the moat to outside: the 3 nodes inside minus these k must pair up among themselves, so 3 − k is even, k is odd, and at least 1. Each crossing pays the moat width t, and each node’s own diamond accounts for the rest. Hence every pairing weighs ≥ 1 + 1 + 1 + 2 (each node’s own) + k·t ≥ 5 + t = 6, exactly the weight the algorithm returned, which proves optimality. That is what z is for: a blossom’s thickness counts once in the bound, because only one crossing pair is guaranteed.
z 为什么不能为负。上面最后一步用的是 k·t ≥ t:跨 k ≥ 1 次,至少付一次河宽。这一步要求 t ≥ 0。若 t < 0,跨得越多付得越少:t = −1 时一个跨 3 次的配法只付 3t = −3,比 t = −1 还少,「至少付 t」不再成立,证书作废。所以一朵内花缩到 z = 0 就必须停,不能接着缩;算法若还要往前走,就得把它展开(下面的第二个例子)。
Why z may not be negative. The last step above used k·t ≥ t: crossing k ≥ 1 times pays the moat width at least once. That step needs t ≥ 0. If t < 0, crossing more pays less: with t = −1 a pairing that crosses 3 times pays 3t = −3, less than t = −1, so “pays at least t” fails and the certificate is void. Hence an inner blossom must stop shrinking at z = 0; if the algorithm has to go on, it expands the blossom (the second example below).
回放是怎么记这笔账的。它不单独存「自己的半径」,而是让花里每个成员的 y 跟着花一起涨(花长 δ,成员的 y 都加 δ),再把花的 z 记成厚度的两倍,z = 2t。所以回放里的 yv = 点 v 自己的半径 + 所有包住 v 的花的厚度。换回下界:|B| 个点的花,厚度被每个成员各算了一次,一共 |B| 次,而下界里只该算一次,要扣掉 |B| − 1 次:
How the player keeps this account. It does not store an “own radius” separately. Instead every member’s y rises with its blossom (the blossom grows δ, every member’s y gains δ), and the blossom’s z is recorded as twice its thickness, z = 2t. So in the player yv = v’s own radius + the thickness of every blossom containing v. To get the bound back: a blossom with |B| nodes has its thickness counted once per member, |B| times in all, but the bound should count it once, so |B| − 1 copies come off:
三角形:8 − (3 − 1) × 2/2 = 6triangle: 8 − (3 − 1) × 2/2 = 6
同理,一条两端都在同一朵花里的边(比如 A–B)并不跨过这条河,两端的 y 却各带了一份厚度,所以它真正的松弛要把多算的加回来:松弛 = w − yu − yv + zB(几层花同时包住两端,就加几个 z)。A–B:2 − 2 − 2 + 2 = 0,仍然是紧的。两端不在同一朵花里的边,照旧用 w − yu − yv。(这两条式子与回放代码的每一步都对得上:我们在 2351 个随机小例子上逐步核对过,其中 1491 个出现了花。)
Likewise an edge with both ends in the same blossom (A–B, say) does not cross the moat, yet each end’s y carries one copy of the thickness, so its true slack adds the excess back: slack = w − yu − yv + zB (one z for every blossom that contains both ends). A–B: 2 − 2 − 2 + 2 = 0, still tight. An edge whose ends are not in a common blossom keeps w − yu − yv. (Both formulas agree with every step of the player’s code: we checked them step by step on 2351 random small instances, 1491 of which formed a blossom.)
一朵内花缩到 z = 0 并展开:再加两个警报An inner blossom shrinks to z = 0 and expands: two more alarms
上面那朵花一直是外点,只长不缩。要看它展开,得让它当一回内点。两个词先说清:基点是花里唯一不在花内部配对的成员(还没配上,或配给了花外的点),其余成员在花内两两配好;入口是花作为内点挂进树时,树边从外点父亲连进花里的那个成员。在三角形旁边再放两个警报 E = (−4, 0)、F = (0, 4)。新增的距离:A–E = A–F = B–F = 4,B–E = C–E = C–F = 6,E–F = 8,D–E = D–F = 10。15 种配法里唯一最轻的是 A–E + B–F + C–D = 12。下表是回放的代码在这六个点上记下的每一步(相邻的「新一轮」等记账步骤合并了),图 2.4 画出第三轮。
The blossom above stayed outer and only grew. To see an expansion it must serve as an inner node. Two words first: the base is the one member of a blossom not paired inside it (unmatched, or matched to a node outside), the others being paired among themselves; the entry is the member at which the tree edge from the outer parent arrives when the blossom hangs in a tree as an inner node. Put two more alarms next to the triangle, E = (−4, 0) and F = (0, 4). The new distances: A–E = A–F = B–F = 4, B–E = C–E = C–F = 6, E–F = 8, D–E = D–F = 10. Of the 15 pairings the unique lightest is A–E + B–F + C–D = 12. The table lists every step the player’s code records on these six points (bookkeeping steps such as “new stage” merged into their neighbours); Fig. 2.4 draws stage 3.
| 步骤Step | 发生什么What happens | y (A B C D E F) | B1 的 zz of B1 | 下界 Σy − (|B|−1)z/2bound Σy − (|B|−1)z/2 |
|---|---|---|---|---|
| 第一轮 · 生长 δ = 1Stage 1 · grow δ = 1 | 六个根一起长;三角形的边最先变紧,扫描先碰到 A–B → 增广:A = BAll six roots grow; the triangle edges become tight first and the scan meets A–B first → augment: A = B | 1 1 1 1 1 1 | — | 6 |
| 第二轮 · 长树、收缩Stage 2 · grow tree, shrink | 根是 C、D、E、F。C–A 紧:A 挂进 C 的树当内点,B 当外点;B–C 紧且同树 → 花 B1 = {A, B, C},基点 CRoots C, D, E, F. C–A is tight: A hangs on C’s tree as inner, B as outer; B–C is tight within one tree → blossom B1 = {A, B, C}, base C | 1 1 1 1 1 1 | 0 | 6 |
| 第二轮 · 生长 δ = 1Stage 2 · grow δ = 1 | 花和 D、E、F 都是外点,一起长The blossom and D, E, F are all outer and grow together | 2 2 2 2 2 2 | 2 | 12 − 2 = 10 |
| 第二轮 · 增广Stage 2 · augment | A–E 紧(4 = 2 + 2),连着两棵不同的树 → 增广:A = E;花内就地改配成 B = C,基点变成 AA–E is tight (4 = 2 + 2) and joins two different trees → augment: A = E; the blossom re-pairs in place to B = C and its base becomes A | 2 2 2 2 2 2 | 2 | 10 |
| 第三轮 · 长树(图 ①)Stage 3 · grow tree (panel ①) | 根是 D、F。D–C 紧:花(此刻是自由点,基点 A 配给 E)挂进 D 的树当内点,入口 C;E 当外点Roots D, F. D–C is tight: the blossom (free right now; its base A is matched to E) hangs on D’s tree as inner with entry C; E becomes outer | 2 2 2 2 2 2 | 2 | 10 |
| 第三轮 · 生长 δ = 1(图 ②)Stage 3 · grow δ = 1 (panel ②) | 外点 D、E、F 长,内花缩;其他紧边都还远(例如 E–F 要 δ = 2),所以 δ = z/2 = 1,z 正好归零Outer D, E, F grow, the inner blossom shrinks; every other event is further away (E–F, for instance, needs δ = 2), so δ = z/2 = 1 and z lands exactly on 0 | 1 1 1 3 3 3 | 0 | 12 |
| 第三轮 · 展开(图 ③)Stage 3 · expand (panel ③) | 从入口 C 到基点 A,沿圈有两条路:C = B – A(2 条边)与 C – A(1 条边)。取偶数的那条,标成 C 内、B 外、A 内;这条路没经过的成员变自由点(这里没有)From entry C to base A the cycle offers two routes: C = B – A (2 edges) and C – A (1 edge). Take the even one and label C inner, B outer, A inner; members off that route become free (none here) | 1 1 1 3 3 3 | — | 12 |
| 第三轮 · 增广Stage 3 · augment | B 现在是外点,B–F 紧(4 = 1 + 3),F 是另一棵树的根 → 增广 F – B = C – D:B = F、C = D,A = E 不变B is now outer and B–F is tight (4 = 1 + 3), F being another tree’s root → augment F – B = C – D: B = F, C = D, A = E unchanged | 1 1 1 3 3 3 | — | 12 |
为什么非展开不可?z 已经是 0,再缩就会变负,上面说过那会让证书作废;可是 F 还没配上,算法必须往前走。展开以后,B 不再被锁在花里,而是一个外点,于是紧边 B–F 能用来增广。结束时没有花了,下界就是 Σy = 1 + 1 + 1 + 3 + 3 + 3 = 12,等于配法的重量,最优性由证书直接给出。
Why must it expand? z is already 0, and shrinking further would make it negative, which voids the certificate as shown above; yet F is still unmatched and the algorithm must go on. After expansion B is no longer locked inside the blossom but an outer node, so the tight edge B–F can carry an augmentation. At the end no blossom is left, the bound is simply Σy = 1 + 1 + 1 + 3 + 3 + 3 = 12, equal to the pairing’s weight, and the certificate proves optimality directly.
边界怎么办。平面贴片上警报还可以单独去毛边界。回放的做法是给每个警报 Ai 配一个自己的边界节点boundary node:为每个警报单独添加的虚拟点,画成边界线上的小空心方块。Ai 与它的边界节点之间的权重 = Ai 到最近毛边界的步数;边界节点彼此之间权重为 0。(边界线上的小空心方块),两者之间的权重 = Ai 到最近毛边界的步数;边界节点彼此之间的权重为 0。这样点数是 2m,一定是偶数;Ai 配给自己的边界节点就表示「把 Ai 推出边界」,用不上的边界节点两两免费配掉。例:三个警报,A1 去边界,A2 与 A3 互配,完整的完美匹配是 A2–A3、A1–A1 的边界节点、再加上另外两个边界节点互配(重量 0)。0 权重的边在 y = 0 时已经是紧的,所以回放一开始就把边界节点两两配好。边界节点之间的这些 0 权重边后来也可能围成奇数圈、缩成只含边界节点的花;回放不把这种花画出来,但它们的 z 照样算进下界,读数会注明这一部分。
What about the boundary? On a planar patch an alarm may also go to a rough boundary alone. The player gives each alarm Ai its own boundary nodeA virtual node added for each alarm, drawn as a small hollow square on the boundary line. The weight between Ai and its boundary node = Ai’s steps to the nearest rough boundary; boundary nodes are joined to each other at weight 0. (a small hollow square on the boundary line), at a weight equal to Ai’s steps to the nearest rough boundary, and joins the boundary nodes to each other at weight 0. The node count is then 2m, always even; pairing Ai with its own boundary node means “push Ai out through the boundary”, and unused boundary nodes pair off among themselves for free. Example: three alarms, A1 goes to the boundary and A2 pairs with A3; the full perfect matching is A2–A3, A1 with its boundary node, and the two other boundary nodes with each other (weight 0). Weight-0 edges are already tight at y = 0, so the player pairs the boundary nodes up at the very start. Later these weight-0 edges between boundary nodes may also close odd cycles and shrink into blossoms made only of boundary nodes; the player does not draw such blossoms, but their z still enters the lower bound, and the readout says how much of it they account for.
回放里每一种步骤都是上面的某个想法:「初始化」(所有 y = 0,边界节点先两两配好);「新一轮」(未配点成为树根、标为外点);「生长 δ」(想法三:外点长、内点缩,花的 z 相应增减);「长树」「增广」(想法三的两种碰法);「收缩成花」「展开」(想法四)。「贪心」一栏则每步只做一件事:在剩下的警报里找全局最近的一对(或最近的边界),连上、移除、再找,配过的永不拆开。回放结束时,开花算法给出的重量会与下面「诚实说明」里的精确枚举逐次核对。
Every kind of step in the player is one of the ideas above: “Initialise” (all y = 0, boundary nodes paired up first); “New stage” (unmatched nodes become roots, labelled outer); “Grow by δ” (Idea 3: outer grow, inner shrink, blossom z moving accordingly); “Grow the tree” and “Augment” (the two touches of Idea 3); “Shrink a blossom” and “Expand” (Idea 4). The “greedy” option does one thing per step: among the remaining alarms take the globally closest pair (or the closest boundary), connect it, remove it, repeat — and never undo a pair. At the end of each run the blossom weight is checked against the exact enumeration described in the honesty box below.
现代的译码器把这个算法做到了极致:Fowler 的并行版本让每个警报只看局部邻域;Higgott 的 PyMatching 成为开源标配;Higgott 与 Gidney 2023 年的 Sparse Blossom 直接在格点上做开花算法、不预先算两两距离,按其摘要,在 0.1% 电路级噪声(5.4 节)下译码 d = 17 的表面码时,单核每轮用时不到 1 微秒,与超导芯片产生症状的速度相当。4.1 节会说为什么「跟得上」本身就是一道硬指标。
Modern decoders push the algorithm to the limit: Fowler’s parallel version lets each alarm look only at its neighbourhood; Higgott’s PyMatching became the open-source standard; and Higgott and Gidney’s 2023 Sparse Blossom runs the blossom algorithm directly on the lattice without precomputing all pairwise distances — per its abstract, decoding a distance-17 surface code under 0.1% circuit-level noise (§5.4) takes under one microsecond per round on a single core, matching the rate at which superconducting chips produce syndrome data. §4.1 explains why keeping pace is itself a hard requirement.
回放里的记号:w = 边的权重(两个警报间的格点距离,或警报到自己边界节点的距离);yu、yv = 两端点的对偶变量(内点的 y 可以缩到负数,菱形只能画出正的半径);δ = 一次生长的步长,取「下一件事发生」所需的最小值;zB = 花 B 的对偶变量,等于整朵花一起长的厚度的两倍(外花加 2δ、内花减 2δ),内花归零即展开。花里成员的 y 含着花的厚度,所以有花时下界是 Σy − ΣB(|B|−1)zB/2(「生长」一步的读数会算出它),两端在同一朵花里的边松弛是 w − yu − yv + ΣB∋u,v zB,求和遍及所有同时包住 u、v 的花(花可以一层套一层)。
Notation in the player: w = edge weight (lattice distance between two alarms, or from an alarm to its own boundary node); yu, yv = the dual variables at its ends (an inner node’s y may shrink below zero; a diamond can only show a positive radius); δ = one growth increment, the smallest amount until the next event; zB = blossom B’s dual, twice the thickness the blossom has grown as a whole (+2δ for an outer blossom, −2δ for an inner one); an inner blossom is expanded when it reaches zero. A member’s y includes its blossom’s thickness, so with blossoms the lower bound is Σy − ΣB(|B|−1)zB/2 (the “grow” readout computes it), and an edge with both ends in one blossom has slack w − yu − yv + ΣB∋u,v zB, summed over every blossom that contains both u and v (blossoms can nest).
上面的「算法逐步回放」实现的是带对偶变量的 Edmonds 开花算法(为演示而写,只处理最多十来个警报)。其余实验台里的「最轻配法」用的是另一种小规模精确法:把「还剩哪些警报没配」编成一个二进制数,对 2m 个状态逐个算最优——m ≤ 16 时瞬间完成,超过就退回贪心(第 3 章)。两种方法给出的最优重量完全一样(回放结束时会逐次核对;有并列时具体配法可以不同),只是枚举法不能扩展到几百个警报。《Surface Code · 高中数学版》的译码游戏用的正是同一段代码(那里的上限设为 14 个警报),这就是它在警报稠密时「退化为贪心」的原因。
The “algorithm step-through” above implements Edmonds' blossom algorithm with dual variables (written for demonstration; it handles a dozen alarms at most). The other benches' “lightest pairing” uses a different small-scale exact method: encode “which alarms remain unpaired” as a binary number and solve all 2m states in turn — instant for m ≤ 16, falling back to greedy beyond (Ch. 3). The two methods' optimal weights coincide exactly (the player checks this at the end of every run; with ties the actual pairing may differ); enumeration simply cannot scale to hundreds of alarms. The decoding game of “The Surface Code · High-School Edition” runs this same code (with its cutoff set at 14 alarms), which is why it “degrades to greedy” when alarms are dense.
译码的第一次「翻译」:从「找最可能的错误链」到「在症状图上找最小重量完美匹配」。端点之间怎么走不重要,谁和谁配才重要;而配对问题有精确、多项式时间的算法。这就是为什么 MWPM 是表面码译码器的默认基准。
Decoding's first “translation”: from “find the most probable error chain” to “find a minimum-weight perfect matching on the syndrome graph”. How endpoints are joined does not matter; who pairs with whom does — and pairing has an exact polynomial-time algorithm. That is why MWPM is the default benchmark for surface-code decoders.
对。第一个警报有 7 个搭档可选,然后 5、3、1。C(8,2) = 28 只数了「选出一对」,没数完剩下的。
Right. The first alarm has 7 possible partners, then 5, 3, 1. C(8,2) = 28 only counts choosing one pair, not finishing the rest.
递归:第一个警报 2m−1 个搭档,然后对剩下的 2m−2 个重复。
Recurse: 2m−1 partners for the first alarm, then repeat on the remaining 2m−2.
贪心与退化:两种输法Greed and degeneracy: two ways to lose
上一章说最优匹配可算,这一章看两种便宜的替代品各自输在哪里。贪心输给一个 3-2-3 的小陷阱;而连最优匹配本身也会输给「一类链很多」这件事——那是一道排列组合题,答案是 C(a+b, a)。 Last chapter: the optimal matching is computable. This chapter: where two cheap substitutes lose. Greed falls for a little 3-2-3 trap, while even the optimal matching loses to “a class with many chains” — a counting problem whose answer is C(a+b, a).
3.1贪心:就近配对,及其陷阱Greed: nearest-first pairing, and its trap
贪心算法一步一步怎么走,2.3 节的算法回放里选「贪心」就能逐步看到;这里看它输在哪。
To watch greedy run step by step, choose “greedy” in the algorithm player of §2.3; here we see where it loses.
最省事的译码器是贪心配对greedy pairing:反复找出当前距离最近的两个警报配成一对(平面上也可与边界比较),直到警报用完。每一步都最优,整体未必。:反复把当前最近的两个警报配对。它每一步都在做局部最优的事,但局部最优之和不是全局最优。最小的反例只需四个警报排成一线,间距依次为 3、2、3:贪心先配中间那对(重量 2),剩下两端只能互配(重量 8),总重量 10;而最优是两头各配一对,3 + 3 = 6。一般地,间距 a、b、c 且 b 最小时,贪心给 a + 2b + c,最优给 a + c,多付了 2b。
The laziest decoder is greedy pairingRepeatedly pair the two alarms currently closest (on the plane, also compare with the boundary) until none remain. Each step is optimal; the whole need not be.: repeatedly pair the two closest alarms. Every step is locally optimal, but a sum of local optima is not a global optimum. The smallest counterexample is four alarms on a line with gaps 3, 2, 3: greed pairs the middle two first (weight 2), leaving the ends to pair with each other (weight 8), total 10; the optimum pairs each end, 3 + 3 = 6. In general, with gaps a, b, c and b the smallest, greed pays a + 2b + c against the optimum a + c — an overpayment of 2b.
一般in general: a + 2b + c 对vs a + c
多付重量本身不致命——译码器的成败只看类。致命的是:贪心修复与最优修复之差,有时含奇数条横跨贴片的串(1.1 节的判据),两者就不同类。那时若真实错误就是那条最短链(这正是最可能的情形),贪心会把它「修」成一次逻辑错误。下面的实验台在 d = 5 的贴片上搜出了 8 个「贪心比最优更重」的症状(例子编号见读数)。每个例子里切到「两者之差」,红线就是两种修复之差:读数把它拆成几段,说出每段是闭合的圈、两端落在同一条毛边界上的路,还是横跨的串,再数左边界上的端点个数定输赢。这 8 个例子里,7 个的差是一段两端落在同一条毛边界上的路(贪心多走了路,但仍然同类),只有 1 个是一条横跨的串(真正的陷阱)。
Overpaying weight is not fatal by itself — only the class matters. What is fatal: the difference between the greedy and the optimal repair sometimes contains an odd number of strings spanning the patch (the criterion of §1.1), and then the two lie in different classes. If the true error is that shortest chain (the most probable case), greed “repairs” it into a logical error. The bench below searched a d = 5 patch for 8 syndromes on which greedy is heavier than the optimum (numbered in the readout). In each, switch to “their difference”: the red line is the difference of the two repairs. The readout splits it into pieces, says whether each is a closed loop, a path with both ends on the same rough boundary, or a spanning string, and counts the ends on the left boundary to give the verdict. Of the 8 examples, 7 differ by a single path with both ends on one rough boundary (greedy walked further but stays in the same class), and only 1 by a spanning string (a genuine trap).
代价在失败率上看得最清楚。6.3 节的实验台会让你亲自量:在本页的码容量模型(只有 Z 错误、测量完美)下,同样的 d = 5 贴片、p = 5% 时,贪心的整轮失败率约是最小重量匹配的两倍:我们用本页的代码(随机数种子 20260924)抽了 10⁶ 次,两种译码器看同一批错误,贪心失败 5.47%,匹配失败 2.77%(两者的 95% 置信区间都在 ±0.05 个百分点以内),比值 1.97(95% 置信区间 1.95 至 2.00)。6.3 节的实验台只取 4%、6% 这样的格点,每点只抽几百次,读数会有零点几到一两个百分点的涨落。当然,贪心的优点是简单到可以硬件化——这个矛盾把我们引向下一章的并查集译码器。
The price is easiest to see in the failure rate. The bench of §6.3 lets you measure it yourself: in this page’s code-capacity model (Z errors only, perfect measurement), on the same d = 5 patch at p = 5%, greed’s round-failure rate is about twice minimum-weight matching’s: we ran this page’s code (random seed 20260924) for 10⁶ rounds, both decoders seeing the same errors, and got 5.47% failures for greedy and 2.77% for matching (both 95% confidence intervals within ±0.05 percentage points), a ratio of 1.97 (95% confidence interval 1.95 to 2.00). The §6.3 bench uses grid points such as 4% and 6% and samples only a few hundred rounds per point, so its readings scatter by a few tenths of a point up to one or two points. Greed's virtue, of course, is simplicity that can be cast in hardware — a tension that leads to the union-find decoder of the next chapter.
3.2退化:一类里有多少条链Degeneracy: how many chains a class holds
现在轮到最优匹配自己的软肋。1.2 节说真正的最优是押类的总概率,而匹配只押一条链。两者何时不同?当某一类里有许多条同样短的链时——它们单条都不占优,加起来却占优。这叫路径退化path degeneracy:同一对端点之间存在多条长度相同的最短链。最大似然译码把它们的概率全部计入;匹配只计一条。。有多少条?两个警报横向相距 a 步、纵向 b 步,一条最短链就是 a 个「横」和 b 个「竖」排成的一列,排法数是 C(a+b, a)。到实验台上点两个检查数一数:
Now the optimal matching's own soft spot. §1.2 said true optimality bets on a class's total probability, while matching bets on one chain. When do they differ? When a class contains many equally short chains — none dominant alone, dominant together. This is path degeneracySeveral shortest chains of equal length between the same endpoints. Maximum-likelihood decoding counts all their probabilities; matching counts one.. How many? Two alarms a steps apart horizontally and b vertically: a shortest chain is one arrangement of a “across” moves and b “up” moves, and there are C(a+b, a) arrangements. Click two checks on the bench and count:
a = 1, b = 2: C(3, 1) = 3 · a = b = 2: C(4, 2) = 6
a = b = 3: C(6, 3) = 20 · a = b = 5: C(10, 5) = 252
现在做一道会翻盘的题。设某个症状下,甲类里最短的链长 5 且只有一条;乙类里最短的链长 6,但有 20 条(a = b = 3)。匹配选甲(5 < 6)。最大似然比的是总概率。这里做一个近似:只比两类各自的最短链。(更长的链单条更不可能,每多一步就再乘一次 p/(1−p),但它们的条数随长度增长得很快,合起来的贡献不一定小;要得到准确的答案,得把整类所有链的概率加起来,那正是最大似然译码器做的事。)在这个近似下:甲 ∝ e−5w₀,乙 ∝ 20·e−6w₀。乙胜出当且仅当 20·e−w₀ > 1,即 p/(1−p) > 1/20,即 p > 1/21 ≈ 4.8%。也就是说,按最短链估算,错误率一过约 4.8%,「多一步但有 20 条」的类就比「少一步但只有 1 条」的类更可能,匹配就押错了。4.8% 是这个近似下的交界点,不是精确值;它说明的是方向:错误率越高,条数越要紧。
Now a problem that flips the verdict. Suppose that under some syndrome class A's shortest chain has length 5 and is unique, while class B's shortest chains have length 6 but there are 20 of them (a = b = 3). Matching picks A (5 < 6). Maximum likelihood compares totals. Here we make an approximation: compare only each class’s shortest chains. (A longer chain is individually less likely, each extra step multiplying by another p/(1−p), but the number of such chains grows quickly with length, so together they need not contribute little; the exact answer needs the sum over every chain of each class, which is precisely what a maximum-likelihood decoder does.) In this approximation: A ∝ e−5w₀, B ∝ 20·e−6w₀. B wins iff 20·e−w₀ > 1, i.e. p/(1−p) > 1/20, i.e. p > 1/21 ≈ 4.8%. So by the shortest-chain estimate, once the error rate passes about 4.8% the class that is “one step longer but twenty-fold” becomes likelier than the “one step shorter but unique” class, and matching bets wrong. The 4.8% is the crossover of this approximation, not an exact value; what it shows is the direction: the higher the error rate, the more the count matters.
匹配只看能量(最短长度),最大似然还看熵(有多少条链)。低错误率下能量压倒一切,两者几乎一致;错误率越高,熵的话语权越大。这就是为什么文献里表面码有两个码容量阈值:最大似然约 10.9%,匹配约 10.3%(出处见 6.2 节的账本)——两者之差不是数值误差,是两种译码器之间的 0.6 个百分点。
Matching sees only energy (shortest length); maximum likelihood also sees entropy (how many chains). At low error rates energy dominates and the two agree; the higher the error rate, the louder entropy speaks. That is why the literature quotes two code-capacity thresholds for the surface code: about 10.9% for maximum likelihood and about 10.3% for matching (sources in the ledger of §6.2) — the gap is not numerical uncertainty but 0.6 percentage points between two decoders.
学名一瞥:随机键 Ising 模型与自由能A glimpse of the scholarly name: the random-bond Ising model and free energy
Dennis、Kitaev、Landahl 与 Preskill(2002)发现:一类链的总概率与统计物理里的配分函数是同一个式子。配分函数把一个系统所有可能的构型按 e−能量/温度 加权求和;把链的长度 ℓ 看成「能量」、把 w₀ 看成「温度的倒数」(温度 T = 1/w₀),一类的配分函数就是 Z(类) = ∑C ∈ 类 e−ℓ(C)/T = ∑ e−w₀ℓ(C)。1.2 节的类概率正是 (1−p)n · Z(类),公因子 (1−p)n 对两类一样。于是「最短链」= 能量最低的构型。自由能定义为 F = −T ln Z,也就是 Z = e−F/T,所以比两类的总概率就是比它们的自由能,F 小的那类更可能。一个特殊情形能看出 F 里装着什么:若一类里要算的构型都一样长,长度都是 E,一共 N 条,那么 Z = N·e−E/T,F = E − T ln N,即能量减去温度乘 ln(条数);这个 ln N 就是这种情形下的熵 S,数的是「有多少种」。上面只算最短链的例子正属于这种情形:甲类 F = 5,乙类 F = 6 − T ln 20,乙类多出的 1 份能量被 T ln 20 抵消;乙胜出 ⇔ T ln 20 > 1 ⇔ w₀ < ln 20,和正文的 20·e−w₀ > 1 是同一个条件。链长短不一时就没有「熵 = ln 条数」这么简单的式子,只能直接用 Z 和 F。匹配相当于把温度降到零:只留能量最低的那一项。最大似然对应的温度恰好由真实的错误率 p 决定(w₀ = ln((1−p)/p)),这些点在统计物理的相图上连成一条线,叫 Nishimori 线。阈值在这幅图景里是一次相变:错误率低于它时,贴片越大,错误那一类的总概率相对正确那一类越小,趋于零;高于它时两类越来越难分——这种随尺寸变大而出现的突变,正是统计物理里相变的定义性特征。DKLP 引用的最大似然阈值 10.94% 就是在这条线上用蒙特卡洛模拟算出的相变点(见 6.2 节)。
Dennis, Kitaev, Landahl and Preskill (2002) noticed that a class’s total probability is the same expression as a partition function in statistical physics. A partition function sums over all configurations of a system, each weighted by e−energy/temperature; read the chain length ℓ as “energy” and w₀ as an inverse temperature (temperature T = 1/w₀), and a class’s partition function is Z(class) = ∑C ∈ class e−ℓ(C)/T = ∑ e−w₀ℓ(C). The class probability of §1.2 is exactly (1−p)n · Z(class), with the factor (1−p)n common to both classes. Then “shortest chain” = lowest-energy configuration. The free energy is defined as F = −T ln Z, i.e. Z = e−F/T, so comparing the two classes’ total probabilities means comparing their free energies, and the class with the smaller F is likelier. A special case shows what F contains: if all the configurations counted in a class have the same length E and there are N of them, then Z = N·e−E/T and F = E − T ln N, energy minus temperature times ln(count); this ln N is the entropy S of that case, a count of “how many”. The shortest-chains-only example above is such a case: class A has F = 5, class B has F = 6 − T ln 20, B’s one extra unit of energy is offset by T ln 20, and B wins ⇔ T ln 20 > 1 ⇔ w₀ < ln 20, the same condition as 20·e−w₀ > 1 in the main text. When the chains have different lengths there is no formula as simple as “entropy = ln count”; one works with Z and F directly. Matching amounts to cooling to zero temperature: only the lowest-energy term survives. Maximum likelihood sits at the temperature fixed by the true error rate p (w₀ = ln((1−p)/p)); these points form a line in the physicist’s phase diagram, the Nishimori line. The threshold, in this picture, is a phase transition: below it, the larger the patch, the smaller the wrong class’s total probability relative to the right one, going to zero; above it the two classes become ever harder to tell apart — an abrupt change that appears as the size grows, which is the defining feature of a phase transition. The maximum-likelihood threshold 10.94% quoted by DKLP is the transition point on this line, located by Monte Carlo simulation (see §6.2).
对。横横竖竖、横竖横竖、横竖竖横、竖横横竖、竖横竖横、竖竖横横,六条。最大似然把这六条的概率都算进这一类。
Right. AAUU, AUAU, AUUA, UAAU, UAUA, UUAA — six of them. Maximum likelihood counts all six toward the class.
一条最短链 = 2 个「横」和 2 个「竖」的一种排列顺序。
A shortest chain = one ordering of 2 “across” and 2 “up” moves.
并查集译码器:长大、合并、剥皮The union-find decoder: grow, merge, peel
匹配精确但要算距离、排顺序;贪心快但会掉进陷阱。2017 年出现了第三条路:让每个警报像水滴一样向外长,碰到就合并,直到每一滴里的警报数变成偶数,然后沿一棵树从叶子往根「剥皮」。它几乎不需要算术,速度几乎与警报数成正比,阈值却只比匹配低一点。 Matching is exact but computes distances and sorts; greed is fast but falls into traps. In 2017 a third road appeared: let every alarm grow outward like a droplet, merge on contact until each droplet holds an even number of alarms, then “peel” a tree from its leaves to its root. It needs almost no arithmetic, runs in nearly linear time, and its threshold sits only slightly below matching's.
4.1为什么要更快Why faster matters
真实芯片大约每一微秒就产出一轮症状(例如 Google 2024 年的 Willow 芯片,一轮 1.1 微秒)。译码器若跟不上,未处理的症状会越积越多,而《格点手术 · 高中数学版》要讲的逻辑门必须等译码结果才能决定下一步——积压意味着整台机器越跑越慢,直到失控。所以译码器有两个指标:阈值(多准)和吞吐(多快),两者要同时达标。开花算法准,但在大贴片和长时间窗上很重。Delfosse 与 Nickerson 在 2017 年给出的并查集译码器union-find decoder(Delfosse–Nickerson 2017):先让奇数簇生长合并(用「并查集」数据结构记录谁和谁同簇),再在每个簇里沿生成树剥皮得到修复。运行时间近似线性。把精度让出一点,换来几乎线性的运行时间。
A real chip emits one round of syndrome roughly every microsecond (Google’s 2024 Willow chip, for instance, runs one round per 1.1 µs). If the decoder cannot keep up, unprocessed syndromes pile up — and the logical gates of “Lattice Surgery · High-School Edition” must wait for decoding results before choosing their next step, so a backlog means the whole machine slows down until it runs away. A decoder therefore has two scores: threshold (how accurate) and throughput (how fast), and both must pass. Blossom is accurate but heavy on large patches over long time windows. Delfosse and Nickerson's 2017 union-find decoderFirst grow and merge odd clusters (tracking who shares a cluster with the “union-find” data structure), then peel a spanning tree inside each cluster to read off the repair. Almost-linear running time. gives up a little accuracy for almost-linear time.
4.2生长与合并Growth and merging
先说什么是簇:格点上连成一片的一组检查,加上它们之间的边(边就是数据比特)。规则只有三句。起点:每个警报自成一个簇(只有一个检查、没有边)。生长:含奇数个警报的簇向外长一层——把与簇相邻的所有边、以及这些边另一端的检查都收进来;含偶数个警报的簇、以及已经碰到毛边界的簇,停下。停下的簇里一定能找到一组边,恰好消掉簇内所有警报(簇是连成一片的,偶数个警报可以在簇内两两连起来;碰到边界的簇则可以把落单的那个推出边界),怎么找见 4.3 节。合并:两个簇一旦共享一条边就合成一个簇,警报数相加。奇数加奇数是偶数,所以合并常常一下子让两个簇同时停下。「谁和谁同簇」这件账,交给一种叫并查集union-find(disjoint-set):一种数据结构,用「每个元素记住自己的上级」表示分组。find(x) 沿上级找到根,就知道 x 属于哪一组;union(a, b) 把一组的根挂到另一组的根下。「按大小合并」加「路径压缩」两项优化让两种操作平均接近常数时间。的数据结构:它只回答两个问题——「x 属于哪个簇」和「把这两个簇并成一个」,每个都几乎一步完成。 这里写的是最简单的均匀生长版:每一轮所有奇数簇一起长。Delfosse 与 Nickerson 的论文第 5 节还给了一个加权生长版:每次只让边界最小(簇边上待收的边最少)的那个奇数簇长;他们报告,这一改动把环面码的阈值从 9.2% 提到 9.9%(码容量),从 2.4% 提到 2.6%(现象学噪声)。本页的实验台用的是均匀生长版,而且每次收整条边(论文里是每次长半条边),是更粗的简化。
First, a cluster: a connected group of checks on the lattice together with the edges between them (edges being data qubits). Three sentences of rules. Start: every alarm is its own cluster (one check, no edges). Grow: a cluster holding an odd number of alarms grows one layer — it absorbs every edge adjacent to it and the checks at the far ends of those edges; clusters with an even count, or already touching a rough boundary, stop. A stopped cluster always contains a set of edges that cancels exactly its alarms (the cluster is connected, so an even number of alarms can be joined in pairs inside it; a boundary cluster can push the odd one out through the boundary); §4.3 shows how to find it. Merge: two clusters sharing an edge fuse into one, alarm counts adding. Odd plus odd is even, so a merge often stops two clusters at once. The bookkeeping of “who shares a cluster with whom” is handled by the union-findA disjoint-set structure in which every element remembers a parent. find(x) follows parents to the root, revealing x's group; union(a, b) hangs one root under the other. The two optimisations “union by size” and “path compression” make both operations nearly constant time on average. data structure: it answers just two requests — “which cluster is x in?” and “merge these two clusters” — each in almost one step. What is written here is the simplest, uniform-growth version: in each round all odd clusters grow together. Section 5 of Delfosse and Nickerson’s paper adds a weighted-growth version that always grows only the odd cluster with the smallest boundary (the fewest edges waiting at its rim); they report that this change raises the toric-code threshold from 9.2% to 9.9% (code capacity) and from 2.4% to 2.6% (phenomenological noise). The benches on this page run the uniform version and add whole edges at a time (the paper grows half an edge at a time), a coarser simplification still.
并查集到底是什么?三行代码的数据结构What is union-find, really? A three-line data structure
一个数组 parent,parent[x] 是 x 的「上级」,根的上级是自己。find(x):沿上级一路向上直到根——两个元素同簇当且仅当根相同。union(a, b):把一个根挂到另一个根下面。例:parent = [0, 0, 1, 3](元素 0 是根,1 的上级是 0,2 的上级是 1,3 自成一组)。find(2):2 → 1 → 0,根是 0;find(3) = 3,所以 2 与 3 不同簇。union(2, 3) 把根 3 挂到根 0 下面,parent[3] = 0,现在四个元素同簇。两项优化让它快:按大小合并——总是把小组的根挂到大组的根下,树就不会长得太高;路径压缩——find 走过一路后,把沿途所有元素的上级直接改成根(上例 find(2) 之后 parent[2] = 0),下次再问就一步到位。Tarjan 1975 年证明,两项优化一起用时,n 次操作总共约需 n·α(n) 步,其中 α 是增长慢到离谱的反阿克曼函数:对任何能在物理宇宙里写出来的 n,α(n) ≤ 4。所以说「几乎线性」。(只用路径压缩而不按大小合并,保证的界要差一个对数因子。)
One array parent: parent[x] is x's superior, and a root is its own superior. find(x): follow superiors up to the root — two elements share a cluster iff their roots coincide. union(a, b): hang one root under the other. Example: parent = [0, 0, 1, 3] (element 0 is a root, 1’s superior is 0, 2’s is 1, and 3 is a group of its own). find(2): 2 → 1 → 0, root 0; find(3) = 3, so 2 and 3 are in different clusters. union(2, 3) hangs root 3 under root 0, parent[3] = 0, and all four now share a cluster. Two optimisations make it fast: union by size — always hang the smaller group’s root under the larger’s, so trees stay shallow; path compression — after find walks a path, re-point every element on it straight to the root (after find(2) above, parent[2] = 0), so the next query takes one step. Tarjan proved in 1975 that with both optimisations n operations take about n·α(n) steps in total, where α is the absurdly slow-growing inverse Ackermann function: α(n) ≤ 4 for any n that could be written down in the physical universe. Hence “almost linear”. (Path compression alone, without union by size, guarantees a bound worse by a logarithmic factor.)
4.3剥皮Peeling
生长结束后,每个簇里的警报数都是偶数(或者簇碰到了边界)。现在要在簇内找一批边,使它们的端点恰好是簇内的警报——但不必是最短的,簇本身已经不大。先借两个图论词。树是一组没有圈的、连成一片的边;簇的一棵生成树是用簇里的边把簇里所有检查连起来、又不含任何圈的那样一组边(每丢掉一条会闭合成圈的边,就离生成树近一步)。在树里选定一个根,每个点就有一个唯一的父节点(往根方向的下一个点);只连着一条树边、又不是根的点叫叶子。做法叫剥皮peeling:在簇内取一棵生成树(触边的簇以边界为根)。反复取一片叶子:若叶子是警报,则把连接它的那条边计入修复并把父节点的警报状态翻转;然后删去叶子。树剥完,修复就得到了。:在簇内取一棵生成树(若簇碰到边界,就以边界为根),然后反复处理叶子。叶子若是警报,把连它的边计入修复,并把「警报」传给它的父节点(父节点原来是警报就变不是,原来不是就变是);叶子若不是警报,什么也不做。删掉叶子,继续。树剥完,每条计入的边都恰好消掉了两端的警报状态,簇内症状清零。回放把「此刻还需要消掉的警报标记」叫缺陷:开始时缺陷就是警报,剥皮会把它从叶子一步步搬向根。
小例子:一个簇是一条直线 S1 – S2 – S3(两条边),S1、S3 亮着警报,以 S3 为根。叶子 S1 有缺陷:保留边 S1–S2,缺陷搬到 S2。此时 S2 成了叶子、带着缺陷:保留边 S2–S3,S3 的缺陷被翻掉(亮变不亮)。剩下根 S3,没有缺陷。修复 = 两条边,正是连接两个警报的那条链。
Once growth ends, every cluster holds an even number of alarms (or touches a boundary). We now need a set of edges inside the cluster whose endpoints are exactly the cluster's alarms — not necessarily the shortest, the cluster is small already. Two words from graph theory first. A tree is a connected set of edges with no cycle; a spanning tree of a cluster is a set of the cluster’s edges that connects all its checks without closing any cycle (dropping each edge that would close a cycle brings you one step closer to one). Choose a root in the tree; then every other node has a unique parent (the next node toward the root), and a non-root node touching only one tree edge is a leaf. The method is peelingTake a spanning tree inside the cluster (rooted at the boundary if the cluster touches one). Repeatedly take a leaf: if it is an alarm, add its edge to the repair and flip the parent's alarm status; then delete the leaf. When the tree is gone, the repair is complete.: take a spanning tree inside the cluster (rooted at the boundary if the cluster touches one) and process leaves repeatedly. If a leaf is an alarm, add its edge to the repair and pass the alarm to its parent (a parent that was an alarm stops being one, and vice versa); if the leaf is not an alarm, do nothing. Delete the leaf, continue. When the tree is gone, every chosen edge has cancelled the alarm status at both ends and the cluster's syndrome is clear. The player calls “an alarm mark still to be cancelled” a defect: at the start the defects are the alarms, and peeling carries them from the leaves toward the root.
A small example: a cluster is the straight line S1 – S2 – S3 (two edges) with alarms at S1 and S3, rooted at S3. Leaf S1 carries a defect: keep edge S1–S2 and move the defect to S2. Now S2 is a leaf carrying a defect: keep edge S2–S3, which flips S3’s defect off (lit becomes unlit). Only the root S3 remains, defect-free. Repair = two edges, exactly the chain joining the two alarms.
为什么一定能清零?因为每处理一片叶子,「簇内警报数为偶」这一性质保持不变(要么不动,要么同时翻转叶子与父节点),最后只剩根:若根不是边界,偶数个缺陷里只剩它一个点,它的缺陷数只能是 0;若根是边界,落单的那个缺陷被它吸收,意思是修复链从那里出界。实验台里每一步都在格点上标出「叶 S…」和「父 S…」。逐步看:
Why must it clear? Because processing a leaf preserves the property “the cluster's alarm count is even” (either nothing changes, or leaf and parent flip together), so when only the root remains: if it is not the boundary, an even defect count on a single node can only be 0; if it is the boundary, the leftover defect is absorbed there, meaning the repair chain leaves the patch at that point. The bench labels each step’s “leaf S…” and “parent S…” on the lattice. Step through it:
本页的并查集译码器是原论文的直观版:簇每次整条边地长;论文里簇每次长「半条边」,两个簇各长半条时正好在中点相遇,这样更节省、精度更高。此外,论文对生长顺序(先长小簇)和边界处理有更细致的规定。文献报告的阈值数字见第 6 章的账本;本页的版本用第 6 章的实验台测,会略低。
This page's union-find decoder is the intuitive version of the original: clusters grow a whole edge at a time; in the paper they grow half an edge, so two clusters growing toward each other meet exactly midway — thriftier and more accurate. The paper also specifies the growth order (smallest clusters first) and boundary handling more carefully. The threshold reported in the literature is in Chapter 6's ledger; this page's version, measured on Chapter 6's bench, comes out a little lower.
并查集译码器把「找最短路径」换成了「判断奇偶」和「合并集合」——两件几乎不用算术的事。它不保证最轻,但保证清零,而且簇的大小天然受限于错误的稀疏程度:错误率低时簇小,几乎和匹配一样好;速度几乎线性,可以做进硬件。准确与快速之间的这个交易,正是今天实时译码器设计的主题。
The union-find decoder swaps “find shortest paths” for “test parity” and “merge sets” — two operations that barely compute. It does not guarantee the lightest repair, but it guarantees a cleared syndrome, and cluster size is naturally bounded by how sparse the errors are: at low error rates clusters are tiny and it nearly matches matching; its speed is almost linear and it fits in hardware. That trade between accuracy and speed is the theme of today's real-time decoder design.
对。奇数簇内不可能把警报全部配完——每条边消掉两个警报状态。所以它必须长到「偶数」或「有边界可配」。这也是并查集译码器与平面边界打交道的方式:边界是永远可以吸收一个奇数的那个「根」。
Right. An odd cluster can never pair all its alarms — each edge cancels two alarm statuses. So it must grow until it is even or has a boundary to pair with. That is also how the union-find decoder handles planar boundaries: the boundary is the root that can always absorb one odd alarm.
数奇偶:每条修复边消掉两个警报状态,3 是奇数。
Count parity: each repair edge cancels two alarm statuses, and 3 is odd.
时空译码:测量也会错Spacetime decoding: measurements fail too
前四章默认警报是真的。真实芯片上,辅助比特会出错、读出仪会看走眼——警报本身可能是假的。解药是反复测量,并只在读数变化时报警。这样一来,测量错误和数据错误在时空图上各有一种指纹,而译码仍然是同一个配对问题,只是多了一个维度。 The first four chapters assumed alarms were real. On a real chip, ancilla qubits fail and readout misfires — an alarm may be false. The remedy is to measure repeatedly and to raise an alarm only when a readout changes. Then measurement errors and data errors leave distinct fingerprints on a spacetime graph, and decoding is the same matching problem in one more dimension.
5.1假警报,与只报「变化」的探测器False alarms, and detectors that report only change
《Surface Code · 高中数学版》第 4 章说,一条检查的读数是由辅助比特收集、再单独读出的。若辅助比特在收集途中被翻、或读出仪读反了,这一轮的这条检查就报出一个错误的 ±1——数据比特其实好好的。单看一轮,真警报与假警报无法区分。但假警报有个弱点:它只持续一轮。下一轮重测,读数又回到正确值。相反,一个真实的数据错误会让该检查的读数从出错那一轮起持续翻转。于是改用探测器detector:同一条检查相邻两轮读数的异或,D(i,t) = s(i,t) ⊕ s(i,t−1)。读数不变时为 0,只有「变了」才亮。报警:D(i,t) = s(i,t) ⊕ s(i,t−1),同一条检查相邻两轮读数不同才亮。这里 s(i,t) 是第 i 条检查在第 t 轮的读数,写成一位二进制数:读到 +1 记 0,读到 −1 记 1;⊕ 是一位数的异或,0 ⊕ 0 = 1 ⊕ 1 = 0,0 ⊕ 1 = 1 ⊕ 0 = 1;开始前没有错误,所以约定 s(i,0) = 0。
手算一遍。某条检查五轮的读数是 0, 0, 1, 1, 1(第 3 轮起一个数据错误让它一直报 −1):探测器 D = 0, 0, 1, 0, 0,只在变化的那一轮亮一次。另一条检查的读数是 0, 0, 1, 0, 0(第 3 轮读反了一次):D = 0, 0, 1, 1, 0,第 3、4 两轮各亮一次——一次读错留下的是时间上相邻的一对。
“The Surface Code · High-School Edition”, Chapter 4 explained that a check's value is collected by an ancilla and read out separately. If the ancilla is flipped midway or the readout misfires, that check reports a wrong ±1 this round — while the data qubits are fine. Within a single round, real and false alarms are indistinguishable. But a false alarm has a weakness: it lasts one round. Re-measure and the value returns to normal. A genuine data error, by contrast, flips that check's value persistently from the round it happens. So we raise alarms with detectorsThe XOR of the same check's readouts in consecutive rounds, D(i,t) = s(i,t) ⊕ s(i,t−1). Zero while the value stays put; lit only on change. instead: D(i,t) = s(i,t) ⊕ s(i,t−1), lit only when a check's value differs between consecutive rounds. Here s(i,t) is check i’s readout in round t written as one bit: +1 is recorded as 0 and −1 as 1; ⊕ is the XOR of bits, 0 ⊕ 0 = 1 ⊕ 1 = 0 and 0 ⊕ 1 = 1 ⊕ 0 = 1; there are no errors before the start, so by convention s(i,0) = 0.
Work one by hand. A check reads 0, 0, 1, 1, 1 over five rounds (from round 3 a data error keeps it at −1): its detectors are D = 0, 0, 1, 0, 0, lit once, in the round of the change. Another check reads 0, 0, 1, 0, 0 (misread once in round 3): D = 0, 0, 1, 1, 0, lit in rounds 3 and 4 — a single misreading leaves a pair adjacent in time.
数据错误 ⇒ 同一时刻、相邻两条检查的探测器亮(横向一对)data error ⇒ two adjacent checks light at the same time (a horizontal pair)
测量错误 ⇒ 同一条检查、相邻两轮的探测器亮(纵向一对)measurement error ⇒ the same check lights in two consecutive rounds (a vertical pair)
5.2两种指纹,一张时空图Two fingerprints, one spacetime graph
为了把图画清楚,这一节用最简单的码——一维重复码(L 个比特排成一行,相邻两个比特之间一条 ZiZi+1 检查)——然后把时间画成第二个维度:每一行是一轮测量,最上面一行是最终的完美读出(实验结束时直接测量数据比特,可以精确算出最后一轮的症状)。规则如上:数据错误在它发生的那一轮点亮左右两条检查的探测器(贴边的只亮一条);测量错误点亮同一条检查这一轮与下一轮的探测器。两种事件都留下一对,只是方向不同。到实验台上点几个错误,看探测器的花样:
To keep the picture clean, this section uses the simplest code — a one-dimensional repetition code (L bits in a row, a ZiZi+1 check between neighbours) — and draws time as the second dimension: each row is one measurement round, and the top row is the final perfect readout (at the end of the experiment the data bits are measured directly, which pins down the last syndrome exactly). Rules as above: a data error lights the detectors of its two neighbouring checks in the round it occurs (one at an edge); a measurement error lights the same check in this round and the next. Both events leave a pair, just in different directions. Toggle a few errors on the bench and watch the pattern:
现在按「译码」。译码器做的仍是2.2 节的事:把亮起的探测器两两配对(或配到左右边界),只是距离现在有两种分量——横向一步和纵向一步。配对完成后,把每条配对路径的横向部分翻转成数据比特的修复(纵向部分对应的是测量错误,不需要修数据)。残留 = 最终真实错误 ⊕ 修复,在一条线上只有两种可能:空集(成功),或整条线全翻(逻辑错误 X̄)。
Now press “Decode”. The decoder still does what §2.2 did: pair the lit detectors (or send them to the left/right boundary), except that distance now has two components — a horizontal step and a vertical one. Once paired, the horizontal part of each pairing path becomes a repair on the data bits (the vertical part corresponds to measurement errors, which need no data repair). Residual = final true error ⊕ repair; on a line it can only be empty (success) or the whole line (logical error X̄).
5.3两种权重,与掉下来的阈值Two weights, and a threshold that drops
若数据错误率为 p、测量错误率为 q,1.3 节的对数权重各算一份:横向每步 wS = ln((1−p)/p),纵向每步 wT = ln((1−q)/q)。p = q 时两者相等,时空图是各向同性的;否则译码器会偏爱便宜的方向。实验台上切换「等权 / 按概率加权」可以看到配法随之改变。对表面码,同样的构造把二维格点变成三维时空块(长 × 宽 × 轮数),探测器事件在三维里配对——算法不变。
With data error rate p and measurement error rate q, §1.3's log weights come in two flavours: wS = ln((1−p)/p) per horizontal step and wT = ln((1−q)/q) per vertical step. At p = q they coincide and the spacetime graph is isotropic; otherwise the decoder favours the cheaper direction. Switching “unit / probability weights” on the bench changes the pairing accordingly. For the surface code the same construction turns the 2D lattice into a 3D spacetime block (length × width × rounds), and detector events are paired in three dimensions — same algorithm.
代价体现在阈值上。表面码用完美测量、匹配译码时阈值约 10.3%;加入与数据错误同样大的测量错误(p = q,这种模型叫现象学噪声phenomenological noise:每轮每个数据比特以概率 p 出错、每条检查的读数以概率 q 读反,不细究测量电路内部。它是「完美测量」与「电路级噪声」之间的中间模型。),阈值掉到约 2.9%(两个数都是匹配译码,Wang–Harrington–Preskill 2003;同一模型下 Delfosse–Nickerson 2017 报告并查集译码器的加权生长版为 2.6%、均匀生长版为 2.4%)。掉的原因不是译码器变笨,而是每一轮多了一整层可以出错的地方,而失败模式(在时空里横跨的串)也多了一个可以延伸的方向。
The price shows in the threshold. With perfect measurement and a matching decoder the surface code's threshold is about 10.3%; add measurement errors as likely as data errors (p = q, a model called phenomenological noiseEach round, every data qubit fails with probability p and every check readout flips with probability q, without modelling the measurement circuit's internals. The middle model between perfect measurement and circuit-level noise.) and it drops to about 2.9% (both numbers for matching, Wang–Harrington–Preskill 2003; for the same model Delfosse–Nickerson 2017 report 2.6% for the weighted-growth union-find decoder and 2.4% for the uniform-growth version). Not because the decoder got dumber, but because each round adds a whole layer of places to fail, and the failure mode — a string spanning spacetime — gains a direction to extend in.
5.4再往下一层:电路级噪声One layer down: circuit-level noise
现象学模型仍然是简化。真实的一轮测量由制备、四个 CNOT、读出组成,每一步都可能出错;一个辅助比特在第二个 CNOT 之后出错,会通过后两个 CNOT 传到两个数据比特上——《Surface Code · 高中数学版》第 4 章提过的 hook error(「钩子错误」:辅助比特上的一个故障,经过还没做完的 CNOT,变成数据比特上的两个错误)。在电路级噪声下,一个故障点亮的探测器不再总是「相邻的一对」:钩子错误留下的一对隔得更远;而一个同时带 X 与 Z 分量的故障,例如数据比特上的一个 Y 错误(Y = X·Z,只差一个相位),会同时点亮两族检查,一共四个探测器(图 5.1)。现代译码器先用模拟把每一种基本故障点亮哪些探测器、发生的概率多大列成一张表,叫探测器错误模型(detector error model)。可匹配图的一条边只能连两个探测器(或一个探测器与边界),所以只点亮一两个探测器的故障可以直接变成一条边,点亮三四个的故障就得先分解:拆成几块,每块只点亮一两个探测器,各当一条边。图 5.1 的 Y 错误拆成「Z 部分:点亮星 S1、S2」与「X 部分:点亮面 P1、P2」两条边,分别放进两族检查各自的匹配图。代价是丢掉关联:这两条边本来总是一起出现(一次故障),分开匹配时却被当成两次独立的故障,同时出现要付两份权重,这种组合的可能性就被低估了。以 PyMatching 为例,它的文档写明:从探测器错误模型建图时,点亮一两个探测器的故障成为边,点亮更多探测器、又没有给出分解的故障直接被忽略。尾声提到的 belief-matching 就是把这份关联找回来的一种办法。电路级噪声circuit-level noise:把一轮症状提取电路里的每个门、每次制备与读出都当作独立的出错位置。阈值数字依赖于具体电路与每步的错误定义,文献值约 0.5%–1%。下的阈值约 0.5%–1%(具体值取决于电路和「一步出错」的定义;例如 Fowler 等 2012 在他们的八步电路、每步错误率 p、匹配译码下得到 0.57%),这才是硬件团队真正对照的数字——第 6 章的账本会说清这些数字各自的前提。
The phenomenological model is still a simplification. A real round consists of preparation, four CNOTs and a readout, each of which can fail; an ancilla error after the second CNOT propagates through the remaining two onto two data qubits — the hook error mentioned in “The Surface Code · High-School Edition”, Chapter 4 (one fault on the ancilla which, through the CNOTs still to come, becomes two errors on data qubits). Under circuit-level noise a single fault no longer always lights “a neighbouring pair” of detectors: a hook error leaves a pair further apart, and a fault with both an X and a Z component, such as a Y error on a data qubit (Y = X·Z up to a phase), lights both families of checks, four detectors in all (Fig. 5.1). Modern decoders first tabulate, by simulation, which detectors each elementary fault lights and how likely it is: the detector error model. But an edge of a matching graph joins only two detectors (or one detector and the boundary), so a fault lighting one or two detectors becomes an edge directly, while a fault lighting three or four must first be decomposed: split into pieces that each light one or two detectors, each piece becoming an edge. The Y error of Fig. 5.1 splits into “the Z part, lighting stars S1 and S2” and “the X part, lighting plaquettes P1 and P2”, two edges placed in the matching graphs of the two check families. The price is lost correlation: the two edges always occur together (one fault), yet matched separately they count as two independent faults, their joint occurrence is charged two weights, and the combination is judged less likely than it is. PyMatching, for example, documents that when it builds a graph from a detector error model, faults lighting one or two detectors become edges, and faults lighting more that come without a suggested decomposition are ignored. Belief-matching, mentioned in the epilogue, is one way to recover that correlation. Under circuit-level noiseEvery gate, preparation and readout in one syndrome-extraction round is an independent fault location. The threshold depends on the specific circuit and on how a step's error is defined; literature values are about 0.5%–1%. the threshold is about 0.5%–1% (the exact value depends on the circuit and on how “one step fails” is defined; Fowler et al. 2012, for instance, find 0.57% for their eight-step circuit, per-step error rate p and matching) — the number hardware teams actually compare against; Chapter 6's ledger spells out the premises behind each figure.
测量错误不需要新思想,只需要新维度。探测器把「读数」换成「读数的变化」,于是测量错误变成时间方向上的一对端点,与数据错误在空间方向上的一对端点用同一个匹配算法处理。从此空间和时间是平等的两个方向:一个能骗过匹配的错误串,不论沿哪个方向延伸,都要凑齐许多个故障。实验通常把症状重复测约 d 轮,就是让时空块在时间方向上和空间方向一样「厚」。
Measurement errors need no new idea, only a new dimension. Detectors replace “the readout” with “the change in the readout”, turning a measurement error into a pair of endpoints along time, handled by the same matching algorithm as a data error's pair along space. From here on space and time are two equal directions: an error string that fools matching needs many faults whichever way it runs. Experiments usually repeat the syndrome for about d rounds precisely so that the spacetime block is as “thick” in time as it is in space.
对。这是竖直的一对:同一条检查,相邻两轮。横向的一对(相邻两条检查、同一轮)才是数据错误的指纹。
Right. That is the vertical pair: the same check in two consecutive rounds. A horizontal pair (two neighbouring checks, same round) is the data error's fingerprint.
探测器只报「变化」。读反一次,读数变了一次、又变回来一次。
Detectors report change only. One misread means the value changes once and changes back once.
阈值账本:译码器决定数字The threshold ledger: the decoder sets the number
「表面码的阈值是多少?」这个问题没有一个答案,有一本账。10.9%、10.3%、9.9%、2.9%、0.57%——每个数字都对,前提各不相同。这一章先立下记账规则,再把数字各归各位,最后让你在浏览器里亲手换译码器、看曲线搬家。 “What is the surface code's threshold?” has no single answer; it has a ledger. 10.9%, 10.3%, 9.9%, 2.9%, 0.57% — every number is right under its own premises. This chapter first lays down the bookkeeping rules, then files each number where it belongs, and finally lets you swap decoders in your browser and watch the curves move.
6.1一个数字,五个限定项One number, five qualifiers
一个阈值数字离开了它的模型就没有意义。至少要写清五件事:① 数据错误信道——只有 Z 错误?X 与 Z 独立?退极化?② 症状模型——完美测量、现象学(第 5 章)、还是电路级?③ 电路约定——若是电路级,一轮有几步、每步的错误怎么定义?④ 译码器——最大似然、匹配、并查集,以及是否利用了退化与相关性?⑤ 归一化——p 是每个位置、每步、每轮还是每周期的概率?缺任何一项,数字就只能留在文献综述里,不能写进读者面前的正文。
A threshold number is meaningless away from its model. Five things must be stated at minimum: ① the data error channel — Z errors only? independent X and Z? depolarising? ② the syndrome model — perfect, phenomenological (Ch. 5), or circuit-level? ③ the circuit convention — if circuit-level, how many steps per round and how is a step's error defined? ④ the decoder — maximum likelihood, matching, union-find, and whether it exploits degeneracy or correlations? ⑤ the normalisation — is p per location, per step, per round or per cycle? Missing any one, the number belongs in a literature survey, not in text put before a reader.
6.2账本The ledger
| 数字number | 信道 / 症状模型channel / syndrome model | 译码器decoder | 出处source | 白话in words |
|---|---|---|---|---|
| ≈ 10.9% | 独立 X/Z,完美症状independent X/Z, perfect syndrome | 最大似然(类概率)maximum likelihood (class probability) | Dennis–Kitaev–Landahl–Preskill 2002(引用 Honecker–Picco–Pujol 的蒙特卡洛值 10.94%) (quoting Honecker–Picco–Pujol’s Monte Carlo value 10.94%) | 理论上限;把退化的链全数进去the theoretical ceiling; counts every degenerate chain |
| 10.3% | 同上same | 最小重量匹配minimum-weight matching | Wang–Harrington–Preskill 2003 | 只取一条最短链;差的 0.6 个百分点就是熵one shortest chain only; the 0.6 points lost are entropy |
| ≈ 9.9% | 同上(环面码)same (toric code) | 并查集,加权生长版(每次只长边界最小的奇数簇)union-find, weighted-growth version (always grows the odd cluster with the smallest boundary) | Delfosse–Nickerson 2017,第 5 节Delfosse–Nickerson 2017, §5 | 再让出一点精度,换几乎线性的速度;所有奇数簇一起长的均匀版是 9.2%;同一篇在现象学噪声下报告 2.6%(均匀版 2.4%,匹配 2.9%)a little more accuracy traded for almost-linear speed; the uniform version, growing all odd clusters together, gives 9.2%; the same paper reports 2.6% under phenomenological noise (uniform version 2.4%, matching 2.9%) |
| ≈ 2.9% | 现象学,p = qphenomenological, p = q | 时空匹配spacetime matching | Wang–Harrington–Preskill 2003 | 测量也会错:多一维,数字掉三倍多measurements fail too: one more dimension, the number falls by more than three |
| 0.57% (每步per step) | 电路级,八步一轮circuit-level, eight steps per round | 匹配matching | Fowler–Mariantoni–Martinis–Cleland 2012 | 硬件真正对照的数字;折算约 4% 每轮the number hardware compares against; about 4% per round |
| Λ = 2.14 ± 0.02 | 真实芯片(Willow)real device (Willow) | 离线神经网络译码器(同一数据改用把多个匹配译码器的结果组合起来的方法得 Λ = 2.04;实时匹配译码器在 d = 3 → 5 上得 Λ = 2.0 ± 0.1)offline neural-network decoder (on the same data, an ensemble combining several matching decoders gives Λ = 2.04; the real-time matching decoder, d = 3 → 5: Λ = 2.0 ± 0.1) | Google Quantum AI 2024 | 不是阈值:d 加 2 时逻辑错误率缩小的倍数;d = 7 每轮 0.143%(X、Z 两种基平均)not a threshold: the shrink factor per d → d+2; d = 7 at 0.143% per round (averaged over the X and Z bases) |
读这本账的方法:同一行内比较才有意义,跨行比较必先换算。10.9% 与 10.3% 的差是译码器(3.2 节);10.3% 与 2.9% 的差是症状模型(第 5 章);2.9% 与 0.57% 的差是把「一轮」拆成了八个可以出错的步骤,还要注意后者的 p 是每步的概率。《Surface Code · 高中数学版》引用的「约 10.3%」与「电路级 0.5%–1%」,就是这本账里的第二行和第五行。
How to read the ledger: comparisons within a row are meaningful; across rows they need conversion first. 10.9% versus 10.3% is the decoder (§3.2); 10.3% versus 2.9% is the syndrome model (Ch. 5); 2.9% versus 0.57% comes from splitting “one round” into eight fault-prone steps — and note the latter's p is per step. The “about 10.3%” and “circuit-level 0.5%–1%” quoted in “The Surface Code · High-School Edition” are rows two and five of this ledger.
6.3亲手换译码器Swap the decoder yourself
下面的实验台对 d = 3、5、7 的表面码,用三种译码器各跑同一组「加噪 → 译码 → 判定」实验:贪心(3.1)、最小重量匹配(第 2 章,≤ 16 个警报时精确)、并查集(第 4 章)。三族曲线形状相同,交叉点不同——这就是「译码器决定数字」的实物。它们都在本页的「完美测量、只有 Z 错误」模型下,所以只能与账本第一到第三行比,而且只能粗看。p 只取 2%、4%……16% 八个点,间隔 2 个百分点;读数报的是 d = 3 与 d = 7 两条曲线第一次换位(d = 7 的失败率开始高于 d = 3)的那一格区间,外加一个在这一格里线性插值得到的估计。这个区间是观测到的,不是误差棒:每点只抽 300 或 1000 次,失败率本身就带着统计误差(在失败率 15% 至 30% 一带,300 次时约 ±4 到 ±5 个百分点,1000 次时约 ±2 到 ±3 个百分点,95% 置信),足以让换位的格子前后挪一格,读数会把这两点上的误差一并列出;d = 3 与 d = 7 这样小的尺寸,交叉点本身还会随尺寸漂移(有限尺寸效应),文献里的阈值是用更大的 d 外推出来的;最后,d = 7 在高错误率下警报常常超过 16 个,「最小重量匹配」这时退回贪心,会把它的交叉点往下拉。
The bench below runs the same noise → decode → verdict experiment on d = 3, 5, 7 surface codes with three decoders: greedy (§3.1), minimum-weight matching (Ch. 2, exact up to 16 alarms), and union-find (Ch. 4). Three families of curves, same shape, different crossings — “the decoder sets the number” made tangible. All three live in this page's “perfect measurement, Z errors only” model, so they compare only with rows one to three of the ledger, and only roughly. p takes just eight values, 2%, 4%, …, 16%, spaced 2 percentage points apart; the readout reports the grid interval in which the d = 3 and d = 7 curves first swap order (d = 7 starts failing more often than d = 3), plus an estimate by linear interpolation within that interval. The interval is what was observed, not an error bar: each point draws only 300 or 1000 samples, so each failure rate carries its own sampling error (for failure rates around 15% to 30%, about ±4 to ±5 percentage points at 300 samples and ±2 to ±3 at 1000, at 95% confidence), enough to move the swap by a grid cell, and the readout lists that error at the two points; at sizes as small as d = 3 and d = 7 the crossing itself also drifts with size (a finite-size effect), and the literature thresholds are extrapolated from much larger d; finally, at high error rates d = 7 often has more than 16 alarms, where “minimum-weight matching” falls back to greedy and drags its crossing down.
6.4Λ 不是 pth/pΛ is not pth/p
《Surface Code · 高中数学版》6.2 节的压制律 PL ≈ A(p/pth)⌈d/2⌉ 暗示:d 每加 2,逻辑错误率就除以 pth/p。实验上直接测量这个倍数,记作 Λ = PL(d)/PL(d+2)。Willow 芯片用离线神经网络译码器测得 Λ ≈ 2.14(换成实时译码器是 2.0 ± 0.1):d 从 3 到 5、5 到 7,逻辑错误率各缩小约一半。同一份数据换个译码器,Λ 就变——这本身就说明 Λ 是整台机器加上它的译码器拟合出来的数,包含了非均匀的噪声、相关错误、译码器的精度与实时性;它不等于任何一行账本上的 pth 除以芯片的 p。把 Λ = 2.14 反推成「pth/p = 2.14」,是这本账最常见的误读。
The suppression law of “The Surface Code · High-School Edition”, §6.2 PL ≈ A(p/pth)⌈d/2⌉ suggests that each +2 in d divides the logical error rate by pth/p. Experiments measure that factor directly and call it Λ = PL(d)/PL(d+2). The Willow chip measured Λ ≈ 2.14 with an offline neural-network decoder (2.0 ± 0.1 with its real-time decoder): from d = 3 to 5 and 5 to 7, the logical error rate roughly halved each time. The same data give a different Λ under a different decoder — which by itself shows that Λ is a fit to the whole machine together with its decoder — heterogeneous noise, correlated errors, the decoder's accuracy and its real-time constraints; it equals no ledger row's pth divided by the chip's p. Reading Λ = 2.14 back as “pth/p = 2.14” is this ledger's most common misreading.
阈值是「码 + 噪声模型 + 译码器 + 归一化」这一整套的属性,不是码单独的属性。换译码器,数字就动;换症状模型,数字动得更多。所以引用一个阈值时,带上它的五个限定项;比较两个阈值时,先确认它们在同一行。
A threshold is a property of the whole package — code + noise model + decoder + normalisation — not of the code alone. Change the decoder and the number moves; change the syndrome model and it moves more. So quote a threshold with its five qualifiers, and before comparing two, make sure they sit in the same row.
对。门错误率是电路级模型里的量。与 10.3% 比会乐观三十倍以上;与 2.9% 比也混淆了「每步」与「每轮」。即便对照 0.57%,还要确认双方对「一步」和「错误」的定义一致。
Right. A gate error rate lives in the circuit-level model. Comparing with 10.3% would be over thirty times too optimistic; comparing with 2.9% confuses “per step” with “per round”. Even against 0.57%, one must check that both sides define “a step” and “an error” the same way.
问自己:0.3% 是每个什么的概率?门是电路里的一步。
Ask: 0.3% is the probability per what? A gate is one step in a circuit.
从游戏到机器,与三条继续走的路From game to machine, and three roads onward
复盘整条推理链:译码是在两个类之间二选一(第 1 章)→ 对数把「最可能」变成「最短」,问题化为症状图上的最小重量完美匹配,配法数是双阶乘,而 Edmonds 的开花算法多项式时间可解(第 2 章)→ 贪心输给 3-2-3 陷阱,匹配输给 C(a+b, a) 条退化的链,这就是 10.9% 与 10.3% 之差(第 3 章)→ 并查集译码器用奇偶与合并换取几乎线性的速度(第 4 章)→ 探测器让测量错误变成时间方向的一对端点,同一个匹配问题多一维(第 5 章)→ 一本五项限定的账把所有阈值数字各归各位(第 6 章)。你现在读一篇译码器论文的摘要,应该能立刻找到它站在账本的哪一行。
Replaying the chain: decoding is a binary choice between two classes (Ch. 1) → logarithms turn “most probable” into “shortest”, the problem becomes a minimum-weight perfect matching on the syndrome graph, pairings number a double factorial, and Edmonds' blossom algorithm solves it in polynomial time (Ch. 2) → greed loses to the 3-2-3 trap and matching to C(a+b, a) degenerate chains, which is the gap between 10.9% and 10.3% (Ch. 3) → the union-find decoder trades parity and merging for almost-linear speed (Ch. 4) → detectors turn measurement errors into endpoint pairs along time, the same matching one dimension up (Ch. 5) → a five-qualifier ledger files every threshold number (Ch. 6). Reading a decoder paper's abstract now, you should be able to locate its ledger row at once.
三条继续走的路。其一,相关性:一个 Y 错误(同时是 X 错误和 Z 错误)同时触发 X 与 Z 两族检查,分开译码会丢掉这份线索。belief-matching 先用「置信传播」(让每个警报和它相邻的比特来回交换「这里出错的可能性有多大」的估计,几轮之后得到每个比特的出错概率)算出这些关联,再据此调整匹配的权重;Higgott 等(arXiv 2022)报告,在他们的电路级噪声模型下它的阈值约 0.94%,同一模型下普通最小重量匹配约 0.82%。其二,实时性:把匹配或并查集做进 FPGA(可以现场改写电路的芯片)与专用芯片,让译码稳定地跟上症状的节拍——Google 2024 年的实验已在 d = 5 上做到实时译码,平均延迟 63 微秒。其三,新码。qLDPC 码(量子低密度奇偶校验码)的定义有两半:每条检查只碰少数几个比特,每个比特也只被少数几条检查碰到,而且这两个数都不随码变大而增长。按这个定义,表面码本身就是 qLDPC 码(每条检查最多碰 4 个比特,每个比特最多在 4 条检查里)。人们说「新的 qLDPC 码」时,指的通常是表面码以外、检查不再局限于平面近邻的码,例如《BB 码》里的双变量自行车码:那里每个数据比特在 3 条 X 型检查里,一个 Z 错误就点亮 3 个警报。这样的码的症状图不再是「每个错误恰好点亮两个警报」的匹配结构,需要新工具,例如置信传播加有序统计译码(BP-OSD:置信传播给不出一致答案时,按出错概率从大到小挑出最可疑的一组比特,直接解一个线性方程组)。入口文献见下。
Three roads onward. One, correlations: a Y error (an X and a Z error at once) triggers both the X and the Z check families, and decoding them separately throws that clue away. Belief-matching first runs “belief propagation” (alarms and their neighbouring qubits repeatedly exchange estimates of “how likely is an error here”, yielding after a few rounds an error probability for each qubit) to capture such correlations, then reweights the matching accordingly; Higgott et al. (arXiv 2022) report a threshold of about 0.94% for it under their circuit-level noise model, against about 0.82% for standard minimum-weight matching in the same model. Two, real time: matching or union-find cast into FPGAs (chips whose circuitry can be rewired in the field) and dedicated chips, so that decoding reliably keeps pace with the syndrome — Google’s 2024 experiment already decoded in real time at d = 5 with an average latency of 63 µs. Three, new codes. A qLDPC code (quantum low-density parity-check code) is defined by two halves: every check touches only a few qubits, every qubit is touched by only a few checks, and neither number grows as the code gets larger. By this definition the surface code is itself a qLDPC code (each check touches at most 4 qubits, each qubit sits in at most 4 checks). When people speak of “new qLDPC codes” they usually mean codes beyond the surface code whose checks are no longer confined to planar neighbours, such as the bivariate bicycle codes of the BB tutorial: there every data qubit sits in 3 X-type checks, so a single Z error lights 3 alarms. The syndrome graphs of such codes lose the “every error lights exactly two alarms” matching structure and need new tools such as belief propagation with ordered-statistics decoding (BP-OSD: when belief propagation gives no consistent answer, pick the most suspicious set of qubits in order of error probability and solve a linear system for them directly). Entry points below.
接着读:《格点手术 · 高中数学版》→ 再往后:《BB 码 · 高中数学版》→ 《qLDPC 码 · 高中数学版》→ 前置教程(高中数学版):《从高考数学到 Toric Code》→ 《Surface Code · 高中数学版》→
Read next: “Lattice Surgery · High-School Edition” → Then: “BB Codes · High-School Edition” → “qLDPC Codes · High-School Edition” → Prerequisite tutorials (high-school edition): “From High-School Math to the Toric Code” → “The Surface Code · High-School Edition” →
符号与读法Symbols & how to read them
| 符号Symbol | 名称与读法Name & how to read it | 在本教程中的含义Meaning in this tutorial |
|---|---|---|
| ∂ | 弯体 d,读「偏」(partial)A curly d, read “partial” | 「取边界」:∂链 = 链的端点集 = 症状。“Take the boundary”: ∂chain = the chain's endpoint set = the syndrome. |
| ⊕ | 圆圈加,读「异或」A circled plus, read “X-OR” | 合并两组比特、成对相消;错误 ⊕ 修复 = 残留。Merge two sets of qubits with pairwise cancellation; error ⊕ repair = the residual. |
| Σ ∑ | 大写希腊字母,读「西格玛」Capital Greek letter, read “SIG-ma” | 求和:一类的概率 = 对类里每条链求和。Summation: a class's probability = a sum over its chains. |
| ℓ | 花体小写 L,读「ell」A script lowercase L, read “ell” | 一条链的长度(出错的比特数)。A chain's length (number of errored qubits). |
| ln | 读「自然对数」Read “natural log” | ln x = 「e 的多少次方等于 x」;把概率的乘法变成长度的加法。w₀ = ln((1−p)/p)。ln x = “e to what power gives x”; turns multiplying probabilities into adding lengths. w₀ = ln((1−p)/p). |
| e | 自然常数,读「e」Euler's number, read “e” | e ≈ 2.718;e−w₀ℓ 是链的相对概率。e ≈ 2.718; e−w₀ℓ is a chain's relative probability. |
| ∝ | 读「正比于」Read “proportional to” | 差一个对所有候选相同的常数,比较时可以扔掉。Equal up to a constant shared by every candidate, hence droppable when comparing. |
| !! | 双阶乘Double factorial | (2m−1)!! = (2m−1)(2m−3)⋯3·1 = 2m 个警报的完美配对数。(2m−1)!! = (2m−1)(2m−3)⋯3·1 = the number of perfect pairings of 2m alarms. |
| C(n, k) | 读「n 选 k」Read “n choose k” | 组合数;C(a+b, a) 是两警报间最短链的条数。Binomial coefficient; C(a+b, a) counts the shortest chains between two alarms. |
| ⌈ ⌉ | 读「向上取整」Read “ceiling” | ⌈d/2⌉ = d 的一半,不足则进一。⌈d/2⌉ = half of d, rounded up. |
| Λ | 大写希腊字母,读「拉姆达」Capital Greek letter, read “LAM-da” | 压制因子 PL(d)/PL(d+2);Willow 实测 ≈ 2.14。Suppression factor PL(d)/PL(d+2); Willow measured ≈ 2.14. |
| ∈ | 读「属于」Read “belongs to” | C ∈ 类:链 C 是这一类的成员。C ∈ class: chain C is a member of the class. |
| w₀ wS wT | 读「w 零」「w S」「w T」Read “w-nought”, “w-S”, “w-T” | 边权重 w₀ = ln((1−p)/p);时空图上横向每步 wS = w₀,纵向每步 wT = ln((1−q)/q)。Edge weight w₀ = ln((1−p)/p); on the spacetime graph wS = w₀ per horizontal step and wT = ln((1−q)/q) per vertical step. |
| T(m) | 读「T m」,电话号码数Read “T of m”, the telephone numbers | m 个警报允许配到边界时的配法数:T(m) = T(m−1) + (m−1)T(m−2)。Pairings of m alarms when the boundary is allowed: T(m) = T(m−1) + (m−1)T(m−2). |
| α(n) | 小写希腊字母,读「阿尔法」;反阿克曼函数Lowercase Greek letter, read “AL-fa”; the inverse Ackermann function | 并查集 n 次操作共约 n·α(n) 步;实际的 n 下 α(n) ≤ 4(Delfosse–Nickerson 按他们的定义写作 ≤ 3),所以「几乎线性」。n union-find operations take about n·α(n) steps; α(n) ≤ 4 for any practical n (Delfosse–Nickerson, with their definition, write ≤ 3), hence “almost linear”. |
| D(i,t) | 读「D i t」,探测器Read “D of i, t”, the detector | D(i,t) = s(i,t) ⊕ s(i,t−1):第 i 条检查在第 t 轮与上一轮读数的异或,只在变化时为 1。D(i,t) = s(i,t) ⊕ s(i,t−1): XOR of check i's readouts in rounds t and t−1; 1 only on change. |
| Z̄ X̄ | 字母上加横线,读「Z 杠」「X 杠」Letter with a bar, read “Z-bar”, “X-bar” | 逻辑算符:横跨贴片的 Z 串 / X 串;译码失败时,残留是它乘上一些检查(含奇数条横跨的串)。Logical operators: a Z / X string spanning the patch; a failed decode leaves it times some checks (an odd number of spanning strings). |
| ⇒ ⇔ | 读「推出」「当且仅当」Read “implies”, “if and only if” | 单向 / 双向的逻辑推导。One-way / two-way logical implication. |
| ≈ ≤ ≥ | 读「约等于」「小于等于」「大于等于」Read “approximately”, “at most”, “at least” | 近似相等;不超过;不少于。Nearly equal; no more than; no less than. |
| yv δ zB | 读「对偶变量」「步长」「花的对偶」Read “dual variable”, “step”, “blossom dual” | 开花算法的记账量:yv 是点 v 的对偶变量(菱形半径;回放里它含着所有包住 v 的花的厚度);两端不在同一朵花里的边,紧当且仅当 w = yu + yv,两端在同一朵花里的边,紧当且仅当 w = yu + yv − ΣB∋u,v zB(对所有同时包住 u、v 的花 B 求和);δ 是一次生长的步长;zB ≥ 0 是花 B 的对偶,等于整朵花一起长的厚度的两倍,内花归零即展开;下界 = Σy − ΣB(|B|−1)zB/2(2.3 节回放)。The blossom algorithm's bookkeeping: yv is node v's dual variable (diamond radius; in the player it includes the thickness of every blossom containing v); an edge whose ends are not in a common blossom is tight iff w = yu + yv, an edge with both ends in a common blossom iff w = yu + yv − ΣB∋u,v zB (summed over every blossom B containing both u and v); δ is one growth increment; zB ≥ 0 is blossom B's dual, twice the thickness the blossom has grown as a whole, and an inner blossom is expanded when it reaches zero; lower bound = Σy − ΣB(|B|−1)zB/2 (§2.3 player). |
本教程新增词汇New terms in this tutorial
| 术语Term | 定义Definition |
|---|---|
| 最大似然译码maximum-likelihood decoding | 给定症状,选总概率最大的类(两条链之差由面检查拼成,就算同一类);一切译码器的上限。Given the syndrome, pick the class of largest total probability (two chains are in one class when their difference is built from face checks); the ceiling for all decoders. |
| 权重 w₀weight w₀ | ln((1−p)/p);一条链的对数概率 = −w₀ × 长度。ln((1−p)/p); a chain's log-probability = −w₀ × length. |
| 症状图 / 完美匹配 / MWPMsyndrome graph / perfect matching / MWPM | 警报为点、距离为边的图;每个警报恰属一对的配法;总重量最小的那一种。Alarms as vertices, distances as edges; a pairing covering every alarm once; the one of least total weight. |
| 开花算法blossom algorithm | Edmonds 1965:多项式时间求最小重量完美匹配,奇圈缩成一点。Edmonds 1965: minimum-weight perfect matching in polynomial time, odd cycles shrunk to a point. |
| 码容量模型code-capacity model | 只有数据比特独立地以概率 p 出错、测量完美的噪声模型;第 1 至 4 章与 6.3 节的实验台都用它。Noise model in which only data qubits fail, independently with probability p, and measurement is perfect; used in Chapters 1 to 4 and the bench of §6.3. |
| 增广路augmenting path | 两端都是未配点、边交替「不在 / 在」匹配里的路;对调后配对数加一。A path between two unmatched nodes whose edges alternate out of / in the matching; swapping them adds one pair. |
| 对偶变量 / 松弛 / 紧边dual variable / slack / tight edge | 每个点的菱形半径 y;两菱形间的空隙 w − yu − yv(两端在同一朵花里时,再加上所有同时包住两端的花的 zB 之和 ΣB∋u,v zB);空隙为 0 的边。没有花时,所有 y 之和是任何配法重量的下界;有花时下界是 Σy − ΣB(|B|−1)zB/2。Each node’s diamond radius y; the gap w − yu − yv between two diamonds (plus ΣB∋u,v zB, the sum over every blossom containing both ends, when they share a blossom); an edge with zero gap. Without blossoms the sum of all y bounds every pairing’s weight from below; with blossoms the bound is Σy − ΣB(|B|−1)zB/2. |
| 外点 / 内点 / 自由点 / 花(基点、入口)outer / inner / free node / blossom (base, entry) | 树里与根隔偶数 / 奇数条边的点(外点长、内点缩);已配上、不在树里的点;缩成一个点的奇数圈;花的基点是唯一不在花内配对的成员,入口是内花挂进树时树边连进来的成员。Nodes an even / odd number of edges below a tree root (outer grow, inner shrink); a matched node in no tree; an odd cycle shrunk to one node, whose base is the one member not paired inside it and whose entry is the member the tree edge arrives at when it hangs in a tree as inner. |
| 边界节点boundary node | 为每个警报添加的虚拟点,权重 = 到最近毛边界的步数,边界节点之间权重 0。A virtual node added per alarm, weight = steps to the nearest rough boundary; boundary nodes are joined to each other at weight 0. |
| 贪心配对greedy pairing | 反复配最近的两个警报;3-2-3 陷阱使其非最优。Repeatedly pair the closest two alarms; the 3-2-3 trap makes it suboptimal. |
| 路径退化path degeneracy | 同一对端点间 C(a+b, a) 条等长最短链;最大似然计入全部,匹配只计一条。C(a+b, a) equally short chains between one pair of endpoints; maximum likelihood counts all, matching one. |
| 并查集译码器 / 剥皮union-find decoder / peeling | 奇数簇生长合并至偶数或触边;沿生成树从叶子读出修复。簇 = 连成一片的检查与边;生成树 = 连起簇内所有检查、不含圈的一组边;叶子 = 只连一条树边的非根点。Odd clusters grow and merge until even or boundary-touching; a spanning tree is peeled from its leaves to read off the repair. Cluster = a connected set of checks and edges; spanning tree = edges linking all the cluster’s checks with no cycle; leaf = a non-root node on only one tree edge. |
| 探测器detector | 同一检查相邻两轮读数的异或;只在变化时亮。XOR of one check's readouts in consecutive rounds; lit only on change. |
| 现象学噪声 / 电路级噪声phenomenological / circuit-level noise | 每轮数据错 p、读数错 q 的中间模型 / 电路中每个门与读出都是独立出错位置的完整模型。The middle model with data error p and readout error q per round / the full model where every gate and readout is an independent fault location. |
| 压制因子 Λsuppression factor Λ | PL(d)/PL(d+2) 的实测值;整机加译码器的拟合,不等于 pth/p。The measured PL(d)/PL(d+2); a fit to device plus decoder, not pth/p. |
延伸阅读Further reading
- E. Dennis, A. Kitaev, A. Landahl, J. Preskill, “Topological quantum memory” (2002)
译码即统计物理:随机键 Ising 模型、最大似然阈值 ≈ 10.9%、时空配对的源头。arXiv: quant-ph/0110143Decoding as statistical physics: the random-bond Ising model, the ≈ 10.9% maximum-likelihood threshold, the origin of spacetime matching. arXiv: quant-ph/0110143 - C. Wang, J. Harrington, J. Preskill, “Confinement-Higgs transition in a disordered gauge theory and the accuracy threshold for quantum memory” (2003)
匹配译码的 10.3% 与现象学噪声的 2.9%——账本第二、四行。arXiv: quant-ph/0207088Matching's 10.3% and the phenomenological 2.9% — ledger rows two and four. arXiv: quant-ph/0207088 - J. Edmonds, “Paths, trees, and flowers”, Canadian Journal of Mathematics 17, 449–467 (1965)
开花算法的原始论文:不带权重的最大匹配,多项式时间。The original blossom paper: maximum (unweighted) matching in polynomial time. - J. Edmonds, “Maximum matching and a polyhedron with 0, 1-vertices”, Journal of Research of the National Bureau of Standards 69B, 125–130 (1965)
带权重的版本:对偶变量与最小重量完美匹配,即 2.3 节回放实现的算法。The weighted version: dual variables and minimum-weight perfect matching, the algorithm the §2.3 player implements. - A. G. Fowler, “Minimum weight perfect matching of fault-tolerant topological quantum error correction in average O(1) parallel time” (2013)
把匹配做成局域、可并行的实时算法。arXiv: 1307.1740Matching made local and parallel for real time. arXiv: 1307.1740 - N. Delfosse, N. H. Nickerson, “Almost-linear time decoding algorithm for topological codes” (2017)
并查集译码器:生长、合并、剥皮,几乎线性时间。arXiv: 1709.06218The union-find decoder: grow, merge, peel, in almost-linear time. arXiv: 1709.06218 - O. Higgott, “PyMatching: A Python package for decoding quantum codes with minimum-weight perfect matching” (2021); O. Higgott, C. Gidney, “Sparse Blossom: correcting a million errors per core second with minimum-weight matching” (2023)
今天实际使用的匹配译码器及其速度。arXiv: 2105.13082;2303.15933The matching decoders in actual use today, and their speed. arXiv: 2105.13082; 2303.15933 - Google Quantum AI, “Quantum error correction below the surface code threshold”, Nature (2024)
Λ = 2.14、d = 7、实时译码——账本最后一行的原始报告。arXiv: 2408.13687Λ = 2.14, d = 7, real-time decoding — the primary report behind the ledger's last row. arXiv: 2408.13687
全篇简化五项,一次结清:① 「最轻配法」用 2m 状态的精确枚举,只到 16 个警报,超过退回贪心;② 并查集译码器整条边地生长,原文按半条边并规定生长顺序;③ 时空译码的实验台用一维重复码(二维时空图)演示,表面码的对应物是三维,算法相同;④ 所有蒙特卡洛只加 Z 错误、只看星检查,X 一侧完全对称;⑤ 账本里的数字是各文献在各自模型下的报告值,本页实验台的交叉点因贴片小、轮数少而偏低。以上不影响任何定性结论。
Five simplifications, settled in one bill: ① the “lightest pairing” uses exact enumeration over 2m states up to 16 alarms, then falls back to greedy; ② the union-find decoder grows whole edges, whereas the paper grows half-edges in a prescribed order; ③ the spacetime bench demonstrates on a 1D repetition code (a 2D spacetime graph), the surface-code analogue being 3D with the same algorithm; ④ every Monte-Carlo adds Z errors only and watches star checks, the X side being fully symmetric; ⑤ the ledger's numbers are the literature's values under their own models, and this page's crossings sit low because patches are small and rounds few. None of this touches any qualitative conclusion.