第3章: 量子ゲートと量子回路

ユニタリ行列から動く回路へ

📖 Reading Time: 20-25 minutes 📊 Difficulty: Beginner 💻 Code Examples: 0 📝 Exercises: 0

ビデオ講義

このビデオは以下のテキストと同じ内容をカバーしています。お好みの学習形式をお選びください。

🌐 JP | 🇬🇧 EN | Last sync: 2026-08-16

量子コンピューティング道場 > 量子コンピュータ入門 > 第3章

第2章では、量子ビットとは何か、そして重ね合わせと量子もつれによって \(n\) 量子ビットのレジスタが \(2^n\) 個の複素振幅を同時に保持できることを学びました。しかし状態だけでは何も計算できません。本章では、量子状態を意図的に 変化させる 方法を学びます。量子ビットに作用するゲート、ゲートの列を記述する回路図、そして自分のノートPCで実行できる小さなシミュレータです。ここでの数学は複素数を伴う線形代数であり、私たちの主張はすべて数値的に確認できます。実際、本章の最後でそれを行います。

3.1 ユニタリ行列としてのゲート

\(n\) 量子ビットの量子状態は、長さ1の \(2^n\) 個の複素振幅からなるベクトル \(|\psi\rangle\) です。

\[ \sum_{x} |\alpha_x|^2 = 1 \]

適用するどんな操作も、この長さを1に保たなければなりません。振幅の2乗が確率であり、確率の総和は1でなければならないからです。複素ベクトル空間で長さを保つ行列は、まさに ユニタリ行列、すなわち

\[ U^\dagger U = U U^\dagger = I \]

を満たす行列 \(U\) です。ここで \(U^\dagger\) は 共役転置(行列を転置し、各要素の複素共役をとったもの)です。量子ゲート とは、単に状態ベクトルに作用させるユニタリ行列のことです。

\[ |\psi'\rangle = U |\psi\rangle \]

ここから3つの帰結が直ちに導かれ、いずれも身に付けておく価値があります。

量子ゲートは可逆である。 すべてのユニタリ行列は逆行列 \(U^\dagger\) を持ちます。2つの入力ビットを1つの出力ビットに写して情報を破壊する古典的なANDゲートに、量子的な対応物はありません。量子アルゴリズムが不可逆に見える古典関数を必要とする場合、その関数はまず可逆な形に書き換えなければなりません。

量子ゲートは線形である。 \(U|0\rangle = |a\rangle\) かつ \(U|1\rangle = |b\rangle\) ならば、\(U(\alpha|0\rangle + \beta|1\rangle) = \alpha|a\rangle + \beta|b\rangle\) です。これこそが、ゲートが \(2^n\) 個の基底状態の重ね合わせに「一度に」作用する仕組みのすべてであり、同時に、その事実だけでは高速化が得られない理由でもあります。測定は1つの結果しか返さないからです。

一部の量子ビットに作用するゲートも、レジスタ全体に作用している。 \(n\) 量子ビットのレジスタの量子ビット \(k\) に適用される1量子ビットゲート \(G\) は、他のすべての量子ビットに単位行列を置いた クロネッカー積(テンソル積)で作られる \(2^n \times 2^n\) 行列です。

\[ I \otimes \cdots \otimes G \otimes \cdots \otimes I \]

3.6節では、まさにこの行列をコードで構成します。

3.2 1量子ビットゲート

📚 PauliゲートX、Y、Z

3つの Pauli行列 は、最も基本的な1量子ビットゲートです。

\[ X = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}, \quad Y = \begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix}, \quad Z = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix} \]

\(X\) ゲート は量子版のNOTゲートです。2つの基底状態を入れ替えます。

\[ X|0\rangle = |1\rangle, \qquad X|1\rangle = |0\rangle \]

\(Z\) ゲート は位相反転です。\(|0\rangle\) をそのままにし、\(|1\rangle\) に \(-1\) を掛けます。

