量子回路のデバッグ術:PythonとQiskitで描く回路図とヒストグラム

量子コンピュータ

前回の記事では、量子プログラミングにおける極小サイズのサンプルを作成し、フレームワークとして使用することで、主要な量子ゲートを繰り返し実装して記憶の定着を図りました。

今回は、それらのプログラムをさらにパワーアップさせる視覚化ツールを学習します。
前回同様、繰り返し手を動かすことで、「量子回路図」と「ヒストグラム」の2大視覚化ツールを完全マスターしましょう。

プログラミング経験者の方へ:

量子プログラミングのデバッグは、古典プログラミングとは根本的に性質が異なります
変数の中身を直接見ることができないため、デバッグの主眼は、『意図した確率分布が実現しているか』を確認することにあります。

第1章:回路図の描画

本章では、前回記事で作成したHゲートのプログラムをそのまま使用します。
しかし、もし前回の内容やコードの記述に少しでも不安がある場合は、プログラムをゼロから再構築しながら本章の実装を進めることを強く推奨します。
この「繰り返し実装」こそが、量子プログラミングの知識を確実なものにするための、最も絶大な効果をもたらす学習法だからです。

ステップ 1:回路図の描画コードについて詳細に解説

画像形式 ('mpl') を使用する場合、Pythonの標準ライブラリである Matplotlib が必要です。
事前準備として、ターミナルやコマンドプロンプトで pip install matplotlib を実行してください。

ステップ 1.1. 描画に必要になる新たなインポート

import matplotlib.pyplot as plt

ステップ 1.2. 描画メソッドの仕様

回路図を描画する主なメソッドは、QuantumCircuit オブジェクトの draw() メソッドです。
このメソッドは、引数で表示形式を指定できます。

記述方法役割
qc.draw()回路図を標準出力にテキスト形式で描画する。
qc.draw(‘mpl’)matplotlibを使用し、画像形式でゲートの視覚的な図を描画する。

今回は、視覚的なデバッグが目的であるため、qc.draw('mpl') を使用し、画像として表示させることを推奨します。
また、ステップ 2 で plt.show() を使用して描画を完了させます。

ただし、VS Codeなどの環境によっては、circuit_drawer を使って描画オブジェクトを取得・表示する手順が必要になる場合があります。

ステップ 2:回路図を「重ね合わせ」プログラムに追加

ステップ 1 で学んだ知識を使用し、前回作成したHゲート(重ね合わせ)のプログラムに回路図の描画機能を追加してください。

回路図を描画するコードは、実行工程(sampler.run)のに記述します。

答え合わせをしたい方は、以下のコードを確認してください。

from qiskit import QuantumCircuit
from qiskit_aer.primitives import Sampler
import matplotlib.pyplot as plt

qc = QuantumCircuit(1, 1)
qc.h(0)

qc.measure(0, 0)

# 回路図を描画するコード(以下の2行)
qc.draw('mpl')
plt.show()

sampler = Sampler()
job = sampler.run([qc], shots=1024)
result = job.result()
counts = result.quasi_dists[0]

print("Counts:", counts)

回路図は、画像をポップアップ表示させるだけではなく、以下のパターンで出力することができます。

  • 標準出力にテキスト形式で描画:
    • print(qc.draw(output=’text’))
  • 画像ファイルとして保存:
    • qc.draw(output=’mpl’, filename=’xxx.png’)

ステップ 3:実行結果の確認

ステップ 2で完成させたHゲートのプログラムを実行し、出力された回路図とCounts(計測結果)が論理通りになっているかを確認します。

ステップ 3.1. 視覚的確認(回路図)

プログラムを実行すると、matplotlibによって以下のような回路図(画像)が表示されます。

重ね合わせ状態の回路図
  • 量子ビット(q0)にアダマールゲート(H)が適用され、その直後に測定操作(メータのアイコン)が適用されていることを確認してください。
  • 上図は、コードの記述通り、量子ビット q0 が重ね合わせ状態にされた後、古典ビット c0 にその結果が書き込まれるという「構造」を明確に示しています。

ステップ 3.2. 確率的確認(Counts)

回路図の確認後、プログラムは計測を行い、Countsとして結果が出力されます。
(値はショット数(1024)に応じて多少変動します)

Counts: {1: 0.494140625, 0: 0.505859375}
  • Hゲートによって生成された重ね合わせ状態は、理論上50%の確率で 0、50%の確率で 1 を示します。
  • 出力された Counts が、この確率分布に近い値になっていることを確認してください。

第2章:ヒストグラムの描画

本章では、前回記事で作成したXゲートのプログラムをそのまま使用します。
しかし、もし前回の内容やコードの記述に少しでも不安がある場合は、プログラムをゼロから再構築しながら本章の実装を進めることを強く推奨します。
この「繰り返し実装」こそが、量子プログラミングの知識を確実なものにするための、最も絶大な効果をもたらす学習法だからです。

ステップ 1:ヒストグラムの描画コードについて詳細に解説

