← Studio Toriumi

QAOA · Interference · IBM Quantum

干渉で、旅先を決める。

行き先の組み合わせをイジング模型に書き直して、量子の干渉にかけます。 悪い旅程の振幅は打ち消し合い、良い旅程の振幅は強め合う。 最後に重ね合わせをほどく 64回の観測だけは、IBM の量子コンピュータ実機が出したビットに任せます。

① 好み — 押すと重みが上がります(○○○ 〜 ●●●)

なぜ「旅程」なのか

1箇所だけ選ぶなら、量子は要りません。点数のいちばん高いところへ行けば終わりです。 組み合わせた瞬間に、話が変わります。 12箇所から選ぶ組み合わせは 212 = 4,096 通り。 20箇所なら約100万通り、40箇所なら1兆通りを超えます。 行き先が増えるたびに、選択肢は倍になっていく。

しかも「良い旅程」は足し算では決まりません。 金沢と京都はどちらも良くても、両方入れると移動が重くなる。 片方を入れると、もう片方の価値が変わる——この相互作用があるせいで、 一つずつ良いものを選んでいく方法では最適解にたどり着けません。 こういう形の問題を、物理ではイジング模型と呼びます。 磁石のスピンが互いに影響し合いながら、全体としていちばん落ち着く配置を探すのと同じ形です。

問題を、量子ハードウェアが読める形に書き直す

xi を「i番目の行き先に行くなら1、行かないなら0」とします。 最小化したいものを、こう書きます。

H(x) = −Σ scorei·xi + A·(Σxi − k)² ← ちょうど k 箇所にする縛り + 予算重み·Σ (costi/予算)·xi + 移動重み·Σi<j (距離ij/1500km)·xi·xj

x は0か1しか取らないので x² = x が成り立ち、(Σx − k)² を展開しても 一次と二次の項しか残りません。この形を QUBO(二次制約なし二値最適化)と言います。 QUBO は変数を x = (1 − z)/2 で置き換えるだけでイジング模型になり、 そのまま量子ハードウェアの上に乗ります。 旅行の話が、磁石の話と同じ式になる。ここがいちばん面白いところです。

干渉とは、ここで何をしているのか

4,096通りの旅程すべてに、複素数の「振幅」を持たせます。最初はどれも同じ大きさ、同じ向き。 そこに二種類の操作を交互にかけます。

① コスト層 — 位相を回す

旅程 z の振幅を、その旅程のコストに比例した角度だけ回します。 この時点では、確率は1ミリも動きません。 振幅の大きさは変わらず、向きだけが変わるからです。上の絵で色(位相)だけが変わるのはこの層です。

② 混合層 — 混ぜる

各量子ビットを少しだけ回して、隣り合う旅程の振幅どうしを足し合わせます。 ここで初めて、向きの違いが効いてきます。 同じ向きの振幅は足されて大きくなり、反対向きの振幅は打ち消されて消える。 ①で「コストの低い旅程だけ違う向き」にしておいたので、 ②で足し合わせると、コストの低い旅程の確率だけが持ち上がります。

これが干渉です。乱数には、この仕組みがありません。 一様な乱数は4,096通りを平等に扱うだけで、良い旅程を優遇する方法を持っていない。 上の絵で「干渉の後」の山が左へ寄っているのは、確率が実際に動いた記録です。

なぜ1回ではなく、64回撮るのか

本物の量子コンピュータは、1回では答えを出しません。 同じ回路を何百回も走らせて、出てきたビット列を数えます。 干渉で作れるのは「良い旅程が出やすい山」であって、「必ず最適解が出る装置」ではないからです。 QAOA を実際に使うときも、撮ったショットの中でいちばん良かったものを答えとして返します。 このページも同じことをしていて、64ショットぶんのビットを IBM のプールからまとめて受け取っています。

③の内訳を見てください。64回撮ると、だいたい50種類くらいの違う旅程が出ます。 バラバラに見えますが、そのどれもが4,096通りの中の「良いほうの端」に集まっています。 干渉がやったのはそこまでで、最後の1つを選ぶのは「撮った中でいちばん良かったもの」という古典的な手続きです。 ここをぼかして「量子が答えを出した」と書くページが多いので、はっきり分けて書いておきます。

正直なところ

この4,096通りは、全部数えたほうが速いです。 このページも、比較のために裏で全部数えています(「総当たりで求めた最適」がそれ)。 いまの量子コンピュータは、この規模で古典計算機に勝てません。 勝てると書いてあるページがあったら、疑ってください。

干渉の計算をしているのは、あなたのブラウザです。 12量子ビットぶんの状態ベクトル(4,096個の複素数)を素直に持って、 行列をかけています。式は本物ですが、動いているのは普通の計算機です。

実機を使っているのは、最後の観測だけです。 IBM の量子コンピュータに毎日ジョブを投げてビットを貯めてあり、 重ね合わせをほどく一手にそれを使っています。 プールが尽きているときは端末の暗号乱数に落ちて、そのことを画面に出します。黙って差し替えません。

では、なぜやるのか。干渉が実際に何をしているのかを、手元で見られるようにするためです。 QAOA の式は論文で読めますが、確率の山が左へ寄っていく様子は、動かしてみないと掴めません。 そして、この同じ回路は、行き先が40箇所になっても量子ビット40本で書けます。 1兆通りを数え上げる必要はない。そこが、いつか効いてくるかもしれない場所です。

実機で動かすには

同じ回路を IBM の実機に投げるコードです。 無料枠(Open Plan)で動きますが、待ち行列が数時間〜数日になることがあります。

from qiskit_optimization import QuadraticProgram
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
from qiskit.circuit.library import QAOAAnsatz
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

qp = QuadraticProgram()
for s in spots:
    qp.binary_var(s["id"])
qp.minimize(linear=h, quadratic=J)          # 上の H(x) をそのまま渡す

ansatz = QAOAAnsatz(qp.to_ising()[0], reps=3)

service = QiskitRuntimeService(channel="ibm_quantum_platform")
backend = service.least_busy(operational=True, simulator=False)
pm = generate_preset_pass_manager(target=backend.target, optimization_level=3)

# γ と β を探すのは古典側の仕事。ここが誤解されやすい
job = SamplerV2(mode=backend).run([(pm.run(ansatz), best_params)], shots=4096)
print(job.result()[0].data.meas.get_counts())

γ と β を探す外側のループは、古典計算機がやります。 量子側は「この角度でやったらどうなるか」を答えるだけです。 「量子コンピュータが最適化してくれる」という言い方をよく見ますが、正確ではありません。

金額と点数について

金額は2泊3日・1人・東京駅発の目安で、交通費と宿代をざっくり足したものです。 季節と取り方で倍くらい動きます。どちらが高いかの比較にだけ使ってください。 各地の点数(温泉5、海4…)は私が付けた主観で、根拠はありません。 好みのつまみを動かして、自分の感覚に寄せてもらうのが正しい使い方です。