メニュー「量子コンピュータの世界」で公開している数々の記事は、量子計算の操作の理論的基礎をテーマにしたものから、動作するプログラムサンプルを紹介したもの、果ては実機に接続してジョブを送信するものまであります。
しかしながら、「自分でプログラムを作れる実感」を得るためには、複雑なアルゴリズムのコードを一度動かすことよりも、最小単位のコードを何度も組み替え、「なぜ、そう書くのか?」という意図と結果の関係を体に沁み込ませることの方が重要です。
そこで本記事では、プログラムを繰り返し作成できるよう極小サイズのサンプルを用意し、コーディングのステップや詳しい解説を入れて1量子ビットの世界を徹底的に探求します。
目次
第1章:量子プログラムの基本構造
最小構造の量子プログラムを作成し始める前に、一般的な構造を確認しておきましょう。
このシリーズでは、広く使われている量子計算ライブラリQiskitを使用することを想定します。
一般的な量子プログラムの実行は、どのような操作を行う場合でも共通する、以下の3つの主要なフェーズと、それに続く細分化されたステップで構成されます。
- 初期設定フェーズ
- ライブラリのインポート: 必要なQiskitモジュール(回路、シミュレータ、可視化ツールなど)を読み込みます。(注:インポート文はプログラムの先頭に記述されますが、実際の開発時にはコードを書き進める中で、必要になったモジュールを適宜追加していきます。)
- 回路の初期化: 量子ビットの数 (\(N_q\)) と、測定結果を格納するための古典ビットの数 (\(N_c\)) を指定し、量子回路を定義します。
- ゲート操作フェーズ
- ゲート操作の適用(オプション): 意図する量子操作(\(X, H, R_y\)など)のゲートを、特定の量子ビットに適用します。(このステップは、デフォルトの状態を確認する最小コードでは省略されます)
- 測定操作の追加: 量子ビットの状態を古典ビットに変換する測定操作を回路の末尾に追加します(古典ビットに結果を「書き込む」)。
- 実行と結果処理フェーズ
- シミュレータの選択: 回路を実行する環境(高速シミュレータまたは実機)を指定し、インスタンス化します。
- 回路の実行: 設定した試行回数(ショット数)を指定して、コンパイルされた回路をシミュレータに送信し実行します。
- 結果データの取得: 実行結果から、観測された古典ビットの「0」と「1」の出現回数(counts)を取得します。
第2章:最小フレームワークの構築
本章では、量子プログラムを実行し、その結果を取得するための最小限の実行フレームワークをプログラムします。
このフレームワークは、今後の全てのプログラミング演習の土台となります。
それでは早速、最小単位の量子プログラムを開発してみましょう。
ただし、完成されたコードを提示するのではなく、目標達成に必要な最小限の操作仕様を定義し、それに従ってステップごとにコードを記述・修正していく流れをご案内します。
ステップ 1:回路と入出力の定義
まずは、量子計算の土台となる回路の箱を定義します。
ステップ1.1. 仕様の確認
| 要素 | 数量 | 目的 |
|---|---|---|
| 量子ビット | 1 | 最小単位の量子計算を行うため。 |
| 古典ビット | 1 | 測定結果(0または1)を格納するため。 |
ステップ1.2. コーディング(最初の試行)
VS Codeで「test1.py」などの名前でファイルを作成し、上記ステップ1.1.の仕様を満たすコードを書いてみましょう。
回路を定義するには、Qiskitの主要なクラスである QuantumCircuit を使用します。
QuantumCircuitは、2つの引数を受け取ります。
第一引数は量子ビット数、第二引数は古典ビット数です。
qc = QuantumCircuit(1, 1)QuantumCircuit とは、Qiskitで用意されているPythonのクラスです。
量子状態の定義、ゲート操作や測定といったアルゴリズムを実行する場合、必ず必要となります。
ステップ 1.3. 警告と原因分析
ステップ 1.2.で記述したコードをVS Codeで開くと、ターミナルで実行する前に、エディタ上で QuantumCircuit の下に警告を示す波線が表示されます。
波線にマウスオーバーすると、以下のような警告が表示されます。
“QuantumCircuit” is not defined