このステップでは、量子プログラミングのデバッグにおける主眼である「確率分布の検証」に必須となるヒストグラムの描画に必要なコードの仕様を解説します。

ステップ 1.1. 描画に必要になる新たなインポート

from qiskit.visualization import plot_histogram # ヒストグラムの描画に必要な関数をインポート
import matplotlib.pyplot as plt

Matplotlib は第1章で既にインストールを促していますが、ヒストグラムも画像形式で出力するため、未インストールの方は再度 pip install matplotlib を実行してください。

ステップ 1.2. 描画メソッドの仕様

ヒストグラムの描画は、plot_histogram() 関数を使用します。
この関数は、計測結果の確率分布(Counts)を引数として受け取ります。

記述方法役割
plot_histogram(counts)計測結果の確率分布(Counts)を基にヒストグラムを作成する。
plt.show()作成したヒストグラムの画像を画面に表示する。

plot_histogram() 関数は、シミュレーション結果の result.quasi_dists から得られたCountsを直接入力します。
この図は、量子プログラムの確率的な動作が意図通りかを確認するための、最も重要なデバッグツールです。

ステップ 2:ヒストグラムをXゲート(NOT操作)プログラムに追加

ステップ 1 で学んだ知識を使用し、前回作成したXゲート(NOT)のプログラムにヒストグラム描画機能を追加してください。

ヒストグラムを描画するコードは、実行結果(counts)の直後に記述します。

答え合わせをしたい方は、以下のコードを確認してください。

from qiskit import QuantumCircuit
from qiskit_aer.primitives import Sampler
from qiskit.visualization import plot_histogram
import matplotlib.pyplot as plt

qc = QuantumCircuit(1, 1)
qc.x(0)
qc.measure(0, 0)

sampler = Sampler()
job = sampler.run([qc], shots=1024)
result = job.result()
counts = result.quasi_dists[0]
print("Counts:", counts)

plot_histogram(counts) # ヒストグラムの描画
plt.show()

ステップ 3:実行結果の確認

ステップ 2で完成させたXゲート(NOT操作)のプログラムを実行し、出力されたヒストグラムとCounts(計測結果)が論理通りになっているかを確認します。

本章はヒストグラムの描画がテーマです。ヒストグラムは、量子プログラムの最も重要な結果である「確率分布」を視覚化するツールです。

以下の理由により、先にCountsの出力結果を確認します。

  • プログラムはまずCounts(数値データ)を出力します。これはプログラムの直接的な結果です。
  • 次に、そのCountsを引数として plot_histogram メソッドを実行し、ヒストグラムという視覚的な出力を得ます。
  • したがって、数値データ(原因)を確認してから、それが正しく視覚化(結果)されたかという流れが、ヒストグラムの実装検証としては論理的です。

ステップ 3.1. 確率的確認(Counts)

プログラムを実行すると、Countsとして以下の結果が出力されます。
(値はショット数(1024)に応じて多少変動します)

Counts: {1: 1.0}
  • Xゲート(NOT操作)は、初期状態 \(|0\rangle\) の量子ビットを \(|1\rangle\) に反転させるため、理論上は100%の確率で 1 が計測されます。
  • 出力された Counts が、この確率分布に近い値になっていることを確認してください。

ステップ 3.2. 視覚的確認(ヒストグラム)

プログラムを実行すると、matplotlibによって以下のようなヒストグラム(画像)が表示されます。

初期状態をXゲートで反転させたヒストグラム
  • ヒストグラムのバーが、ほぼ完全に「1」の位置に立っていることを確認してください。
  • この図は、量子プログラムの確率的な動作が意図通りか、すなわちXゲートが確実に反転操作を行っているという「論理」を明確に示しています。

第3章:知識の定着(応用)

本章では、第1章と第2章で学んだ回路図とヒストグラムの両方を、量子もつれ(CNOTゲート)プログラムに適用します。

ステップ 1:複数の描画を確実に行うためのコードについて解説

ステップ 1.1. 描画に必要なインポート

第1章および第2章で使用したすべてのインポートを再利用します。
特に matplotlib.pyplot as plt は、複数の図を制御するために必須です。

from qiskit.visualization import circuit_drawer, plot_histogram
import matplotlib.pyplot as plt

ステップ 1.2. 描画オブジェクトの明示的な取得

これまでは qc.draw('mpl') のようにメソッドを呼び出すだけで描画を試みましたが、複数の図を同時に描画する場合、厄介な問題が発生する場合があります。
個々の図のメソッドを呼び出すだけでは、描画プロセスが競合し、片方の図しか表示されない、あるいは、表示されはするものの一瞬でウィンドウが閉じてしまうことがあるのです。

その解決手法として、描画オブジェクトを変数に代入することで、plt.show() がすべてのオブジェクトを認識し、安定して表示できるようになります。
複数の図を同時に扱うには、描画結果(Figureオブジェクト)を変数に明示的に代入する必要があることを覚えておきましょう。