\[ Z|0\rangle = |0\rangle, \qquad Z|1\rangle = -|1\rangle \]

\(Z\) は、確実に \(|0\rangle\) または確実に \(|1\rangle\) である量子ビットに対しては観測可能な効果を何も与えないことに注意してください。測定確率 \(|\alpha|^2\) は変わりません。その効果は、2つの分岐の相対的な符号が意味を持つ重ね合わせの中でのみ見えるようになります。この 相対位相(物理的に意味を持つ)と 大域位相(状態全体に \(e^{i\theta}\) を掛けるもので、物理的に検出できない)の区別は、本シリーズを通じて重要になります。

3つのPauli行列はいずれも2乗すると単位行列になります: \(X^2 = Y^2 = Z^2 = I\)。\(X\) を2回適用すれば元の状態に戻ります。

📚 Hadamardゲート

Hadamardゲート \(H\) は、重ね合わせを生み出すゲートです。

\[ H = \frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix} \]

基底状態に作用させると次のようになります。

\[ H|0\rangle = \frac{|0\rangle + |1\rangle}{\sqrt{2}} \equiv |+\rangle, \qquad H|1\rangle = \frac{|0\rangle - |1\rangle}{\sqrt{2}} \equiv |-\rangle \]

\(|+\rangle\) も \(|-\rangle\) も、計算基底で測定すれば結果0と1を確率1/2ずつ与えます。両者は相対的な符号だけが異なり、その符号こそが両者を区別可能にしています。\(H^2 = I\) なので、\(H\) をもう一度適用すると1回目が打ち消されます。したがって \(H|+\rangle = |0\rangle\)、\(H|-\rangle = |1\rangle\) となり、元の状態が厳密に復元されます。振幅が打ち消し合ったり強め合ったりする 干渉 がその仕組みであり、第4章のあらゆる量子アルゴリズムが利用する資源です。

有用な恒等式を2つ挙げます。いずれも3.6節で数値的に検証します。

\[ HXH = Z, \qquad HZH = X \]

ゲートをHadamardで挟むと、ビット反転が位相反転に、またその逆に変換されます。

📚 位相ゲートと回転ゲート

Sゲート と Tゲート は、\(|1\rangle\) により細かい位相シフトを与えます。

\[ S = \begin{pmatrix} 1 & 0 \\ 0 & i \end{pmatrix}, \qquad T = \begin{pmatrix} 1 & 0 \\ 0 & e^{i\pi/4} \end{pmatrix} \]

ここで \(T^2 = S\)、\(S^2 = Z\) です。

連続的な制御には、Pauli行列の指数関数として定義される 回転ゲート を使います。

\[ R_x(\theta) = e^{-i\theta X/2}, \qquad R_y(\theta) = e^{-i\theta Y/2}, \qquad R_z(\theta) = e^{-i\theta Z/2} \]

各Pauli行列は2乗すると単位行列になるので、これらの指数関数には閉じた形が存在します。たとえば

\[ R_y(\theta) = \begin{pmatrix} \cos(\theta/2) & -\sin(\theta/2) \\ \sin(\theta/2) & \cos(\theta/2) \end{pmatrix} \]

であり、\(R_y(\theta)|0\rangle = \cos(\theta/2)|0\rangle + \sin(\theta/2)|1\rangle\) となります。「回転」という名前は第2章のBloch球の描像から来ています。\(R_x, R_y, R_z\) はBlochベクトルをそれぞれ \(x\)、\(y\)、\(z\) 軸のまわりに角度 \(\theta\) だけ回転させます。因子2に注意してください。Blochベクトルの \(2\pi\) 回転は \(\theta = 2\pi\) に対応し、その点で \(R_y(2\pi) = -I\) となりますが、これは大域位相です。

