12/9(月) 応用科学学会シンポジウムで自動運転に関する講演を担当します☆彡(試乗会もあります!来て!)

量子アニーリング(HOBO)でTakuzuパズルを解いてみた

やること

前回に引き続き、HOBO対応の疑似アニーリングパッケージ「HOBOTAN」でペンシルパズルを解いていきましょう。

今回は「Takuzu(Binairo)」です。このパズル知ってますか?

※この記事はQUBOアニーリングの基礎講座を履修済みであることを前提としています。

TYTANについて

前身となる「TYTAN」はOSSの疑似量子アニーリングパッケージです。

GitHub - tytansdk/tytan: Python SDK for large QUBO problems
Python SDK for large QUBO problems. Contribute to tytansdk/tytan development by creating an account on GitHub.

日本量子コンピューティング協会が運営しているチュートリアル教材はこちら。

GitHub - tytansdk/tytan_tutorial
Contribute to tytansdk/tytan_tutorial development by creating an account on GitHub.

私のオンライン講義でよければこちらから見れます。

【第3世代】1/5 QUBOアニーリング TYTANチュートリアル

discordコミュニティもあるので気軽に質問できます。

https://discord.gg/qT5etstPW8

HOBOTANについて

それを元にしてできたのが「HOBOTAN」。使い方はTYTANとほとんど同じです。分からないことがあれば何でも聞いてください。

GitHub - ShoyaYasuda/hobotan: tytanのHOBO版(テスト)
tytanのHOBO版(テスト). Contribute to ShoyaYasuda/hobotan development by creating an account on GitHub.

Takuzuとは

このパズルにはいくつか別名があります。

  • タクズ(Takuzu)
  • ビナイロ(Binairo)
  • まるばつロジック

Puzzle Team さんはBinairoと呼んでいます。1問お借りします。

ルールは、盤面を黒と白の玉で埋めるのですが、各行、各列とも白と黒が同数(3個ずつ)入ります。また、直線に3つ同じ色が並んではいけません。さらに、まったく同じ配列の行が2つ以上あってはいけません(列も同様)。

答えはこちらです。

コンセプティスパズル さんでも遊べます(こちらはまるばつロジックという名前ですね)。

定式化

この手の二値タイプのパズルはQUBO/HOBOと相性が良いですね。

黒を0、白を1としておきます。あらかじめ決まっているマスの制約と、各行・各列とも3個だけ1にする制約を設定します。

「直線に3つ同じ色が並んではいけない」はHOBOTANのチュートリアルにある「教室の席にできるだけ多くの生徒を座らせる(ただし縦・横に3席連続で座ってはいけない)」と同じ設定ですね。また出ました。これが3次の項なのでHOBOになります。

GitHub - ShoyaYasuda/hobotan: tytanのHOBO版(テスト)
tytanのHOBO版(テスト). Contribute to ShoyaYasuda/hobotan development by creating an account on GitHub.
from hobotan import *
import numpy as np
import matplotlib.pyplot as plt

#問題(空マスは5にした)
question = [[1,5,5,5,5,5],
            [5,5,5,5,5,0],
            [1,5,0,5,0,5],
            [5,5,5,5,0,5],
            [5,5,5,5,5,5],
            [1,1,5,5,5,5]]


#量子ビットの用意
q = symbols_list([6, 6], 'q{}_{}')

#式を用意
Hconst = 0

#問題を反映
for i in range(6):
    for j in range(6):
        if question[i][j] != 5:
            Hconst += (q[i, j] - question[i][j])**2

#よこ方向の白は3個
for i in range(6):
    Hconst += (np.sum(q[i, :]) - 3)**2

#たて方向の白は3個
for j in range(6):
    Hconst += (np.sum(q[:, j]) - 3)**2

#直線の3マスが連続で1になったら臨時ペナルティ
for i in range(6):
    for j in range(6 - 3 + 1):
        Hconst += np.prod(q[i, j:j+3])
for j in range(6):
    for i in range(6 - 3 + 1):
        Hconst += np.prod(q[i:i+3, j])

#直線の3マスが連続で0になったら臨時ペナルティ
for i in range(6):
    for j in range(6 - 3 + 1):
        Hconst += np.prod((1 - q[i, j:j+3]))
for j in range(6):
    for i in range(6 - 3 + 1):
        Hconst += np.prod((1 - q[i:i+3, j]))

#式の合体
H = Hconst

#HOBOテンソルにコンパイル
hobo, offset = Compile(H).get_hobo()
print(f'offset\n{offset}')

#サンプラー選択
solver = sampler.MIKASAmpler()

#サンプリング
result = solver.run(hobo, shots=1000, T_num=10000)

#上位3件
for r in result[:3]:
    print(f'Energy {r[1]}, Occurrence {r[2]}')

    #さくっと配列に
    arr, subs = Auto_array(r[0]).get_ndarray('q{}_{}')
    
    #さくっと画像に
    img, subs = Auto_array(r[0]).get_image('q{}_{}')
    plt.figure(figsize=(3, 3))
    plt.imshow(img)
    plt.show()
