手を上げるキュビットくんゆるふわ量子コンピュータ
すまし顔のキュビットくん

表面符号(サーフェスコード)をQiskitで実装|XとZを同時に見張る2次元誤り訂正

2026-09-03実践

#Qiskit#表面符号#誤り訂正#Python#実践

ビットフリップ符号はXエラー専用、位相フリップ符号はZエラー専用、ショア符号はその両方を9量子ビットで同時に訂正しました。この記事で扱う**表面符号(サーフェスコード)**は、データ量子ビットを2次元格子状に並べ、隣接する少数の量子ビットだけを使ってXとZの両方のエラーをその場で検出し続ける、現在の実機で最も採用が進んでいる誤り訂正方式です1。Googleの量子プロセッサ「Willow」が2024年末に示した「格子を大きくするほど論理エラー率が指数関数的に下がる」という結果2は、まさにこの表面符号の実証でした。この記事では表面符号の最小単位をQiskitで組み、Xエラー・Zエラーそれぞれがどう検出されるかを手を動かして確認します。

表面符号の基本アイデア:格子上でXとZを同時に見張る

表面符号は、データ量子ビットを碁盤の目のように並べ、その間に「アンシラ(補助)量子ビット」を配置します。各アンシラは、周囲4個のデータ量子ビットの**パリティ(偶奇)**を測定する役割を持ち、2種類のアンシラが交互に並びます。

表面符号の格子で起きていること

🔲

2次元格子

データ量子ビットを碁盤目に配置

✖️

Xスタビライザー

周囲4個のZエラーを検出

Zスタビライザー

周囲4個のXエラーを検出

🔁

反復測定

毎サイクル全アンシラを測り続ける

ポイントは、1種類のアンシラでは片方のエラーしか見えないことです。だからこそ2種類のスタビライザーを格子状に交互配置して、どこにXエラーが起きてもZスタビライザーの誰かが気づき、どこにZエラーが起きてもXスタビライザーの誰かが気づく、という体制を作ります。

準備

pip install qiskit qiskit-aer

① 最小単位:4データ+1アンシラの「プラケット」

表面符号を丸ごと実装すると量子ビット数が数十〜数百に膨れ上がるので、まずは格子の中の1マス分を取り出します。データ量子ビット q0〜q3 を正方形の四隅に置き、アンシラ q4 でその**Zパリティ(ZZZZ)**を測ります。

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator

def z_stabilizer(error_qubit=None):
    qc = QuantumCircuit(5, 1)   # q0-q3: データ(正方形の四隅), q4: アンシラ
    if error_qubit is not None:
        qc.x(error_qubit)       # データにビットフリップ(X)エラーを注入
    for q in range(4):
        qc.cx(q, 4)             # 各データをアンシラへCNOT → パリティを転写
    qc.measure(4, 0)
    return qc

sim = AerSimulator()
for label, eq in [("エラー無し", None), ("q0にXエラー", 0), ("q2にXエラー", 2)]:
    counts = sim.run(z_stabilizer(eq), shots=1000).result().get_counts()
    print(label, ":", counts)
エラー無し   : {'0': 1000}
q0にXエラー : {'1': 1000}
q2にXエラー : {'1': 1000}

エラーが無ければアンシラは常に 0(偶パリティ)。どのデータ量子ビットにXエラーが1個起きても、アンシラは 1 に反転してパリティの崩れを教えてくれます。これがシンドローム(症状)測定です。

💡

測定してもデータは壊れない

CNOTでパリティだけをアンシラに転写して測定するので、データ量子ビットの重ね合わせ自体は壊れません。「何が起きたか」だけを盗み見て、「量子情報そのもの」は覗かない——これがスタビライザー測定の肝です。

② Xスタビライザー:位相エラーを検出する

同じ4個のデータ量子ビットに対して、今度はXパリティ(XXXX)を測るアンシラを組みます。アンシラを |+⟩ にしてから制御方向を逆にする「アダマールテスト」の形になります。ただしXXXXのパリティが意味を持つのは、データがXXXXの固有状態になっているときだけなので、先にデータ全体を |++++⟩ にそろえておきます(先ほどの例で |0000⟩ がZZZZの固有状態だったのと対になる関係です)。

def x_stabilizer(error_qubit=None):
    qc = QuantumCircuit(5, 1)
    for q in range(4):
        qc.h(q)                   # データを |++++> に(XXXXの固有状態にそろえる)
    qc.h(4)                      # アンシラを |+> に
    if error_qubit is not None:
        qc.z(error_qubit)        # データに位相フリップ(Z)エラーを注入
    for q in range(4):
        qc.cx(4, q)               # アンシラ制御でデータへCNOT
    qc.h(4)                      # 基底を戻してX測定と等価に
    qc.measure(4, 0)
    return qc