回転ゲートが実用上重要なのは、実際のハードウェアがネイティブに実装しているのがまさにこれだからです。所定の継続時間と位相を持つマイクロ波またはレーザーのパルスが、連続的に調整可能な角度の回転を生み出します。また、第5章で扱う変分アルゴリズムで角度が最適化されるのも、このゲートです。

3.3 2量子ビットゲートと万能性

📚 CNOTゲート

1量子ビットゲートだけでは、量子もつれを決して生み出せません。各量子ビットに個別に作用するので、積状態は積状態のままです。少なくとも1つ、2つの量子ビットを結合するゲートが必要です。標準的な選択が CNOT(制御NOT)ゲートです。

CNOTは 制御 量子ビットと 標的 量子ビットを持ちます。制御が \(|1\rangle\) のときに限り、標的に \(X\) を適用します。

\[ |00\rangle \to |00\rangle, \quad |01\rangle \to |01\rangle, \quad |10\rangle \to |11\rangle, \quad |11\rangle \to |10\rangle \]

順序付けられた基底 \(\{|00\rangle, |01\rangle, |10\rangle, |11\rangle\}\) で、第1量子ビットを制御とすると次のようになります。

\[ \text{CNOT} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \end{pmatrix} \]

これは置換行列であり、最後の2つの基底状態を入れ替えているだけです。置換行列はユニタリなので、CNOTは正当な量子ゲートです。基底状態に対しては古典的な可逆XORとまったく同じように振る舞います: \(|a, b\rangle \to |a, a \oplus b\rangle\)。重ね合わせに対しては、次節で見るとおり古典的な対応物のない働きをします。

規約について一言注意しておきます。\(|q_0 q_1\rangle\) において量子ビット0が最上位ビットなのか最下位ビットなのかは、教科書やソフトウェアパッケージによって異なります。上の行列は、量子ビット0が左端の最上位ビットであることを前提としています。これを取り違えることは、シミュレーション結果が混乱する最もよくある原因の1つなので、以下で行うようにコード中で規約を明示しておく価値があります。

📚 万能ゲート集合

有限個のゲートの集合が 万能(universal)であるとは、任意個数の量子ビットに対する任意のユニタリを、その集合のゲートだけで組んだ回路によって任意の精度で近似できることをいいます。これは古典論理におけるNANDの万能性の量子版です。

証明なしに、標準的な事実を2つ述べます。

2つ目の事実の方が注目に値します。離散的な ゲートの集合で十分だということ、つまり無限の精度を持つアナログ制御が不要だということを意味するからです。さらにSolovay–Kitaevの定理により、必要なゲート数は \(1/\epsilon\) の多重対数程度にしか増えないことが保証されており、近似は効率的です。

万能性は何が 可能か についての主張であって、何が 安価か についての主張ではありません。一般の \(n\) 量子ビットユニタリには \(n\) について指数的な個数のゲートが必要であり、有用な操作に対して短い回路を見つけることこそが、量子アルゴリズム設計の大部分を占めています。

3.4 回路モデル

量子回路 図は、量子プログラムの標準的な記法です。その要素はごくわずかです。

Bell状態を生成する回路をテキスト形式で書くと次のようになります。

q0: |0> ──[ H ]───■────  measure
                  │
q1: |0> ──────────⊕────  measure

読み方は次のとおりです。両方の量子ビットを \(|0\rangle\) から始め、量子ビット0に \(H\) を適用し、量子ビット0を制御として量子ビット1にCNOTを適用し、両方を測定する。行列の積が要求する反転した順序で書くと、対応する行列表現は

\[ |\psi\rangle = \text{CNOT} \cdot (H \otimes I) \cdot |00\rangle \]

です。回路深さ とは、順に適用しなければならないゲートの層の数です。互いに素な量子ビットに作用するゲートは同じ層に置けます。実機では量子ビットが時間とともにデコヒーレンスを起こすため、深さは非常に重要であり、同じゲート数なら浅い回路の方が通常は優れた回路です。この制約には第5章で立ち返ります。

