第0章ガイダンスとQiskit環境構築
この章の目標
- ステップ2の全体像と、ステップ1の公理との対応を掴む
- Qiskit環境を構築し、ベル状態の回路を動かして手計算と一致することを確認する
- ステップ1の必須事項が手に馴染んでいるかセルフチェックする
0.1 ステップ2で何が変わるのか
ステップ1では状態ベクトルと行列を直接書いて計算しました。実際の量子プログラミングでは同じことを回路図という言語で書きます。対応は1対1です:
| ステップ1の言葉 | ステップ2の言葉 |
|---|---|
| 状態ベクトル $|\psi\rangle \in \mathbb{C}^{2^n}$ | $n$ 本のワイヤ(量子ビット)の「現在の中身」 |
| ユニタリ行列を掛ける | ワイヤにゲートを置く |
| 行列の積(右から左) | ゲートの列(左から右) |
| ボルン則で確率を計算 | 測定ゲートを置いてヒストグラムを見る |
| テンソル積 $A \otimes I$ | 「そのワイヤだけにゲートを置く」 |
新しい概念で本当に増えるのは、ブロッホ球(1量子ビットの状態と操作を球面で見る地図、第1章)と、設計上の制約たち(no-cloning・測定の破壊性が回路に課すルール、第4〜6章)です。あとは語彙(ゲートの品揃え)が増えるだけです。
0.2 Qiskit環境構築
Python 3.9以降があれば5分で終わります。仮想環境を作ってインストール:
python3 -m venv qc-env
source qc-env/bin/activate # Windowsは qc-env\Scripts\activate
pip install qiskit qiskit-aer matplotlib
動作確認として、ステップ1の演習5-6で手計算したベル状態の回路をそのまま動かします。bell.py として保存して実行してください:
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit_aer import AerSimulator
# ベル状態の回路: |00> -> (H⊗I) -> CNOT
qc = QuantumCircuit(2)
qc.h(0) # 0番の量子ビットに H
qc.cx(0, 1) # 制御0番, 標的1番の CNOT
print(qc.draw())
# 測定前の状態ベクトルを確認(シミュレータならでは)
sv = Statevector.from_instruction(qc)
print(sv) # [0.707, 0, 0, 0.707] のはず
# 測定して1000回実行
qc.measure_all()
result = AerSimulator().run(qc, shots=1000).result()
print(result.get_counts()) # {'00': ~500, '11': ~500} のはず
出力の状態ベクトルが $\frac{1}{\sqrt2}(|00\rangle + |11\rangle)$ の成分 $(0.707, 0, 0, 0.707)$ に、測定結果が「00と11がほぼ半々、01と10はゼロ」になっていれば成功です。ステップ1で紙の上で導いたものが、いま画面に出ています。
Qiskitは測定結果やベクトル成分を「量子ビット番号の大きい方を左」に書きます(リトルエンディアン)。q0=1, q1=0 の結果は '01' と表示されます。この教材(と多くの教科書)は「1番目の量子ビットを左」に書くので、2量子ビット以上でQiskitの出力を読むときは左右反転してください。ベル状態のように対称な例では気づけないので、非対称な回路(例: $X \otimes I$)で一度混乱を経験しておくと免疫がつきます(演習0-3)。
QuantumCircuit にゲートを積む、(2) Statevector.from_instruction() で測定前の振幅を覗く(手計算の答え合わせ)、(3) measure_all() + AerSimulator でヒストグラムを見る(ボルン則の答え合わせ)。この3つを使い回すだけで、このステップは完走できます。
演習0
【ステップ1復習】何も見ずに書けるか:(a) $X$, $Z$, $H$ の行列、(b) $H|0\rangle$ と $H|1\rangle$、(c) ボルン則、(d) $|00\rangle$ からベル状態を作る手順。詰まったらステップ1の該当章を復習してから進むこと。
解答を見る
(a)(b) ステップ1第3章、(c) 第4章、(d) 第5章演習5-6。この4つはステップ2の全章で前提として使います。特に (d) がスラスラ出ないうちは先へ進まないでください——第3章以降の計算が全部これの変奏です。
上の bell.py の qc.h(0) を qc.h(1) に変えると、状態ベクトルと測定結果はどうなるか。先に手計算で予想してから実行して確かめよ。
解答を見る
$H \otimes I$ が $I \otimes H$ に変わり、CNOT の制御は0番のまま。$(I \otimes H)|00\rangle = |0\rangle|+\rangle = \frac{|00\rangle + |01\rangle}{\sqrt2}$。CNOTの制御(q0)は $|0\rangle$ のままなので何も起きず、最終状態は $\frac{|00\rangle + |01\rangle}{\sqrt2}$。エンタングルしていない積状態で、測定結果は 00 と 01(Qiskit表示では '00' と '10'!)が半々。「Hをどこに置くか」と「CNOTの制御がどちらか」の組み合わせで結果が別物になる——回路は1文字違いで意味が変わります。
【ビット順の免疫をつける】2量子ビット回路で q0 にだけ $X$ を掛けて測定すると、Qiskitの出力はどうなるか予想せよ:qc = QuantumCircuit(2); qc.x(0); qc.measure_all()。実行して確かめよ。
解答を見る
状態は「1番目(q0)が1、2番目(q1)が0」。教科書表記なら $|10\rangle$ ですが、Qiskitの出力は {'01': 1000}。q1 q0 の順で左から表示されるからです。ここで一度「あれ?」と思っておけば、今後同じ混乱をしたときに「ビット順だな」とすぐ気づけます。
Statevector.from_instruction(qc) は測定前の振幅(複素数)をそのまま表示できる。実機の量子コンピュータで同じことは可能か? ステップ1の公理に照らして答えよ。
解答を見る
不可能です。実機から情報を得る手段は測定だけで(公理3)、1回の測定は1つの結果を返して状態を壊します。振幅の推定には同じ回路の大量の反復実行と統計が必要で、位相情報を得るにはさらに測定基底の工夫が要ります。Statevector は「シミュレータが内部で持っている配列を覗いている」だけの、学習用の神の視点です。この視点は答え合わせには最高ですが、「実機ではこれが見えない」という感覚を常に並走させてください。アルゴリズム設計(ステップ3)とは、まさに「見えない振幅をどう操って、見える測定結果に答えを出させるか」の技術です。