for label, eq in [("エラー無し", None), ("q1にZエラー", 1), ("q3にZエラー", 3)]:
    counts = sim.run(x_stabilizer(eq), shots=1000).result().get_counts()
    print(label, ":", counts)
エラー無し   : {'0': 1000}
q1にZエラー : {'1': 1000}
q3にZエラー : {'1': 1000}

先ほどのZスタビライザーはXエラーを検出し、こちらのXスタビライザーはZエラーを検出します。名前と検出対象が逆になっているのが最初は紛らわしいところですが、「スタビライザーと同じ種類のエラーはすり抜け、違う種類のエラーだけがパリティを反転させる」と覚えると整理できます3

⚠️

同じ種類のエラーは見えない

Zスタビライザー(ZZZZ測定)はZエラーを検出できません。ZエラーはZ基底の測定と可換なので、パリティに影響を与えないからです。だからこそ表面符号ではXとZ、2種類のスタビライザーを両方配置する必要があります。

③ 両方を1つの回路で:どちらのエラーかを同時に見分ける

実際の表面符号では、Xスタビライザーの格子とZスタビライザーの格子が互い違いに重なっています。今度はZZZZとXXXXの両方の固有状態でなければいけないので、データを (|0000⟩+|1111⟩)/√2 というもつれ状態(GHZ状態)に用意します。実はこの状態、ZZZZ・XXXX両方の+1固有状態になっている、ちょうどよい"符号状態"です4

def prepare_code_state(qc):
    qc.h(0)
    qc.cx(0, 1)
    qc.cx(0, 2)
    qc.cx(0, 3)          # データを (|0000>+|1111>)/√2 に

def surface_patch(error_gate=None, error_qubit=None):
    qc = QuantumCircuit(6, 2)     # q0-q3: データ, q4: Zスタビライザー用, q5: Xスタビライザー用
    prepare_code_state(qc)
    qc.h(5)

    if error_gate == "x":
        qc.x(error_qubit)
    if error_gate == "z":
        qc.z(error_qubit)

    for q in range(4):
        qc.cx(q, 4)               # Zスタビライザー(ZZZZ)→ Xエラーを検出
    for q in range(4):
        qc.cx(5, q)               # Xスタビライザー(XXXX)→ Zエラーを検出
    qc.h(5)

    qc.measure(4, 0)
    qc.measure(5, 1)
    return qc

for label, gate, eq in [
    ("エラー無し", None, None),
    ("Xエラー(q0)", "x", 0),
    ("Zエラー(q0)", "z", 0),
]:
    counts = sim.run(surface_patch(gate, eq), shots=1000).result().get_counts()
    print(f"{label:12s}:", counts)
エラー無し   : {'00': 1000}
Xエラー(q0) : {'01': 1000}
Zエラー(q0) : {'10': 1000}

2ビットのシンドローム (Zスタビライザー, Xスタビライザー) を見るだけで、「エラー無し」「Xエラー」「Zエラーが起きた」を区別できます。実際のデコーダー(例:Minimum Weight Perfect Matching5)は、格子全体に散らばった大量のシンドロームパターンからエラーの場所を逆算し、訂正をかけます。

なぜ「格子を大きくする」と強くなるのか

ここまでは1マス分の最小単位でしたが、表面符号の本領は**格子を大きく(距離を上げる)**したときに発揮されます。距離 d の表面符号は d 個以上のエラーが同時に起きない限り訂正できるため、d を大きくするほど論理エラー率は指数関数的に下がります。

📉

2.14倍

Googleが実証した、格子(距離)を1段階上げるごとの論理エラー率の改善係数

🔲

101量子ビット

距離7の表面符号に必要な物理量子ビット数(Willowでの実証)

🎯

0.143%

距離7で達成された、誤り訂正1サイクルあたりの論理エラー率

Googleは2024年末、超伝導プロセッサ「Willow」で距離3・5・7の表面符号を実際に動かし、格子を1段階大きくするごとに論理エラー率が約2.14倍ずつ改善する指数関数的抑制を初めて実証しました2。距離7(101量子ビット)では、論理量子ビットの寿命が最良の物理量子ビット単体よりも長くなる「損益分岐点」を超えたことも示されています。これは、しきい値定理(ショア符号の記事で紹介)が理論だけでなく実機でも成り立つことを示した、業界にとって象徴的な結果でした。QuantinuumもMicrosoftと共同で、2026年3月に56量子ビットの実機上で12個の論理量子ビットを実証し、論理エラー率が物理エラー率を下回る「信頼できる量子計算」を達成したと発表しています6