3.5 実例: Bell状態を作る

Bell状態の回路を、手計算で一歩ずつ実行してみましょう。目標は量子もつれ状態

\[ |\Phi^+\rangle = \frac{|00\rangle + |11\rangle}{\sqrt{2}} \]

です。

ステップ0 — 初期状態。 両方の量子ビットが \(|0\rangle\) から始まるので、レジスタは

\[ |\psi_0\rangle = |00\rangle = \begin{pmatrix} 1 \\ 0 \\ 0 \\ 0 \end{pmatrix} \]

です。

ステップ1 — 量子ビット0へのHadamard。 レジスタ全体に作用するゲートは \(H \otimes I\) です。\(H|0\rangle = (|0\rangle + |1\rangle)/\sqrt{2}\) であり、量子ビット1は手つかずなので、

\[ |\psi_1\rangle = (H \otimes I)|00\rangle = \left(\frac{|0\rangle + |1\rangle}{\sqrt{2}}\right) \otimes |0\rangle = \frac{|00\rangle + |10\rangle}{\sqrt{2}} \]

となります。ベクトルとしては \(|\psi_1\rangle = (1/\sqrt{2}, 0, 1/\sqrt{2}, 0)^T\) です。この時点では2つの量子ビットはまだ もつれていません。状態は \(|+\rangle \otimes |0\rangle\) と因数分解できます。

ステップ2 — 量子ビット0を制御とするCNOT。 線形性を使って項ごとにCNOTを適用します。

\[ \text{CNOT}\frac{|00\rangle + |10\rangle}{\sqrt{2}} = \frac{\text{CNOT}|00\rangle + \text{CNOT}|10\rangle}{\sqrt{2}} = \frac{|00\rangle + |11\rangle}{\sqrt{2}} \]

CNOTは \(|00\rangle\) をそのままにし(制御が0)、\(|10\rangle \to |11\rangle\) と写す(制御が1なので標的が反転する)からです。結果は \(|\Phi^+\rangle\) で、ベクトルは \((1/\sqrt{2}, 0, 0, 1/\sqrt{2})^T\) です。

この状態が量子もつれである理由。 これが積 \((a|0\rangle + b|1\rangle) \otimes (c|0\rangle + d|1\rangle)\) として書けたとしましょう。展開すると \(|00\rangle, |01\rangle, |10\rangle, |11\rangle\) の振幅はそれぞれ \(ac, ad, bc, bd\) になります。\(ad = 0\) かつ \(bc = 0\) が必要なので、\(a = 0\) か \(d = 0\) のいずれか、そして \(b = 0\) か \(c = 0\) のいずれかが成り立ちます。どの選び方でも \(ac\) と \(bd\) の少なくとも一方が0になってしまい、両方が \(1/\sqrt{2}\) でなければならないという要求と矛盾します。積への分解は存在しないので、この状態は量子もつれ状態です。

測定すると何が得られるか。 確率は \(|00\rangle\) について \(|1/\sqrt{2}|^2 = 1/2\)、\(|11\rangle\) について \(1/2\)、残り2つについて0です。各量子ビットは個別には公平なコインに見えます。しかし2枚のコインは常に一致します。量子ビット0を測定して0が出れば、量子ビット1も必ず0です。この完全な相関は、量子ビットをどれだけ遠くに引き離しても保たれ、量子もつれの証拠です。ただし超光速の信号伝達は許しません。局所的な結果はランダムであり、相関は2つの結果を古典通信路で突き合わせて初めて見えるからです。

3.6 Python: 最小限の状態ベクトルシミュレータ

以上はすべて線形代数なので、NumPyだけですべて確認できます。以下のシミュレータは \(2^n\) 個の複素振幅からなる状態ベクトル全体を保持し、ゲートを行列の積として適用します。これは考えうる最も直接的な実装であり、意図的に最速ではありません。そして自分の限界について正直です。メモリは \(2^n\) で増えるので、ノートPCではせいぜい25〜30量子ビット程度が限界です。この指数の壁こそが、実機の量子ハードウェアを求める理由です。

