TL;DR
ゴミ記事なので本当に読まなくていいです.
はじめに
LAWSON presents 麻倉もも Live Tour 2022 “Piacere!” の開催に際して, 全10問のそこそこムズい4択クイズをやることになりました.
初日に真面目にやったら正解数は2問でした. それから数日間それなりにちゃんと考えつつ挑戦しましたが, 7問正解から伸びることはなく, 筆者は麻倉ももさんを理解できていないと痛感しました.
麻倉ももマスターへの道のりは遠いですが, 筆者はコンピュータサイエンスでマスターを取っているので, コンピュータに仕事をさせることにしました.
本当はこれを TL;DR に書くべき
4択クイズへの回答と正解数を制約条件とした制約充足問題を定式化し, SAT ソルバを用いて解く事で正解を導いた.
制約充足問題 (CSP) とは?
自分の修論に書いてるから引用するのが楽だなと思いつつ
こんな感じ. 要はいくつかの変数からなる等式とか不等式とかを全て満たすように変数に値を割り当てられるか判定する問題.
例) 整数変数 について, 次の制約式
を満たす値は存在するか?答えは Yes である ().
充足可能性問題 (SAT) とは?
かなーりめちゃくちゃ雑に言えば2進数の変数に限定した制約充足問題である.
雑に全探索すると 個の変数と 個の制約式からなる SAT 問題は 回の探索が必要となるが, この世の中にはもっと高速に解を探索するソルバがいっぱい存在する.
https://jssst-ppl.org/workshop/2017/slides/ppl2017_c4_soh.pdf
使用ツール
制約充足ソルバとして Sugar を用いる.
Sugar は与えられた CSP を SAT にエンコードし, SAT ソルバで解を求め, 解が存在する場合は元の問題の解にデコードするソルバである.
上記の例の問題を Sugar CSP で記述すると以下の通りとなる.
(int x -10 10) (int y -10 10) (eq (+ x y) 3) (eq (+ (* x x) x -6) 0)
実行してみるとこんな感じ.
[f_t_ikt]:$ cat >ex.csp (int x -10 10) (int y -10 10) (eq (+ x y) 3) (eq (+ (* x x) x -6) 0) [f_t_ikt]:$ sugar ex.csp s SATISFIABLE a x 2 a y 1 a
注意すべきなのは, SAT ソルバは「制約を充足する値の割当てが存在するか否か」を判定するものであり, 上記の例のように複数通りの解が存在するとしてもすべての解を求めるわけではない.
また, SAT ソルバは MiniSat を用いる.
いないと思うけど試してみたい方には以下の記事が参考になる.
SATソルバーMiniSatとSugarを導入 - Qiita
余談だが, 筆者は学生時代にある問題の解が存在しないことを証明するために, 様々な SAT ソルバを試して悪戦苦闘していた.
定式化してみる
そういうわけなので, 変数と制約式を定義すれば解ける!簡単!
① 各問題の選択肢に対応する変数を定義する.
クイズの問題数を , 選択肢の数を とする.
② 「選択肢は各問題で1つのみが正解となる」という制約を追加.
③ 制約式を定義するためにクイズに適当に答え, 解答内容と正解数をメモる.
より確実に絞り込むために, 全部1番目のとき, 2番目のとき, 3番目のときの正解数も調べておいた. つまりこれで3日消費している.
④ いい感じに溜まってきたら制約式をドーンと追加.
クイズに挑戦した回数をとする (らしい).
として, 以下の制約を追加.
式で書くと何だこれと思うような見た目だが, 要はすべての試行に対して, 選んだ選択肢で何問正解したかということを表現しているだけ. 各変数に0か1を割り当てて矛盾が生じなければ, 1となった変数に対応する選択肢が正解となる, かもしれない.
こんだけ?はい.
⑤ Sugar CSP で記述して解かせる.
手で書くのはめんどくさいので, 退屈なことはPython にやらせよう.
for i in range(1,11): for j in range(1,5): print(f"(int x_{i}_{j} 0 1)") for i in range(1,11): print("(eq (+",end="") for j in range(1,5): print(f" x_{i}_{j}",end="") print(") 1)") while True: s = [] try: s = input().split() except: break print("(eq (+",end="") for i in range(10): print(f" x_{i+1}_{s[i]}",end="") print(f") {s[-1]})")
あとは任せた! 1秒ほどで Sugar くん (というか MiniSat くん) がゴリゴリに探索してそれっぽい解を吐き出す.
⑥ 麻倉ももマスターの称号を手に入れる.
頭を使わないために頭を使うのが好きです. これは使ったうちには入りません.
アホ
あろうことか福岡公演の日にメモを取り間違えて一生 UNSAT を吐き続けていた. メモも取れないしクイズもできないアホと申します.
まとめ
4択クイズの解答状況を制約として, CSP を定式化し, SAT ソルバを用いて解く方法を提案した. 筆者の解答状況にはばらつきがあったからか, 無事に正解となる一意解を出すことに成功した.
考察
麻倉ももさんかわいい.
むすびに
これ全然学部レベルです.