tensor order = 2
----- compile -----
MODE: GPU
DEVICE: cuda:0
-------------------
offset
160.0
===== sampler =====
MODE: GPU
DEVICE: cuda:0
===================
.......... 1000/10000 min=-156.0 mean=-149.4350128173828
.......... 2000/10000 min=-156.0 mean=-150.55599975585938
.......... 3000/10000 min=-158.0 mean=-151.4910125732422
(中略)
.......... 8000/10000 min=-160.0 mean=-156.65200805664062
.......... 9000/10000 min=-160.0 mean=-156.7930145263672
.......... 10000/10000 min=-160.0 mean=-156.9390106201172
Energy -160.0, Occurrence 6
(画像)
Energy -160.0, Occurrence 3
(画像)
Energy -159.0, Occurrence 1
(画像)

オフセットが160、解のエネルギーが-160(理想的)のものが2種類出ました。正解と見比べてみてどうでしょうか?1番目は正しいですが、2番目は不正解です。

2番目の解は同じ配列があちこちに現れてしまっています。

エネルギーが理想的だったにもかかわらず正しくないということは、制約条件が間違っていた(足りなかった)ということですね。やはり「同じ配列の行が2つ以上あってはいけない(列も同様)」の設定が必要です。

配列の一致の検出

ということで「マスが6組とも一致したら臨時ペナルティ」を設定したいです。

思いっきり簡単にして「マスが2組とも一致したらペナルティ」を考えてみましょう。

AとBの一致は (A – B)^2 で判定できます。[0, 0] or [1, 1] なら0に、[0, 1] or [1, 0] なら1になります。一致したときに1になってほしいので、この式の否定(=0/1を逆転させる)で (1 – (A – B)^2) となります(→量子アニーリング(QUBO)で複数の数字を均等に2組に分ける。これでAとBの一致判定ができました。同じことをCとDでも行い、それらをかけ算(=同時に1になったら)すれば「2組とも一致したら1」の出来上がりです。

ところで、(1 – (A – B)^2) × (1 – (C – D)^2) の次数はいくつか?つまり、最大で何個の量子ビットのかけ算になっているかです。展開すると4次だと分かります。

実際は「6組とも一致したら臨時ペナルティ」なので・・・

(1 – ( )^2) × (1 – ( )^2) × (1 – ( )^2) × (1 – ( )^2) × (1 – ( )^2) × (1 – ( )^2)

展開すると12次の式になります。。圧倒的HOBO感!

6列あってどの列も重複してはならないなので、(列目でいうところの)1-2, 1-3, 1-4, 1-5, 1-6, 2-3, 2-4, 2-5, 2-6, 3-4, 3-5, 3-6, 4-5, 4-6, 5-6 の15通りの一致ペナルティを設定します。6C2のコンビネーションで次のように設定できます。

from itertools import combinations

#よこ配列が重複しない
for a, b in combinations(range(6), 2):
    Hconst += (1 - (q[a, 0]-q[b, 0])**2) * (1 - (q[a, 1]-q[b, 1])**2) * (1 - (q[a, 2]-q[b, 2])**2)\
            * (1 - (q[a, 3]-q[b, 3])**2) * (1 - (q[a, 4]-q[b, 4])**2) * (1 - (q[a, 5]-q[b, 5])**2)

#たて配列が重複しない
for a, b in combinations(range(6), 2):
    Hconst += (1 - (q[0, a]-q[0, b])**2) * (1 - (q[1, a]-q[1, b])**2) * (1 - (q[2, a]-q[2, b])**2)\
            * (1 - (q[3, a]-q[3, b])**2) * (1 - (q[4, a]-q[4, b])**2) * (1 - (q[5, a]-q[5, b])**2)
tensor order = 12
----- compile -----
MODE: GPU
DEVICE: cuda:0
-------------------
offset
190.0
===== sampler =====
MODE: GPU
DEVICE: cuda:0
===================
.......... 1000/10000 min=-184.0 mean=-179.20901489257812
.......... 2000/10000 min=-186.0 mean=-180.26100158691406
.......... 3000/10000 min=-186.0 mean=-181.1070098876953
(中略)
.......... 8000/10000 min=-190.0 mean=-186.239013671875
.......... 9000/10000 min=-190.0 mean=-186.4110107421875
.......... 10000/10000 min=-190.0 mean=-186.58700561523438
Energy -190.0, Occurrence 7
(画像)
Energy -189.0, Occurrence 3
(画像)
Energy -189.0, Occurrence 1
(画像)

今度はどうでしょうか?理想的なエネルギーの解が一つだけ出ました。見事に正解です。

ちなみに実行時間はそれなりのGPUでも10分以上かかります。

余談(計算速度の話)

2025年1月現在、TYTANパッケージとHOBOTANパッケージはどちらもHOBOに対応しています。どちらで解いても構いません。

しかし、TYTANが通常のテンソルを使うのに対し、HOBOTANは疎テンソルでデータを扱うように改良されています。TYTANで量子ビット数=5のHOBOをコンパイルすると5次テンソルなので55の要素をもつテンソルになりメモリに乗り切りません(乗るかもしれんけど)。一方のHOBOTANはコンパイルが通ります(式が多いとアニーリング作業は遅いですが)。

ということで(およそ)5次以上のHOBOを扱うならHOBOTANがいいです。

おわりに

なお、Takuzuには10×10や20×20サイズの問題もあります。40次のテンソルは、、無理ですね ( ˘ω˘ )アーヤメヤメ

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