必要環境: Python 3.9以上とNumPyのみ。量子SDKは不要です。

コード例1: ゼロから作るBell状態

"""小規模量子レジスタ向けの最小状態ベクトルシミュレータ(NumPyのみ)。"""

import numpy as np

# --- 1量子ビットゲートの行列(2x2、複素数) ---
I2 = np.eye(2, dtype=complex)
X = np.array([[0, 1],
              [1, 0]], dtype=complex)
Z = np.array([[1, 0],
              [0, -1]], dtype=complex)
H = np.array([[1, 1],
              [1, -1]], dtype=complex) / np.sqrt(2)


def apply_1q(state, gate, target, n_qubits):
    """n量子ビット状態ベクトルの量子ビット `target` に2x2ゲートを適用する。

    量子ビット0は基底ラベルの左端(最上位)ビットなので、
    |q0 q1 ... > はインデックス q0*2^(n-1) + q1*2^(n-2) + ... に対応する。
    """
    op = np.array([[1]], dtype=complex)
    for q in range(n_qubits):
        op = np.kron(op, gate if q == target else I2)
    return op @ state


def cnot_matrix(control, target, n_qubits=2):
    """CNOTゲートの 2^n x 2^n 置換行列を構成する。"""
    dim = 2 ** n_qubits
    M = np.zeros((dim, dim), dtype=complex)
    for i in range(dim):
        bits = [(i >> (n_qubits - 1 - q)) & 1 for q in range(n_qubits)]
        if bits[control] == 1:              # 制御が |1> のとき標的を反転
            bits[target] ^= 1
        j = sum(b << (n_qubits - 1 - q) for q, b in enumerate(bits))
        M[j, i] = 1.0                        # 列 i -> 行 j
    return M


def probabilities(state):
    """すべての計算基底状態の測定確率。"""
    return np.abs(state) ** 2


# --- Bell状態を作る: 量子ビット0にH、続いてCNOT(0 -> 1) ---
n = 2
psi = np.zeros(2 ** n, dtype=complex)
psi[0] = 1.0                                  # |00> から開始
print("start      :", np.round(psi.real, 4))

psi = apply_1q(psi, H, target=0, n_qubits=n)
print("after H    :", np.round(psi.real, 4))

CNOT = cnot_matrix(control=0, target=1, n_qubits=n)
psi = CNOT @ psi
print("after CNOT :", np.round(psi.real, 4))

labels = ["00", "01", "10", "11"]
print("\nprobabilities:")
for label, p in zip(labels, probabilities(psi)):
    print(f"  |{label}> : {p:.4f}")

# --- 健全性チェック ---
print("\nnorm            :", round(float(np.sum(probabilities(psi))), 10))
print("unitary (CNOT)  :", np.allclose(CNOT.conj().T @ CNOT, np.eye(4)))
print("unitary (H)     :", np.allclose(H.conj().T @ H, np.eye(2)))

# --- 測定統計のシミュレーション ---
rng = np.random.default_rng(0)
shots = 10000
outcomes = rng.choice(4, size=shots, p=probabilities(psi).real)
counts = np.bincount(outcomes, minlength=4)
print("\n10000 shots:")
for label, c in zip(labels, counts):
    print(f"  |{label}> : {c}")

検証済みの出力:

start      : [1. 0. 0. 0.]
after H    : [0.7071 0.     0.7071 0.    ]
after CNOT : [0.7071 0.     0.     0.7071]

probabilities:
  |00> : 0.5000
  |01> : 0.0000
  |10> : 0.0000
  |11> : 0.5000

norm            : 1.0
unitary (CNOT)  : True
unitary (H)     : True

10000 shots:
  |00> : 4990
  |01> : 0
  |10> : 0
  |11> : 5010