🌱

コストは『物理量子ビットの数』

距離7で101量子ビットが必要だったように、表面符号は原理はシンプルでも大量の物理量子ビットを消費します。1個の高品質な論理量子ビットのために数百〜数千の物理量子ビットが必要というのが、大規模フォールトトレラント量子計算の最大のハードルです。

まとめ

  • 表面符号はデータ量子ビットを2次元格子に並べ、XスタビライザーとZスタビライザーを交互に配置する誤り訂正方式
  • Zスタビライザー(ZZZZ測定)はXエラーを、Xスタビライザー(XXXX測定)はZエラーを検出する
  • 2種類のシンドロームを組み合わせることで、エラーの種類と場所を推定できる
  • 格子(距離)を大きくするほど論理エラー率は指数関数的に下がる — Googleの「Willow」が2.14倍/段階を実証
  • 代償は必要な物理量子ビット数の急増。距離7で101量子ビットが1個の論理量子ビットを守る

もう少し詳しく(背景と理論)

表面符号は、Alexei Kitaevが提唱したトーリック符号(toric code)7を平面(境界のある格子)に持ち込んだもので、Bravyi・Kitaevらによって定式化されました8。最近接の量子ビット同士の相互作用だけで実装でき、理論上のしきい値が約1%と、他の多くの符号より高い(=物理量子ビットの精度がそこまで高くなくても機能する)ことが実用面での強みです9。実際のデコード処理には、シンドロームのパターンを「マッチング問題」として解くMinimum Weight Perfect Matchingや、近年ではニューラルネットワークを使った高速デコーダーも使われています5。表面符号は現在、Google・IBM・Quantinuum・Amazonなど主要プレイヤーの多くが採用または参照する事実上の標準アーキテクチャとなっており、量子ボリューム/ベンチマークの記事で触れた「実機の性能をどう測るか」という議論とも密接に関わっています。

次の一歩 🌸

誤り訂正の全体像は誤り訂正入門、片方のエラーだけを直す基礎はビットフリップ符号位相フリップ符号、両方を同時に直す原点はショア符号へどうぞ。

Footnotes

  1. 表面符号は最近接相互作用のみで実装でき、比較的高いエラーしきい値を持つため、超伝導方式を中心に実機での採用が進んでいる。

  2. Google Quantum AI, "Quantum error correction below the surface code threshold," Nature (2024/2025)。距離3・5・7の表面符号で、距離を2上げるごとに論理エラー率がΛ=2.14±0.02倍改善する指数抑制を実証。距離7(101量子ビット)で1サイクルあたり0.143%±0.003%の論理エラー率を達成し、最良の物理量子ビットの寿命を2.4±0.3倍上回った。 2

  3. スタビライザーはそれと可換な演算子には反応しない。ZZZZ測定はZ型の演算子(Zエラー)とは可換なため素通りし、非可換なX型の演算子(Xエラー)にだけ反応する。XXXX測定はその逆。

  4. (|0000⟩+|1111⟩)/√2 にZZZZを作用させると、各項とも4個のZがすべて偶数個の|1⟩にかかるため符号は変わらず+1固有状態。XXXXを作用させると |0000⟩⇄|1111⟩ が入れ替わるだけで状態全体は変わらないため、これも+1固有状態になる。1つの状態が2種類のスタビライザーに対して同時に固有状態になれるのは、この状態がまさに"符号空間"に属しているため。

  5. シンドローム(検出されたパリティ反転の位置)から、最も『あり得そうな』エラーの組み合わせを推定するアルゴリズム。近年はGoogleのAlphaQubitなどニューラルネットワークベースのデコーダーの研究も進んでいる。 2

  6. Quantinuum, "Quantinuum and Microsoft announce new era in quantum computing with breakthrough demonstration of reliable logical qubits"(2026年3月)。56量子ビットのSystem Model H2上で12個の論理量子ビットを実証し、論理エラー率が物理エラー率を下回ったと発表。

  7. Kitaev, A. Y. (1997/2003). "Fault-tolerant quantum computation by anyons." Annals of Physics, 303, 2–30. トポロジカルな量子誤り訂正符号(トーリック符号)を提案。

  8. Bravyi, S. B. & Kitaev, A. Y. (1998). "Quantum codes on a lattice with boundary." 境界のある平面格子上にトーリック符号を実装する「表面符号」の定式化。

  9. 表面符号のしきい値は数値シミュレーションで概ね0.5〜1%程度と見積もられており、超伝導量子ビットなど現行ハードウェアの物理エラー率(0.1〜1%程度)と近い水準にあるため、現実的な実装対象として広く研究されている。

🔥 この分野の最新トレンドをチェック →

あわせて読みたい