量子計算を用いた手続き型生成
How: 本研究は、量子計算が手続き生成において有用な結果を提供できることを示すことを目的としています。量子干渉を利用したぼかし効果の量子一般化という証明概念を導入しています。これにより、さらなる技術開発がなくとも、今すぐにでも量子計算の実験が有益であることを示しています。
Characteristics: 本研究は、量子計算の即時的な有用性を強調しています。他の研究では、量子計算の実用化にはさらに多くのキュービットが必要であるとされますが、本研究は現在利用可能なプロトタイプハードウェアやシミュレーターを利用して有用な結果を示しています。
Method: 量子干渉を利用したぼかし効果の量子一般化という手法を使用しています。この方法は、現在利用可能なプロトタイプ量子ハードウェアやシミュレーターを用いて実施されています。
Evaluation: 調査結果の評価は、量子干渉を利用したぼかし効果が手続き生成においてどのように役立つかを検証することで行われました。
Discussion: 議論としては、現在の計算資源でも量子計算が有用であることを示し、さらなる研究が他の分野においても有用な結果をもたらす可能性があることが述べられています。
Label: 量子計算, 手続き生成, 量子干渉, シミュレーター, プロトタイプハードウェア
/icons/hr.icon
II. 量子状態における画像のエンコード
前節で紹介した概念を使用して、画像をエンコードし操作する方法を紹介します。具体的には、量子干渉を用いてぼかしのような効果を実装する操作を行います。グレースケール画像を考え、各ピクセルの明るさが0から1の値に対応するものとします。これらの画像を高さマップとしても考えることができ、時にはそのように呼ぶこともあります。
コードスニペットを提供し、この方法がどのように生成されるかを明示的に示します。これらはPythonで記述されており、量子回路を扱うためにQiskitフレームワークを使用します(18)。まず、必要なツールをインポートすることから始めます。
code:python
import numpy as np
from math import pi
from qiskit import QuantumCircuit, quantum_info as qi
他の言語の場合、MicroQiskitを使用できることに注意してください【19】。これはQiskitの最小限の再実装であり、他のプログラミング言語への移植を容易にするよう設計されています。次の方法は、MicroQiskitでもほぼ同じ構文で使用できます。
A. 画像を量子状態に変換する
我々は約20量子ビットまでの小規模な量子プロセスに焦点を当てていますが、それを使って数千のポイントを持つ画像を生成したいと考えています。この2つの間には明らかなスケールの違いがあります。しかし、上記のように、n量子ビットの状態は2^n個の振幅セットによって記述されます。これは各出力ビット列に対応しています。したがって、これらの振幅または対応する確率をすべて利用することで、このギャップを埋めることができます。
実際の量子プロセッサーを使用する場合、その状態に直接アクセスすることはできません。代わりに、2^n個の可能な出力ビット列ごとの確率を推定する必要があります。これは、回路を何度も繰り返して出力をサンプリングすることで行います。具体的には、shots = 4^nのサンプルを使用すれば、確率を十分な精度で推定することができます。しかし、このサンプル数は、シミュレーションを使用した場合に確率に直接アクセスするために必要なO(2^n)を超える計算複雑性を伴います。したがって、我々が開発する方法は、実際の量子デバイスを使用するよりもシミュレーターを使用する方が有利であるというものであり、これは通常の量子コンピューティングでは逆の現象です。
最初の課題は、画像を記述する数値(各座標の明るさの値)と量子状態を記述する数値(各出力ビット列の振幅)との間の対応関係を見つけることです。最も重要な要素は、座標とビット列の間の対応関係を定義することです。
我々の目的に適した理想的な対応関係は、隣接する座標を隣接するビット列に対応させるものです。例えば、ある座標 (x, y) を0000に対応させるとすると、隣接するポイントに対する良い選択肢は次のようになります。
code:tex
(x+1, y) \rarr 1000 \\
(x−1, y) \rarr 0100 \\
(x, y+1) \rarr 0010 \\
(x, y−1) \rarr 0001
ここで、任意の2点間のマンハッタン距離は、対応するビット列間のハミング距離に等しくなります。
一般的に、この対応関係は完全なものではありません。我々は通常、2Dの正方格子に基づいて画像を考えますが、nビット列間のハミング距離によって形成される構造はn次元のハイパーキューブです。これにより、隣接していない座標(格子上)であっても、ビット列が隣接している(ハイパーキューブ内)場合が必ず発生します。しかし、少なくとも隣接する座標が隣接するビット列を持つようにすることはできます。
これは、nビット列のリストを使用して長さが2倍になる(n+1)ビット列のリストを作成するプロセスを繰り返すことで実行されます。このプロセスは、元のリストの2つの変更コピーを作成することから始まります。最初のコピーでは、各ビット列の末尾に0を追加します。次に、2番目のコピーでは順序を反転させ、各ビット列の末尾に1を追加します。最後に、これら2つのリストを結合します。例えば、(0, 1)から始めると、末尾に0を追加した元のリストは (00, 10)になり、末尾に1を追加した反転リストは (11, 01)になります。これらを結合すると、(00, 10, 11, 01)というリストが形成されます。このプロセスを繰り返すことで、任意のnに対して、nビット列のリストの長さを2^nにすることができます。
このプロセスは次のPython関数で適用できます。リストの希望の長さが与えられると、この関数はその長さに少なくとも達するリストを返します。
code:python
def make_line ( length ):
n = int(np.ceil(np.log(length)/np.log(2)))
for j in range(n-1):
cp0 = []
for string in line:
cp0.append (string+’0’)
cp1 = []
cp1.append (string+’1’)
line = cp0+cp1
return line
これにより、2つのリストのx番目とy番目の要素を組み合わせることで、グリッドの各座標 (x, y) に対して一意の文字列を定義できます。次の関数 make_grid は、L × L のグリッドのすべての座標を走査し、対応するビット列を計算し、すべての結果を出力します。これをPythonの辞書として行い、ビット列をキーとして、対応する座標を値として格納します。
code:python
def make_grid(L):
line = make_line(L)
grid = {}
for x in range(L):
for y in range(L):
grid[linex + liney] = (x, y) return grid
これで画像内の座標に対して何をすべきかがわかったので、次は明るさの値そのものに焦点を当てる時です。これを行うために、各値 h が 0≤h≤1の範囲に存在し、すべての高さの中で最大のものが正確に1に等しいと仮定します。この仮定は一般性を失わないものであり、任意の値のセットをこの形にシフトおよび再スケールすることができます。
次に、ビット列 b の確率が対応するグリッドのポイント $ grid \lbrack b \rbrackの明るさに比例するような量子状態を定義します。
code:tex
\frac{p_{b'}}{p_b} = \frac{h_{gridb'}}{h_{gridb}} ここで、単純に$ p_b = h_{grid \lbrack b \rbrack}と設定できない理由は、確率は常に1に合計されなければならないためです。これを実現するために、次のように正規化を行います。
code:tex
p_b = \frac{h_{gridb}}{H}, \quad H=\sum_b h_{gridb} 確率が得られたので、基底状態に対応する振幅が必要です。これらの振幅を実数に制限する場合、それらは確率と単純な関係によって関連付けられます。すなわち、 $ c_b = \sqrt{p_b}です。したがって、我々が画像をエンコードするために必要な状態は次のようになります。
code:tex
\frac{1}{\sqrt{H}}\sum_b \sqrt{h_b}|b\rangle
これで、任意の画像に対してこの状態を作成する関数を構築できます。これは、適切な量子ビット数の操作セットである「量子回路」を作成し、デフォルトの初期状態 $ |00\dots00\rangle から必要な状態を準備することを意味します。この抽象的なレベルで詳細に立ち入るのではなく、量子回路がQuantumCircuitクラス内で定義されるQiskitを使用します。このクラスには、希望する初期状態を設定するために使用できるinitializeメソッドが含まれています。
次に操作する画像は、座標をキーとし、対応する明るさを値とするPythonの辞書形式で表されます。欠落した座標は、0の値に対応すると仮定されます。以下はそのような画像の例です。
code:python
height = {}
for pos in [(2,5),(2,6),(5,6),(5,5),(2,1),\
(3,1),(4,1),(5,1),(1,2),(6,2)]:
次の関数は、与えられた画像を量子回路に変換することができます。
code:python
def height2circuit(height):
# グリッドサイズを決定
L = max(max(height)) + 1
# グリッドを作成
grid = make_grid(L)
# 必要な量子ビット数を決定
n = 2 * int(np.ceil(np.log(L) / np.log(2)))
# 空の状態を作成
# 必要な振幅で状態を埋める
H = 0
for bit_string in grid:
if (x, y) in height:
H += h
# 状態を正規化
for j, amp in enumerate(state):
statej = amp / np.sqrt(H) # 量子回路を定義し初期化
qc = QuantumCircuit(n, n)
qc.initialize(state, range(n))
# 標準のQiskitを使用する場合は以下を使用
# qc.initialize(state, qc.qregs0) return qc
B 量子状態を画像に変換する
次の作業は、逆のプロセスを実装することです。つまり、量子回路を画像に変換することです。そのためには、各可能な出力ビット列bに対する確率$ p_bを決定する必要があります。シミュレーションプロセスの場合、量子状態全体を追跡することができます。その後、以下の circuit2height 関数で示されているように、確率$ p_bを直接抽出できます。
code:python
def circuit2height(qc):
# 回路から量子ビットの数を取得
n = qc.num_qubits
grid = make_grid(int(2**(n/2)))
# 回路から初期状態を取得
ket = qi.Statevector(qc.data00.params) qc.data.pop(0)
# 回路の残り部分でこの状態を進化させる
ket = ket.evolve(qc)
# 出力確率を抽出
p = ket.probabilities_dict()
# 再スケーリングのために最大確率値を決定
max_h = max(p.values())
# 再スケーリングされた確率値を高さに設定
height = {}
for bit_string in p:
if bit_string in grid:
return height
もし実際の量子ハードウェアを使用する場合、プロセスは少し複雑になります。まず、出力ビット列を取得するためには、量子ビットを測定する必要があります。全量子ビットの測定は、qc.measure_all() を使用して回路の最後に測定を追加することで行うことができます。その後、回路を実行するたびに、確率分布$ p_bに従って抽出されたビット列bが返されます。これらの確率を推定するためには、回路を複数回実行し、各出力を得た回数をカウントする必要があります。これらの結果は、カウント辞書として表現され、$ counts\lbrack b \rbrackがビット列bに対するサンプル数を示します。これは以下のように行います。
code:python
result = execute(qc, backend, shots=shots).result()
counts = result.get_counts()
バックエンドは回路 qc を実行するデバイスを示し、shots はプロセスを繰り返すサンプル数を表します。各カウント値を shots で割ることにより、確率の推定が得られます。ただし、元の画像を取り戻すためにこれらの値を再スケーリングする必要があるため(最大値が1になるようにするため)、確率の代わりにカウント値をそのまま使用することができます。前述のように、shots の回数分のサンプリングのオーバーヘッドにより、この特定のアプリケーションでは実際の量子ハードウェアを使用することは効率的ではありません。
どのようにして circuit2height を実行するにしても、height2circuit と組み合わせることで、例の画像の高さをエンコードし、復元するというシンプルなプロセスを実装することができます。
code:python
qc = height2circuit(height)
new_height = circuit2height(qc, backend)
https://scrapbox.io/files/66b98dc82d0d06001cc83363.png
図1:
(a) 量子回路にエンコードされ、そこから復元されたシンプルな顔の画像。
(b) すべての量子ビットに対して$ R_y \left( \frac{\pi}{10} \right) ゲートを適用した後の画像。
(c) (b)と同じ画像ですが、値が対数的にプロットされています。
もっと興味深いのは、回路に量子ゲートを追加して画像を操作することです。適用するゲートについては多くの選択肢がありますが、非常に簡単なものを考えます。すべての量子ビットに対して与えられた角度θでRyを単純に適用します。結果は図1に示されています。指数分布によるぼやけが発生するため、効果は非常にわずかに見えます。値を対数表示すると、効果がより明確に見えます。このぼやけ効果が干渉プロセスによるものであることは、大きな角度を使用したときに最も簡単に確認できます。これは、初期の2ピクセルの画像がいわゆるGHZ状態を表す図2に示されています。
ここで、小さな角度では比較的単純なぼやけ効果が見られます。しかし、単に均一な分布にぼやけるのではなく、角度θ=0.5πでは干渉効果によりチェッカーボードパターンが生じます。より大きな角度では、元の点が再形成され、角度θ=πで元の画像に戻ります。角度θ=0.5πでの干渉パターンは初期状態に強く依存するため、元の画像で他のピクセルを選んだ場合、異なるパターンが現れるでしょう。
方法の応用
量子ぼかし法は、様々なゲームジャムのプロジェクトで開発され、テストされました。主にシード画像からテクスチャを手続き的に生成するために使用されました。これらの応用例のいくつかを以下に示します。
最初の応用は、PyWeek 27のゲームジャムで「Quantograph」というアートトイとして使用されました。ユーザーはシード画像と一連のパラメータを選択でき、これらのパラメータに基づいて複数の量子回路が実装され、それぞれがわずかに異なるフレームを生成してアニメーションを作成しました。これにより、量子干渉効果がシード画像を歪ませる様子が視覚化されました。このプロジェクトでは、カラー画像を扱えるようにするため、RGBの各カラーチャンネルごとに3つの異なる量子プロセスを実行しました。同様のアニメーションは、GMTK Game Jam 2019のゲームでも使用され、レベル間の移行時に画面を量子プロセスでスクランブルして元に戻すトランジションアニメーションとして使用されました。
このアイデアの拡張として、2つのシード画像間の遷移をテレポーテーションのような効果で実現できます。具体的には、同じサイズのキュービットレジスタに作用するSWAPゲートを使用して、それらの状態を交換します。RxやRyがNOTゲートの分数形式と見なされるのと同様に、SWAPゲートの分数形式も定義できます。2つの異なる画像を異なるキュービットレジスタにエンコードし、異なるフレームの画像を生成するためにSWAPゲートの異なる分数を適用することで、この量子SWAP操作の中間状態を視覚化し、テレポーテーションのような効果のアニメーションを作成できます。少数のピクセル画像の例が図3に示されています。
Ludum Dare 44では、量子ぼかし効果を使用してマップを生成し、シンプルなゲームをプレイしました。使用された手法の例が図4に描かれています。具体的には、図4(b)の16×16のテクスチャパッチは、図4(a)のランダムに生成されたシード画像から作成されます。その後、ビット文字列と座標の代替マッピングがランダムに生成され、対応する画像が同じ確率セットを使用して構築されるシャッフルプロセスによって、数百のランダムなバリエーションが作成されます。これにより、量子プロセスを一度だけ使用して数百のテクスチャが生成され、ノートパソコンでの全体の処理時間は10秒未満です。これらのテクスチャは、予め決められたシンプルなレイアウトの高さに基づいて、200×200ピクセルの画像にランダムに配置されます。このプロセス全体で、図4(c)に示されている島が生成され、色は異なる高さの地形の種類を表します。
PROCJAM 2019では、上記の方法が3Dでレンダリング可能な島を作成するために適応されました。これは、ボクセルベースのゲームエンジンを使用して行われ、高さが各点で切り捨てられました。このため、真の値と切り捨てられた値の間の差として0 ≤ r < 1の値が各点に残り、これらの値は木などのオブジェクトの配置位置を決定するために使用されました。この方法は、その後、教育ゲームのQiskitBlocksでも使用されました。
この方法は、離散データの他の形式にも適用され、make_lineの結果をマッピングの出発点として使用しました。例えば、特定の音符を、バー内の位置とオクターブを表す座標で構成された3D空間に配置することができます。各座標は適切な長さのビット文字列のラインに対応し、全体の座標はこれらのビット文字列の組み合わせに対応します。これにより、音楽を量子状態に変換したり、量子状態から音楽に変換したりできます。量子ゲートのぼかし効果により、音符がバーやオクターブ間でにじむ効果が生じます。図5は、量子ぼかし効果を使用して生成され、QiskitBlocksで3Dレンダリングされた島の例です。