途中のベクトルは手計算を厳密に再現しています。\((1,0,0,0)\) が \(H\) の後に \((0.7071, 0, 0.7071, 0)\) となり、CNOTの後に \((0.7071, 0, 0, 0.7071)\) となります。10000回のシミュレーション測定は \(|00\rangle\) と \(|11\rangle\) をおよそ5000回ずつ与え、\(|01\rangle\) と \(|10\rangle\) は ちょうど0回 です。完全な相関は近似ではありません。

コード例2: ゲートの恒等式を確認する

"""NumPyによるゲート代数のチェック。"""

import numpy as np

X = np.array([[0, 1], [1, 0]], dtype=complex)
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
Z = np.array([[1, 0], [0, -1]], dtype=complex)
H = np.array([[1, 1], [1, -1]], dtype=complex) / np.sqrt(2)
T = np.array([[1, 0], [0, np.exp(1j * np.pi / 4)]], dtype=complex)


def rot(axis, theta):
    """R_axis(theta) = exp(-i * theta/2 * sigma_axis)"""
    sigma = {"x": X, "y": Y, "z": Z}[axis]
    return np.cos(theta / 2) * np.eye(2) - 1j * np.sin(theta / 2) * sigma


print("H X H == Z ?", np.allclose(H @ X @ H, Z))
print("H Z H == X ?", np.allclose(H @ Z @ H, X))
print("H H   == I ?", np.allclose(H @ H, np.eye(2)))
print("T^2   == S ?", np.allclose(T @ T, np.diag([1, 1j])))
print("Rx(pi) == -iX ?", np.allclose(rot("x", np.pi), -1j * X))

# Ry(theta) を |0> に作用させると cos(theta/2)|0> + sin(theta/2)|1> になる
theta = np.pi / 3
ket0 = np.array([1, 0], dtype=complex)
out = rot("y", theta) @ ket0
print(f"Ry(pi/3)|0> = {out[0].real:.4f}|0> + {out[1].real:.4f}|1>")
print(f"expected      {np.cos(theta/2):.4f}|0> + {np.sin(theta/2):.4f}|1>")

検証済みの出力:

H X H == Z ? True
H Z H == X ? True
H H   == I ? True
T^2   == S ? True
Rx(pi) == -iX ? True
Ry(pi/3)|0> = 0.8660|0> + 0.5000|1>
expected      0.8660|0> + 0.5000|1>

最後の \(R_x(\pi)\) のチェックに注目してください。これは \(X\) ではなく \(-iX\) に等しくなります。回転ゲートはPauliゲートと大域位相 \(-i\) だけ異なるのです。大域位相は観測できないので、レジスタ全体に適用する限り両者は物理的に等価ですが、ゲートがより大きな操作の制御される部分として使われる場合、その位相は大域ではなく相対的になるため、この区別が意味を持ちます。

コード例3: 命令リストとして回路を実行する

同じ補助関数は任意の量子ビット数に拡張できます。ここでは回路をタプルのリストとして記述し、回路図を読むのとまったく同じように左から右へ実行します。

"""コード例1の続き: 命令のリストとして与えた回路を実行する。
コード例1に追記するか、I2, X, Z, H, apply_1q, cnot_matrix を再インポートすること。"""

GATES = {"X": X, "Z": Z, "H": H}


def run_circuit(circuit, n_qubits):
    """circuit: ('H', 0) や ('CNOT', 0, 1) のタプルのリスト。左から右へ適用する。"""
    psi = np.zeros(2 ** n_qubits, dtype=complex)
    psi[0] = 1.0
    for op in circuit:
        if op[0] == "CNOT":
            psi = cnot_matrix(op[1], op[2], n_qubits) @ psi
        else:
            psi = apply_1q(psi, GATES[op[0]], op[1], n_qubits)
    return psi