ステップ 2:量子もつれプログラムに回路図とヒストグラムの両方を追加する

前回作成した量子もつれ(CNOTゲート)プログラムに、第1章で学んだ回路図、第2章で学んだヒストグラム、そして本章ステップ 1で学んだ描画オブジェクトの明示的な取得という、すべてのコードを追記します。

以下のすべての機能を実装してください。

  1. CNOTゲートの後に測定(qc.measure_all() を推奨)を追加します。
    • 従来の qc.measure([0, 1], [0, 1]) でも完全に動作しますが、効率コードの簡潔さから、qc.measure_all() を推奨しています。
  2. qc.draw('mpl') の結果を、変数 fig_circuit に代入します。
  3. plot_histogram(counts) の結果を、変数 fig_hist に代入します。
  4. 最後に plt.show() で両方の図を一括表示します。

答え合わせをしたい方は、以下のコードを確認してください。

from qiskit import QuantumCircuit 
from qiskit_aer.primitives import Sampler 
from qiskit.visualization import plot_histogram
import matplotlib.pyplot as plt # ★ 描画制御用

# 回路と入出力の定義 (2Qubit, 2Cbit)
# 量子もつれには2つの量子ビットが必要です
qc = QuantumCircuit(2, 2) 

# 量子操作の定義(エンタングルメントの作成)
qc.h(0) # index 0の量子ビットを重ね合わせ
qc.cx(0, 1) # index 0を制御ビットとしてindex 1にCNOTを適用

# 測定と実行の定義
# 全ての量子ビットを測定できる便利なメソッド
qc.measure_all()

sampler = Sampler()                      
job = sampler.run([qc], shots=1024)
result = job.result()                    
counts = result.quasi_dists[0]           

print("Counts:", counts)

# 回路図とヒストグラムの描画(オブジェクト取得)
# それぞれの描画オブジェクトを変数に保持
fig_circuit = qc.draw('mpl')
fig_hist = plot_histogram(counts)

# ★ 5. 全ての図の一括表示
plt.show()

何かしらのプログラミング言語の経験者は、このコードを見て「fig_circuitfig_histという2つの変数は、未使用ではないか」と思われるかもしれません。

今回、変数に描画オブジェクトを代入した目的は、そのオブジェクト自体を使用することではなく、そのオブジェクトをPythonのメモリ上で「生存」させておくことです。

変数(fig_circuit、fig_hist)に代入しないと、Pythonのメモリ管理機能が、生成されたオブジェクトをすぐに解放(破棄)してしまう可能性があります。
これが、「片方の図しか表示されない」「表示はされるが一瞬で消えてしまう」という競合問題の根本原因です。

それぞれ変数に格納しておくことで、最後の行 plt.show() が実行されるとき、Matplotlibは現在メモリ上に生存しているすべての描画オブジェクト(Figureオブジェクト)を検出し、一斉に画面に表示するという動作をします。

ステップ 3:実行結果の確認

ステップ 2で完成させた量子もつれプログラムを実行し、出力された回路図ヒストグラムが、CNOTゲートの論理通りになっているかを確認します。

ステップ 3.1. 回路図の確認

プログラムを実行すると、fig_circuit に保持された描画オブジェクトが plt.show() によって表示されます。

量子もつれの回路図
  • 初めに、q0にアダマール(H)ゲートが適用されていることが確認できます。
  • 続いて、CNOTゲートによって、アダマールゲート(H)を通ったq0が制御ビット(上図の青丸マーク)となり、初期状態のq1に操作を適用して量子もつれ状態を生成していること(上図のプラス⊕マーク)が確認できます。
  • 最後に、回路の右端にあるメーターアイコン(測定操作)によって、q0とq1の量子状態が古典ビット(一番下の「c」のライン)に書き込まれていることが確認できます。これは、シミュレーション結果(Counts)を得るための最終ステップです。

ステップ 3.2. ヒストグラムの確認

fig_hist に保持された描画オブジェクトであるヒストグラムも表示されているはずです。

量子もつれのヒストグラム
  • CNOTゲートによって生成された量子もつれ状態は、理論上、以下の2つの状態のみが50%ずつ計測されます。
    • \(|00\rangle\) つまり0 (q1が0、q0が0)
    • \(|11\rangle\) つまり3 (q1が1、q0が1)
  • ヒストグラムのバーが、「00」(10進数で0)と「11」(10進数で3)の位置のみに立っていることを確認してください。これは、「01」と「10」の状態が絶対に計測されないことを示しており、量子もつれが正しく生成されていることの証拠です。

まとめ

本記事では、量子プログラミングにおける最も重要なデバッグツールである回路図ヒストグラムの使い方を、実践を通じて徹底的に解説しました。

エラーを修正することだけでなく、コードが正しいことを検証することもデバッグの重要な役目です。
この2つのツールを使いこなすことで、量子プログラムの信頼性正確性を常に保証できるようになります。

コメント

タイトルとURLをコピーしました