量子回路シミュレータ — ゲートを並べて振幅を流す

量子計算のプログラムは量子回路という図で書かれます。この章では2量子ビットの回路を自分で組み、状態ベクトル(4つの複素振幅)が左から右へ変化していく様子を観察します。最後に「なぜ古典コンピュータでのシミュレーションは破綻するのか」まで踏み込みます。

1. 回路図の読み方 — 左から右へ流れる時間

量子回路は「量子ビット版の楽譜」です。読み方のルールは3つだけ。

前章までに登場したゲートを復習しておくと、H(重ね合わせを作る)、X(ビット反転)、Z(|1⟩ の符号を反転)、S(|1⟩ に90°の位相)、CNOT(制御が |1⟩ のときだけ標的を反転)でした。

POINT — 回路図は「行列の掛け算の予約表」 回路を図として読むときは左→右ですが、数式で書くと状態には右から順に掛かります:3ステップの回路なら |ψ出⟩ = U3U2U1|ψ入⟩。図と数式で順序が逆に見えるのは量子計算の定番のつまずきポイントです。

2. 回路を組んで動かす — ミニ回路ビルダー

下のビルダーで実際に回路を組んでみましょう。パレットでゲートを選び、グリッドのセルをクリックすると配置できます(同じゲートをもう一度クリックすると削除)。「⚡ 実行」を押すと状態が左から右へ流れ、下段の4本のバーが各瞬間の振幅を示します。バーの高さが振幅の大きさ |c|、色が位相角です。

ミニ回路ビルダー — 2量子ビット × 6ステップ
上段=回路(クリックで編集)、下段=状態ベクトル。|00⟩〜|11⟩ の表記は「左が q0、右が q1」。CNOT はクリックした行が制御●、もう一方が標的⊕になります。測定ゲートを置くと、そこを通過した瞬間に結果(0/1)が確定し、状態が収縮します — 「ベル+測定」を何度も実行して 00 と 11 だけが出ることを確かめてください。
POINT — プリセットで見どころチェック ベル状態:H と CNOT の2手で |00⟩ と |11⟩ に振幅が半分ずつ(もつれ)。SWAP:CNOT 3連発で2つの量子ビットの中身が入れ替わる(先頭の X は入れ替わりが見えるようにするための仕込み)。H·Z·H:真ん中の Z を消して実行と比べると、同じ H×2 でも出力が |00⟩ ⇄ |10⟩ で反転する — 位相が結果を変える瞬間です。

3. 振幅は複素数 — 複素平面で「回る」を見る

2量子ビットの状態は、4つの複素数の組で完全に記述されます。

|ψ⟩ = c00|00⟩ + c01|01⟩ + c10|10⟩ + c11|11⟩,    |c00|² + |c01|² + |c10|² + |c11|² = 1 それぞれの c が複素平面上の矢印。長さの2乗=その結果が測定される確率

下のデモは上のビルダーと連動しています。4本の矢印が4つの振幅です。S ゲートを置けば矢印が90°、Z なら180°回ります。振幅の「長さ」は確率に、「向き(位相)」は干渉のしかたに効きます。H·Z·H プリセットを実行して、矢印が足し合わされて消える(干渉で打ち消される)瞬間を観察してください。

振幅の複素平面表示 — 上の回路と連動
実線の円=|c|=1、破線の円=1/√2。矢印が破線の円上にあれば、その状態の測定確率は 50%。上のビルダーで回路を編集したり実行したりすると、ここの矢印がリアルタイムに動きます。

4. 測定統計 — 確率は「何度も走らせて」初めて見える

量子回路を1回実行して測定しても、得られるのは「00」のようなたった1つの結果です。振幅そのものは読み出せません。確率分布 P(x) = |cx|² を確かめるには、同じ回路を何百・何千回も実行(ショット)してヒストグラムを取ります。実機の量子コンピュータの結果が常に「counts」で返ってくるのはこのためです。

P(x) = |cx|² x ∈ {00, 01, 10, 11}。ショット数を増やすほど実測は理論値に近づく(大数の法則)
測定統計 — 上の回路を何度も実行する
色付きバー=実測の割合、白い破線=理論確率。ショット数 50 と 5000 で理論値からのブレを比べてみてください。ばらつきは約 1/√n で縮みます。回路を編集すると自動で再集計されます。
注意 — 測定は状態を壊す 測定した瞬間、重ね合わせは1つの結果に収縮し、元の振幅の情報は失われます。「1回実行して途中の状態ベクトルを覗く」ことは実機では原理的に不可能。このページのように振幅を直接見られるのは、シミュレータの特権です。

5. 状態ベクトルシミュレーションのしくみ

このページの裏側では、教科書どおりの状態ベクトルシミュレーションが動いています。仕組みは驚くほど単純です。

実際にこのページで動いているコードの核心部はこれだけです。

function apply1(st, q, m) {          // 1量子ビットゲート
  const out = st.slice();
  const pairs = q === 0 ? [[0,2],[1,3]] : [[0,1],[2,3]];
  for (const [i0, i1] of pairs) {    // ペアごとに 2×2 行列 × ベクトル
    out[i0] = add(mul(m[0][0], st[i0]), mul(m[0][1], st[i1]));
    out[i1] = add(mul(m[1][0], st[i0]), mul(m[1][1], st[i1]));
  }
  return out;
}

6. なぜ古典シミュレーションは n で破綻するのか

単純で美しいアルゴリズムですが、致命的な弱点があります。配列の長さが 2n — 量子ビットを1個増やすたびに、必要なメモリと計算量が2倍になるのです。

メモリ = 2n × 16 バイト 複素数1個 = 倍精度実数2個 = 16バイトとして
量子ビット数 n振幅の個数 2n必要メモリ目安
101,02416 KB一瞬
20約100万16 MBノートPCで余裕
30約10億17 GBノートPCの限界付近
40約1兆17.6 TB大型サーバでも苦しい
50約101518 PB世界最大級のスパコン級
100約1.3×1030—地球上の全ストレージでも不可能

一方、量子コンピュータ自身は n 量子ビットをただ「持っている」だけでこの状態空間を扱えます。ここが量子計算の潜在的な優位性の源泉です。

一歩先へ — 2ⁿ の壁と「量子超越」の攻防 2019年の Google の量子超越実験は53量子ビット。ただし古典側も黙っておらず、回路に構造があればテンソルネットワークなどの手法で 2n を全部持たずに計算できる場合があります。「どの回路が本当に古典で真似できないか」は今も研究の最前線です。なお次章で見るとおり、2n の重ね合わせを作れること自体は速さの理由になりません — 鍵は干渉です。

7. まとめ