# GHZ状態: (|000> + |111>)/sqrt(2)
ghz = run_circuit([("H", 0), ("CNOT", 0, 1), ("CNOT", 1, 2)], n_qubits=3)
for i, amp in enumerate(ghz):
    if abs(amp) > 1e-12:
        print(f"|{i:03b}> : {amp.real:+.4f}")
print("norm:", round(float(np.sum(np.abs(ghz) ** 2)), 10))

検証済みの出力:

|000> : +0.7071
|111> : +0.7071
norm: 1.0

CNOTをもう1つ加えると、2量子ビットのBell状態が3量子ビットの GHZ状態 \((|000\rangle + |111\rangle)/\sqrt{2}\) に拡張され、3つの量子ビットすべてが完全に相関します。GHZ状態は実機の標準的なベンチマークです。\(n\) 量子ビットのGHZ状態を高い忠実度で準備することは、ゲート品質とコヒーレンス時間の両方を厳しく試す試験になります。

🎯 演習問題

  1. ユニタリ性: \(H^\dagger H = I\) を手計算で確認し、\(H\) がエルミートかつユニタリであることを確かめてください。
  2. 位相の不可視性: \(Z|+\rangle\) と \(|+\rangle\) の測定確率を計算してください。次に \(HZ|+\rangle\) と \(H|+\rangle\) の確率を計算してください。なぜ2組目でのみ位相が見えるようになるのかを説明してください。
  3. 反転したCNOT: 量子ビット1を制御、量子ビット0を標的とするCNOTの \(4 \times 4\) 行列を書き、コード例1の cnot_matrix 関数と照合してください。
  4. 他のBell状態: コード例1を修正して \((|01\rangle + |10\rangle)/\sqrt{2}\) と \((|00\rangle - |11\rangle)/\sqrt{2}\) を準備してください。ヒント: CNOTの前に \(X\) または \(Z\) を挿入します。
  5. スケーリングの壁: 30、40、50量子ビットの状態ベクトルをcomplex128で保存するのに必要なメモリ量を見積もってください。量子ビット数がいくつになるとノートPCでは足りなくなりますか。

まとめ

本章では、量子計算がゲートの回路としてどのように表現されるかを学びました。量子ゲート は ユニタリ行列 であり、そのためすべてのゲートは可逆で長さを保存し、不可逆な古典論理の直接的な量子版は排除されます。Pauliゲート \(X\)、\(Y\)、\(Z\) はビットと位相を反転させ、Hadamardゲート は干渉に基づくすべてのアルゴリズムが依拠する重ね合わせを生み出し、回転ゲート \(R_x\)、\(R_y\)、\(R_z\) は実機がネイティブに実装する連続調整可能な操作を提供します。CNOTゲート は2つの量子ビットを結合し、そもそも量子もつれを可能にします。1量子ビットゲートだけでは決してもつれを作れないからです。集合 \(\{H, T, \text{CNOT}\}\) は 万能 であり、任意のユニタリをこの3つのゲートから望むだけ精密に近似できます。ただし万能性が保証するのは可能性だけで、効率ではありません。回路モデル では、ワイヤが量子ビットを運び、時間は左から右へ流れ、測定はワイヤを古典ビットに変換して終端します。Bell状態 \((|00\rangle + |11\rangle)/\sqrt{2}\) をHadamard1つとCNOT1つで構成し、代数を項ごとに追い、結果が積状態に分解できないことを証明し、さらにNumPyだけで書いた 状態ベクトルシミュレータ で途中のベクトルをすべて数値的に再現しました。

次章では、これらのゲートを実際に働かせ、この分野を有名にした量子アルゴリズム — Deutsch–Jozsa、Grover、Shor — を学びます。どの高速化が指数的で、どれが2乗にすぎず、どの問題では高速化が全く得られないのかに注意を払いながら進めます。

← 第2章: 量子ビット、重ね合わせ、量子もつれ 第4章: 量子アルゴリズム →

免責事項