- 警告の原因: Pythonは、
QuantumCircuitというクラスが、どのライブラリ(モジュール)に定義されているかを知らないためです。VS CodeのPython拡張機能が、この名前を認識できず、未定義である可能性を警告しています。 - 必要な措置:
QuantumCircuitクラスを含むライブラリをインポートする必要があります。
ステップ 1.4. 警告の解決
ステップ 1.3.で表示された警告を解消するためには、QiskitのAPIリファレンスを参照し、QuantumCircuit がどのモジュールに属するかを確認します。
上手く探せましたか?QuantumCircuit は、Qiskitの主要なモジュールである qiskit に含まれています。
よって、以下のようにコードを修正します。
from qiskit import QuantumCircuit # 👈このコードを追加
qc = QuantumCircuit(1, 1)ステップ2:ゲート操作
ステップ 2.1. 操作の定義
ここからは、回路に量子操作(ゲート)を適用するステップに進みます。
操作を定義する前に、まず、量子ビットがデフォルトでどのような状態にあるかを確認する最小限の操作を定義します。
今回は量子ビットに対して何も操作しないため、コードにはコメントのみを追記します。
from qiskit import QuantumCircuit # 👈このコードを追加
qc = QuantumCircuit(1, 1)
# 操作の定義(仕様により、ここでは何も記述しません)ステップ 2.2. 測定の仕様
このステップでは、操作が完了した量子ビットの状態を、古典的な結果として取得するための仕様を定義します。
- 定義する操作: 測定 (
measure) - 仕様: 量子ビット 0 (\(q[0]\)) の状態を、古典ビット 0 (\(c[0]\)) に格納する。
- 目的: 量子回路の操作結果を、古典的な情報として取得し、結果を確認可能にする。
ステップ 2.3.. コーディング(測定操作の定義)
ステップ 2.2. の仕様に従い、量子ビット \(q[0]\) の状態を古典ビット \(c[0]\) に格納するための測定操作を定義します。
Qiskitでは、測定操作を定義するために QuantumCircuitが持つmeasureメソッドを使用します。
QuantumCircuit.measureメソッド- 第一引数:量子ビットのインデックス
- 第二引数:古典ビットのインデックス
- 戻り値:
qiskit.circuit.InstructionSet(今回は使用しない)
from qiskit import QuantumCircuit # 👈このコードを追加
qc = QuantumCircuit(1, 1)
# 操作の定義(仕様により、ここでは何も記述しません)
# 測定操作の定義
qc.measure(0, 0)ステップ3:実行と結果処理
ステップ 3.1. 実行と結果取得・観測のフロー
ここからは、構築した量子回路を実行し、結果を取得・観測するためのステップに入ります。
プログラムの流れは以下の通りです。
- 必要なライブラリのインポート: 実行環境クラスをインポートします。
- ステップ 1.4. で学んだとおり、必要に応じてインポートする必要があります。
- Sampler のインスタンス化: 実行環境のオブジェクトを作成します。ここでは最も基本的な
Samplerを使用します。 - 実行と結果の取得: 構築した回路 (
qc) を Sampler に渡し、測定ショット数 (shots=1024など) を指定して実行します。 - 結果の整形: 取得した
resultから、測定結果の準確率分布 (quasi_dists) を取り出し、counts変数に格納します。 - 結果の出力:
countsをターミナルに出力します。
ステップ 3.2. コーディング(完成コード)
最小フレームワークの最終的な完成コードを記述します。
Qiskitでは、回路を実行し結果を取得するためにプリミティブ(Primitives)と呼ばれる実行環境(Sampler や Estimator、StatevectorSampler など)を使用しますが、本ステップでは Sampler を使用します。
from qiskit import QuantumCircuit
from qiskit.primitives import Sampler # 👈v1.x系の場合:このコードを追加
from qiskit_aer.primitives import Sampler # 👈v2.x系の場合:このコードを追加
qc = QuantumCircuit(1, 1)
# 操作の定義(仕様により、ここでは何も記述しません)
# 測定操作の定義
qc.measure(0, 0)
# -------------------
# 実行環境の定義と実行
# -------------------
sampler = Sampler() # Sampler(実行環境)のインスタンスを作成
job = sampler.run([qc], shots=1024) # 回路(qc)をSamplerで1024回実行し、ジョブとして格納
result = job.result() # ジョブの実行完了を待ち、結果オブジェクトを取得
counts = result.quasi_dists[0] # 結果から測定の準確率分布を取得
print("Counts:", counts)quasi_distsについて
quasiとは、はラテン語に由来する接頭辞で、「準(じゅん)」「〜のような」「ほとんど」「見かけ上」といった意味を持ちます。
そのため、quasi_dists(準確率分布)は、「確率分布のように振る舞うが、厳密には古典的な確率の定義を満たさない可能性がある分布」という意味合いで使われています。
ステップ 3.3. 分析と学習(最小フレームワーク)
ステップ 3.2. で完成させた最小フレームワークを実行すると、以下の結果が表示されるはずです。
Counts: {0: 1.0}この Counts: {0: 1.0} という実行結果の分析を行い、作成したコードから何を学べるかを明確にします。
- 実行結果の分析
実行結果Counts: {0: 1.0}は、以下の事実を示しています。- キーの
0: 観測された量子状態がバイナリの \(0\) であること。 - 値の
1.0: その状態が \(100\%\) の確率(準確率)で観測されたこと。
- キーの
- \(0\) が \(100\%\) になる理由
この結果は、意図的に量子操作(ゲート)を省略しているために発生します。- 初期状態の確認: 量子ビットはデフォルトで \(|0\rangle\) 状態(古典的な \(0\) に相当)で初期化されます。
- 操作の省略: 量子ゲートを一切適用しない場合、状態は \(|0\rangle\) のままです。
- 測定の動作: \(|0\rangle\) 状態を測定すると、当然ながら \(0\) の結果のみが得られます。
ステップ 3.4. SamplerV2対応
qiskit_aerの最新バージョンは、2025年11月現在 v0.17.2 です。
この時点で本ブログが使用しているのは v0.17.1 です。
qiskit_aerの v0.15.0 以降、Sampler (V1) は非推奨となっており、SamplerV2が標準です。
将来性を考え、この項ではステップ3.2の完成コードを、SamplerV2を使用したプログラムに対応させています。
(SamplerV2は、より広範囲且つ汎用的に使えるよう更新されており、記述が若干増えます。)
from qiskit import QuantumCircuit
from qiskit_aer.primitives import SamplerV2 # 👈インポートが変ります
qc = QuantumCircuit(1, 1)
qc.measure(0, 0)
sampler = SamplerV2()
# SamplerV2のrunにはpubsが必要: [(circuit, parameter_values, shots)]
job = sampler.run([(qc, None, 1024)])
result = job.result()
data = result[0].data
# resultのquasi_distsが廃止されているため、以下のようにcountsを取得します
counts = {}
for field_name in data:
field = getattr(data, field_name)
if hasattr(field, "get_counts"):
counts = field.get_counts()
print("Counts:", counts)第3章:アダマールゲートと重ね合わせの探求
第2章で、量子回路の最小フレームワークの構築と実行に成功しました。
ここからは、このフレームワークを「量子計算」として機能させるための操作を組み込みます。
具体的には、量子計算の基礎となる重ね合わせ(Hゲート)、NOT操作(Xゲート)、そして量子もつれ(CNOTゲート)の3つの操作を実装し、その結果が古典計算とどのように異なるのかを実証します。
まず本章では、量子性を示す最も基本的な現象、重ね合わせ (Superposition) をマスターしましょう。
アダマール (H) ゲートを使用して「重ね合わせ」状態を生成し、その結果を分析します。
ステップ 1:重ね合わせの仕様確認
このステップでは、量子計算の最初の一歩である重ね合わせの実現に向けて、具体的な目標と手段を明確にします。
最小フレームワークを量子計算として機能させるために、以下の3つの小ステップを通じて、アダマールゲートの役割を定義します。
ステップ 1.1. 重ね合わせの定義と目標
量子計算の学習において、最初に知っておくべきことは、量子ビットが古典的なビット(\(0\) または \(1\))と異なり、二つの状態を同時に持つことができるという事実です。
これが重ね合わせです。
第2章で確認した通り、量子ビットは初期状態で必ず \(0\) の状態 \(|0\rangle\) に設定されています。
この状態を測定すると、\(100\%\) の確率で \(0\) が得られます。
本章の目標は、この確定した \(|0\rangle\) の状態を、等しい確率で \(|0\rangle\) と \(|1\rangle\) の両方を持つ状態(=重ね合わせ状態)へ移行させることです。
\(\text{目標状態} = \displaystyle\frac{1}{\sqrt{2}}|0\rangle + \displaystyle\frac{1}{\sqrt{2}}|1\rangle\)
この状態を測定すると、\(0\) が約 \(50\%\)、\(1\) が約 \(50\%\) の確率で得られることになります。
ステップ 1.2. アダマール (H) ゲートの役割
前のステップで定義した通り、目標は \(|0\rangle\) の状態から \(50\%\) の \(|0\rangle\) と \(50\%\) の \(|1\rangle\) の重ね合わせ状態を作り出すことです。
この操作を実現するのがアダマール (H) ゲートです。
アダマール (H) ゲートを \(|0\rangle\) 状態の量子ビットに適用すると、以下の変換が行われます。
\(|0\rangle \stackrel{\text{H}}{\rightarrow} \displaystyle\frac{1}{\sqrt{2}}|0\rangle + \displaystyle\frac{1}{\sqrt{2}}|1\rangle\)
これは、本章ステップ 1.1. で設定した「目標状態」そのものであることがわかります。
ステップ 1.3. 期待される結果の予測
アダマール (H) ゲートの操作により、量子ビットの状態は \(|0\rangle\) と \(|1\rangle\) の重ね合わせ状態になっています。
\(\text{目標状態} = \displaystyle\frac{1}{\sqrt{2}}|0\rangle + \displaystyle\frac{1}{\sqrt{2}}|1\rangle\)
量子力学において、特定の状態が測定される確率は、その状態の確率振幅(上記数式の \(|0\rangle\) や \(|1\rangle\) の前についている係数)の絶対値の二乗で計算されます。
- 状態 \(|0\rangle\) の測定確率:
- \(P(0) = \left|\displaystyle\frac{1}{\sqrt{2}}\right|^2 = \displaystyle\frac{1}{2} = 0.5\)
- 状態 \(|1\rangle\) の測定確率:
- \(P(1) = \left|\displaystyle\frac{1}{\sqrt{2}}\right|^2 = \displaystyle\frac{1}{2} = 0.5\)
作成するプログラムでは、回路を 1024 回実行(shots=1024)します。したがって、測定結果は以下の通りになると予測されます。
- \(0\) が観測される回数: \(1024 \times 0.5 \approx 512\) 回
- \(1\) が観測される回数: \(1024 \times 0.5 \approx 512\) 回
よって、実行結果では、この回数が準確率分布として表示され、約 \(50\%\) ずつになることが期待されます。
ステップ 2:アダマール (H) ゲートのコーディング
このステップでは、第2章で構築した最小フレームワークの構成を参考に、Hゲートを組み込んだ新しいコードをゼロから記述し、重ね合わせを実現します。
既存の「test1.py」を書き換えても実装可能ですが、本記事の目的は「繰り返しコードを記述することで理解と記憶を定着させること」であるため、新たなファイル(test2.py)を作成して進めることを推奨します。
ファイル(test2.py)が作成できたら、第2章のプログラムを自力でコーディングしてみましょう。
ステップ 2.1. 新しいコードの仕様確認
最少フレームワーク部分がコーディングできたら、Hゲートによる量子現象を実現するコードを追加していきます。
最小フレームワークからの変更点
基本構造は維持しつつ、以下の処理を操作のセクションに加えます。
qc.h(0): 量子ビット 0 にアダマールゲートを適用し、重ね合わせ状態を生成する。
完成コードの構成
| セクション | 記述内容 |
|---|---|
| 準備 | QuantumCircuit および Sampler のインポート |
| 定義 | 1量子ビット、1古典ビットの回路定義 (QuantumCircuit(1, 1)) |
| 操作 | Hゲートの追加 (qc.h(0)) 👈 今回の主役 |
| 実行 | 測定、Samplerの実行、結果の取得 (qc.measure(0, 0) 以降) |
ステップ 2.2. アダマール (H) ゲートを組み込んだコード
上記の仕様に基づき作成したプログラムの全文は以下のとおりです。
from qiskit import QuantumCircuit
from qiskit_aer.primitives import Sampler
# 回路と入出力の定義
# (Hゲートは1量子ビット操作なので、回路は1Qubit、1Cbitで十分)
qc = QuantumCircuit(1, 1)
# 量子操作の定義(Hゲートの追加)
qc.h(0) # 量子ビット0を重ね合わせ状態にする
# 測定と実行の定義
qc.measure(0, 0) # 量子ビット0の結果を古典ビット0に格納
sampler = Sampler()
job = sampler.run([qc], shots=1024)
result = job.result()
counts = result.quasi_dists[0]
print("Counts:", counts) # 測定結果の度数を表示ステップ 3:重ね合わせの結果分析
ステップ 3.1. 実行結果の確認
ステップ 2.2. で作成した、Hゲートを組み込んだコードを実行すると、次のような結果が得られます。(結果は確率的であるため、値は若干変動します。)
Counts: {1: 0.5078125, 0: 0.4921875}ステップ 3.2. 結果の分析
この結果は、ステップ 1.3. で予測した通り、\(0\) と \(1\) の結果が約 \(50\%\) ずつ得られたことを示しており、「重ね合わせ」が成功したことの証明となります。
- もし量子操作を行わなければ、結果は \(\{0: 1.0\}\) となります(第2章の結果がそうでしたね)。
- Hゲートを適用したことにより、量子ビットは\(|0\rangle\) と \(|1\rangle\) の両方の性質を同時に持つ「重ね合わせ」状態となり、測定によって確率的にどちらかの結果に収束しました。
第4章:Xゲート(量子NOT操作)の探求
第3章で、アダマール(H)ゲートによる重ね合わせ状態の生成に成功し、量子性の基礎を掴みました。
本章では、古典計算における最も基礎的な操作であるNOT(反転)を、量子ビット上で行うXゲート(量子NOT操作)を探求します。
量子ビットの初期状態を意図的に反転させ、その結果を分析します。
今回からは、「仕様」と「ヒント」のみを提示します。
第2章と第3章で習得した知識を応用し、自力でのコーディングに挑戦してみてください。
ステップ 1:Xゲートの仕様とヒント
ステップ 1.1. Xゲートの仕様確認
仕様は、量子ビットの初期状態である \(|0\rangle\) の状態を、確定的な \(|1\rangle\) の状態へ移行させることです。
\(\text{初期状態} = |0\rangle\)
\(\text{目標状態} = |1\rangle\)
この状態を測定すると、\(100\%\) の確率で \(1\) が得られることになります。
Xゲートとは、量子ビットの \(|0\rangle\) と \(|1\rangle\) の状態を反転させるゲートです。
Xゲートを \(|0\rangle\) 状態に適用すると、目標状態 \(|1\rangle\) が得られます。
\(\label{eq:2}|0\rangle \stackrel{\text{X}}{\rightarrow} |1\rangle\)
ステップ 1.2. コーディングのためのヒント
以下のヒントと、第2章と第3章で作成したコードを参考にして、目標状態 \(|1\rangle\) を出力する新しいプログラムを作成してみてください。
- 回路の定義:
- 1量子ビット、1古典ビットで十分です。
- 量子操作の追加:
qc.の後に、Xゲートに対応するメソッドを記述します。
- 測定結果の予測:
- 実行結果の準確率分布は、\(\{1: 1.0\}\) に極めて近くなるはずです。
ステップ 2:Xゲートのコーディング
答え合わせをしたい方は、以下のコードを確認してください。
from qiskit import QuantumCircuit
from qiskit_aer.primitives import Sampler
qc = QuantumCircuit(1, 1)
qc.x(0) # 👈量子ビット0にXゲートを適用(NOT操作)
qc.measure(0, 0)
sampler = Sampler()
job = sampler.run([qc], shots=1024)
result = job.result()
counts = result.quasi_dists[0]
print("Counts:", counts)ステップ 3:結果分析
ステップ 3.1. 実行結果の確認
ステップ 2 で作成したプログラムを実行した結果は、以下のようになります。
Counts: {1: 1.0}ステップ 3.2. 結果の分析
- NOT操作の証明
- この結果は、ステップ 1.1. で設定した目標(\(100\%\) の \(|1\rangle\) の状態)を完全に達成しています。
- Xゲートを適用する前の初期状態は \(|0\rangle\) でしたが、Xゲートによって状態が反転し、確定的に \(|1\rangle\) が得られました。これは、古典計算におけるNOT操作と全く同じ機能です。
- 重ね合わせとの違い
- 第3章のアダマールゲートでは、結果は \(50/50\) の確率分布を示しました。しかし、今回のXゲートでは、結果は \(100\%\) の確率で \(1\) に収束し、確率的な振る舞いは見られません。これは、Xゲートが確定的な操作であり、重ね合わせ状態を生成しないためです。
第5章:CNOTゲート(量子もつれ)の探求
第4章までで、量子ビットの重ね合わせとNOT操作という基本的な単一量子ビット操作をマスターしました。
本章では、量子コンピュータが古典コンピュータに対して優位性を持つ量子もつれ(エンタングルメント)を探求します。
もつれを生成するために必須のCNOTゲート(二量子ビットゲート)を使用し、2量子ビット回路の構築に挑戦します。
ステップ 1:CNOTゲートの仕様とヒント
このステップでは、量子もつれを生成するためのCNOTゲート(Controlled-NOT)を探求します。
2量子ビット回路を初めて扱うため、具体的な仕様に加えて、コード構築のための重要なヒントを提供します。
ステップ 1.1. CNOTゲートの仕様確認
- 目標の設定:
本章の目標は、量子もつれ(Entanglement)を生成することです。具体的には、量子計算で最も有名なもつれ状態であるベル状態 \(\Phi^+\) を生成します。- \(\text{目標状態} = \frac{1}{\sqrt{2}}(|00\rangle + |11\rangle)\)
- この状態は、量子ビット0と量子ビット1が完全に相関していることを意味します。
- CNOTゲートの役割:
- CNOTゲートは、2つの量子ビット(制御ビットとターゲットビット)を使用します。
- 制御ビットが \(|1\rangle\) のときのみ、ターゲットビットにNOT操作(Xゲート)を適用します。
- CNOTゲート単体ではもつれは生成されません。HゲートとCNOTゲートを組み合わせることで、目標のベル状態が生成されます。
ステップ 1.2. コーディングのためのヒント
以下のヒントを元に、目標状態 \(\Phi^+\)(ベル状態)を出力する新しいプログラムを作成してみてください。
- 回路の定義:
- 2つの量子ビットと、2つの古典ビットが必要になります。
qc = QuantumCircuit(2, 2)の形式に変更しましょう。
- 2つの量子ビットと、2つの古典ビットが必要になります。
- 量子もつれの生成:
- 量子ビット0にHゲートを適用し重ね合わせを生成します。\(\rightarrow\)
qc.h(0) - CNOTゲートを適用します。制御ビットを0に、ターゲットビットを1にします。
- 量子ビット0にHゲートを適用し重ね合わせを生成します。\(\rightarrow\)
- CNOTの記述:
qc.の後に、CNOTゲートに対応するメソッドを記述します。- 形式は
qc.cx(制御ビット, ターゲットビット)です。
- 測定 (qc.measure) の記述:
- 測定対象:
measureメソッドは、リスト形式で複数の量子ビットを指定できます。今回は量子ビット 0 と 1 の両方を測定します。 - 結果の格納先:古典ビットも同様にリスト形式で指定します。量子ビット 0 の結果を古典ビット 0 に、量子ビット 1 の結果を古典ビット 1 に対応させて格納します。
- 記述:したがって、測定の行は
qc.measure([0, 1], [0, 1])の形式となります。リスト内の順番が、量子ビットと古典ビットの対応関係を決定します。
- 測定対象:
- 測定結果の予測:
- 結果は \(\{00: 0.5, 11: 0.5\}\) となり、\(\{01, 10\}\) は観測されないはずです。
ステップ 2:CNOTゲートのコーディング
答え合わせをしたい方は、以下のコードを確認してください。
from qiskit import QuantumCircuit
from qiskit_aer.primitives import Sampler
# 回路と入出力の定義 (2Qubit, 2Cbit)
qc = QuantumCircuit(2, 2)
# 量子操作の定義(ベル状態の生成)
qc.h(0) # Qubit 0 を重ね合わせ状態にする
qc.cx(0, 1) # Qubit 0 を制御、Qubit 1 をターゲットにCNOT適用
# 測定と実行の定義
qc.measure([0, 1], [0, 1]) # Qubit 0, 1 の結果をCbit 0, 1 に格納
sampler = Sampler()
job = sampler.run([qc], shots=1024)
result = job.result()
counts = result.quasi_dists[0]
print("Counts:", counts) ステップ 3:結果分析と考察
ステップ 3.1. 実行結果の確認
ステップ 2 で作成したプログラムを実行した結果は、以下のようになります。
(結果は確率的であるため、値は若干変動します。)
Counts: {3: 0.494140625, 0: 0.505859375}ステップ 3.2. 結果の分析
- 量子もつれ(Entanglement)の証明:
- この結果は、「00」または「11」がそれぞれ約 \(50\%\) の確率で得られ、「01」や「10」といった組み合わせが全く観測されないことを示しています。
- もし量子ビット0と量子ビット1が独立していたなら、全ての組み合わせ(00, 01, 10, 11)がランダムに出現する可能性があります。
- しかし、CNOT操作によって量子もつれが生成された結果、量子ビット0が測定で0になれば、量子ビット1も必ず0になるという強い相関関係が生まれました。これがベル状態の特性であり、量子もつれが成功したことの証明です。
【参考】結果が厳密な \(50\% / 50\%\) にならない理由(準確率とノイズ)
前提として、「量子もつれ」とは、二つの量子ビットが距離に関係なく、切っても切れない強い相関を持つ状態のことであり、片方を測定すると、瞬時にもう片方の状態が決まります。
しかしながら、今回の結果は『「00」または「11」がそれぞれ約 \(50\%\) の確率』で出現しており、厳密な \(50\%\) ではありませんでした。
『これは、「量子もつれ」の要件を満たしていないのではないか?』と感じられた読者もいらっしゃるかもしれません。
このように、結果に僅かな誤差が生じる理由は「統計的な揺らぎ (Statistics)」です。
qiskit.primitives.Sampler や qiskit_aer.primitives.Sampler などのシミュレーターは、理論上はノイズのない理想的な環境をシミュレートしますが、計算の過程は確率的なプロセスです。
サイコロを振るのと同じで、有限の試行回数(shots)で実行する限り、理論上の確率(\(50\%\))から必ずわずかに変動するという統計的な限界があります。
ここで最も重要な疑問は、「なぜシミュレーターでさえ、試行回数(shots)を設定し、統計的な計算をしなければならないのか?」という点です。これは、量子計算の根本原理に由来します。
量子ビットは測定されるまで \(|00\rangle\) と \(|11\rangle\) の重ね合わせ状態にありますが、測定を行った瞬間に、その重ね合わせ状態は消滅し、確定的な古典的な状態(\(00\) または \(11\))に「崩壊(収縮)」します。
一度の測定で重ね合わせが崩壊してしまうため、量子ビットが持っていた真の確率分布(\(50/50\) の比率)を把握するためには、回路を何度も繰り返し実行(サンプリング)し、その結果の統計を集めるしか方法がないのです。
シミュレーターが統計的な計算を行うのは、この「測定による重ね合わせの崩壊(collapse)」という量子力学の物理法則を忠実に模倣しているためです。
まとめと次回予告
本記事では、量子計算の基礎を「極小サイズのプログラム」に凝縮し、以下の3つの重要な操作の意図(なぜそのゲートを使うのか)と結果(測定値の意味)を学習しました。
- アダマールゲート (H)
- 操作: 量子ビットに重ね合わせを生成しました。
- 結果: 測定結果は \(|0\rangle\) と \(|1\rangle\) が約 \(50/50\) で出現し、量子的な確率分布が示されました。
- Xゲート(量子NOT操作)
- 操作: 量子ビットの状態を確定的に反転(NOT)させました。
- 結果: 測定結果は\(100\%\) の \(|1\rangle\) となり、古典計算と同じ確定的な動作を示しました。
- CNOTゲート(量子もつれ)
- 操作: \(\text{H}\) ゲートと組み合わせることで、2つの量子ビット間に量子もつれ(相関関係)を生成しました。
- 結果: 測定結果は\(|00\rangle\) と \(|11\rangle\) のみが \(50/50\) で出現し、\(|01\rangle\) や \(|10\rangle\) が出現しないことから、二つのビットが分離できない関係にあることが証明されました。
次回予告:量子プログラムを「視覚化」する
今回、全てのプログラムはテキスト形式の準確率分布として結果を出力しました。
しかし、量子計算では、回路の構造や結果の分布を視覚的に確認することが、デバッグや理解を深める上で非常に重要になります。
次回の記事では、今回作成したプログラムをさらに進化させ、視覚的なフィードバックを得る方法を探求します。
今回同様、繰り返し手を動かして実装することで、理解と記憶の定着をより盤石なものにしましょう。
| 視覚化要素 | 目的 |
|---|---|
| 回路図 | qc.h(0) や qc.cx(0, 1) といった記述が、実際にどのようなゲートの並びとして実行されているかを、グラフ形式で確認します。 |
| ヒストグラム | テキストで出力されていた準確率分布を、棒グラフ(ヒストグラム)として視覚化します。これにより、重ね合わせともつれの確率的な特性を直感的に理解できるようになります。 |


コメント