AI要約
やること
量子ゲート方式の勉強をしています。これまでに基本的な量子ゲートの使い方を学び、足し算と引き算の量子回路(回路ではないので是非とも量子譜と呼びたい)を作りました。
ここまではGUIアプリを使ってマウスポチポチでゲートを置いてきましたが、やはりPythonでもっと立派な量子計算がしてみたいと思い、新たな課題を考えました。
ずばり、7セグメントLEDで0~Fまでを点灯させます。

詳しくはシリーズを通して解説していきます。
まず今回は、Pythonで量子譜を記述して計算シミュレーションができる「Qiskit」というパッケージの練習をしていきます。
Qiskitとは
QiskitはIBMによって公開されたオープンソースの量子計算パッケージです。
Python環境にpipインストールしてください。最新版はうまく動かなかったのでバージョン1.1.0を入れました。
pip install qiskit==1.1.0
pip install qiskit-aer
NOTゲート(最小コード)
最小コードを見てみます。
量子ビットを2個用意して、1個目をHゲートで重ね合わせ状態に。2個目は1個目をNOTしたものとします(※NOT, AND, XOR, ORゲートの基礎は過去記事参照)。
最後にすべての量子ビットを観測します。サンプリング回数は100回。
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
#初期化
qc = QuantumCircuit(2)
#同時計算のため入力ビットを重ね合わせにする
qc.h(0)
#処理
qc.cx(0, 1)
qc.x(1)
#計算
qc.measure_all()
backend = AerSimulator(method='matrix_product_state')
result = backend.run(qc, shots=100).result().get_counts()
#解の確認
for r in result:
print(f'{r[::-1]} | {result[r]}/100')
01 | 49/100
10 | 51/100
解の量子ビットは左から順に並ぶようにしました(元は右から並ぶ)。縦棒の右側は、全サンプリング回数の中で何回この解にHITしたか。
解を見ると [01] と [10] だけが出ています。1個目の量子ビットは分身して2パターンを取り、2個目はそれのNOTになっています。
ここで、このNOTゲートを関数化します。
def NOT(i, j):
global qc
"""
(NOT i) -> j
"""
qc.cx(i, j)
qc.x(j)
関数を使ってさっきと同じ計算をしてみます。
#初期化
qc = QuantumCircuit(2)
#同時計算のため入力ビットを重ね合わせにする
qc.h(0)
#処理
NOT(0, 1)
#計算
qc.measure_all()
backend = AerSimulator(method='matrix_product_state')
result = backend.run(qc, shots=100).result().get_counts()
#解の確認
for r in result:
print(f'{r[::-1]} | {result[r]}/100')
10 | 55/100
01 | 45/100
ちなみに、子譜の画像を保存する場合はこちらのコードを計算前に入れます。
#量子譜の図を保存
fig = qc.draw(output='mpl', scale=1.0, fold=-1)
fig.savefig('circuit.png', dpi=300, bbox_inches='tight')

やはりこの図が表示されると「ゲートやってるぞ」って感じがしますね(初心者)
AND, XOR, ORゲート
ANDゲート
ANDゲートも関数も作ってみましょう。これ以降のゲートでは3量子ビット用意して、入力が2個、出力が1個です。
def AND(i, j, k):
global qc
"""
(i AND j) -> k
"""
qc.ccx(i, j, k)
#初期化
qc = QuantumCircuit(3)
#同時計算のため入力ビットを重ね合わせにする
qc.h(0)
qc.h(1)
#処理
AND(0, 1, 2)
#計算
qc.measure_all()
backend = AerSimulator(method='matrix_product_state')
result = backend.run(qc, shots=100).result().get_counts()
#解の確認
for r in result:
print(f'{r[::-1]} | {result[r]}/100')
000 | 26/100
010 | 31/100
100 | 24/100
111 | 19/100

ちゃんとANDできていますね。入力が [11] のときだけ出力が [1] になっています。
XORゲート
XORゲートの関数です。
def XOR(i, j, k):
global qc
"""
(i XOR j) -> k
"""
qc.cx(i, k)
qc.cx(j, k)
#処理
XOR(0, 1, 2)
000 | 15/100
011 | 29/100
101 | 29/100
110 | 27/100

うまくできています。
ORゲート
最後にORゲートです。私の考え方が原始的なせいか、やたらにXゲートを使います。
def OR(i, j, k):
global qc
"""
(i OR j) -> k
"""
qc.x(i)
qc.x(j)
qc.ccx(i, j, k)
qc.x(i)
qc.x(j)
qc.x(k)
#処理
OR(0, 1, 2)
000 | 23/100
011 | 23/100
101 | 23/100
111 | 31/100

OKですね。
おわりに
さまざまな量子計算を行うための基本的な素子であるNOT, AND, XOR, ORゲートを、Python+Qiskitで使用することができました。厳密に言えばXORは必須ではないのですが、せっかくCCXゲートが対応しているので用意しておきました。
いよいよ次回から7セグメントLEDの計算に移ります。