!!! サイト改修中のため表示が乱れる場合があります(1月末頃まで) !!!
量子アニーリング

21-24. 量子アニーリング(QUBO)で論理クイズ「犯人は誰だ?」を解く

やること

もうQUBOは完全に飽きましたが、今回は論理クイズ「犯人は誰だ?」を解いてみます。

【問題】A, B, C, Dの中に犯人が1人います。犯人は嘘をつき、他の人は本当のことを証言します。犯人は誰でしょうか?

  • A「Dが犯人だ」
  • B「僕は犯人ではない」
  • C「Aは犯人ではない」
  • D「Bが犯人だ」

紙とペンで解く

この手のクイズは犯人が2人いたり一般人は本当のことを言うか嘘を言うか気まぐれだったりしていくらでも複雑になるのですが、シンプルに嘘つきが1人の場合の簡単な解き方を紹介します。

まず、「~が犯人だ」を「~は犯人ではない」に言い換えます。次のように表を用意して、犯人ではないと証言された部分にNoを書き、Noの数を縦に集計します。Noが0個の人が犯人です。

ただ、通常はNoが0個の人はいません。そこで対角成分を無効にして集計します。これは犯人による「自分は犯人ではない」という証言を無効にするためです。これで答えが得られると思います。

QUBO式のおさらい

今回は基本の「n個の量子ビットからm個を1にする」の他に

応用A3「2個の量子ビットが同時に1になったら報酬を与える」

応用A4「2個の量子ビットが同時に0になったら報酬を与える」

このあたりを使用します。

その他のQUBOで設定できる条件式については過去のまとめ記事をご参照ください↓

どうやってアニーリング(QUBO)で解くか?

さっきの問題はシンプルすぎたので、「犯人はA~Cの誰か」「A~Cは犯人ではない」のように複数人指定がある問題でやってみます。

問題(答えは ここ に置いておきます)

  • A「僕とCは犯人ではない」
  • B「犯人はA, C, Dの誰か」
  • C「Eは犯人ではない」
  • D「A, C, Eは犯人ではない」
  • E「犯人はA, Bのどちらか」

まず、各人に5個の量子ビット(A~E)を割り当てて、1になったら犯人とします。

強い条件として、5人の中に犯人が1人いるので「5個の量子ビットから1つだけ1になる」を設定します。

次に、各人の証言を「もし~なら~が成り立つ」というif文を使って言い換えます。「もし自分が正直者なら、自分の証言が成り立つ」という感じです。

  • 「もしAが0なら、A, Cは0」
  • 「もしBが0なら、A, C, Dのどれかが1」
  • 「もしCが0なら、Eは0」
  • 「もしDが0なら、A, C, Eは0」
  • 「もしEが0なら、A, Bのどれかが1」

さらにこれを「◯◯かつ✕✕なら報酬を与える」に言い換えます。

  • A=0かつA=0なら報酬、A=0かつC=0なら報酬
  • B=0かつA=1なら報酬、B=0かつC=1なら報酬、B=0かつD=1なら報酬
  • C=0かつE=0なら報酬
  • D=0かつA=0なら報酬、D=0かつC=0なら報酬、D=0かつE=0なら報酬
  • E=0かつA=1なら報酬、E=0かつB=1なら報酬

例えば、「B=0かつC=1なら報酬」の部分は次のように設定できます。

H = -0.1 * ((1 - B) * C)

証言の重みを1にしてしまうと報酬欲しさに犯人を2人にしてしまうかもしれません。したがってここは弱い条件として重み0.1にします。

コードと結果

量子ビット名がA~Eである点は分かりやすいです。

from pyqubo import Binary
from dwave_qbsolv import QBSolv

#量子ビットを用意する
A = Binary('qA')
B = Binary('qB')
C = Binary('qC')
D = Binary('qD')
E = Binary('qE')

#5人の中に犯人が1人いる(強い条件)
H = 0
H += (A + B + C + D + E - 1)**2

#各人の証言(成り立てば弱い報酬)
H += -0.1 * ((1 - A) * (1 - A))
H += -0.1 * ((1 - A) * (1 - C))

H += -0.1 * ((1 - B) * A)
H += -0.1 * ((1 - B) * C)
H += -0.1 * ((1 - B) * D)

H += -0.1 * ((1 - C) * (1 - E))

H += -0.1 * ((1 - D) * (1 - A))
H += -0.1 * ((1 - D) * (1 - C))
H += -0.1 * ((1 - D) * (1 - E))

H += -0.1 * ((1 - E) * A)
H += -0.1 * ((1 - E) * B)


#コンパイル
model = H.compile()
qubo, offset = model.to_qubo()

#分割サンプリング
response = QBSolv().sample_qubo(qubo, num_repeats=500)

#レスポンスの確認
print('response')
for (sample, energy, occurrence) in response.data():
    print(f'Sample:{list(sample.values())} Energy:{energy} Occurrence:{occurrence}')
response
Sample:[0, 1, 0, 0, 0] Energy:-1.1 Occurrence:501

Bが犯人だと分かりました。解のエネルギーは叶った報酬の数によりますがこれは問題からは予想が難しいと思われます(頑張れば分からなくはないですが)。

さいごに

もっと複雑なif文を表現できるようになりたいですね。「A=0かつB=1なら、C=1またはD=1」のような。中継ビットを使うとできるとかできないとか・・・

リアクションのお願い

「参考になった!」「刺激された!」と思ったらぜひリアクションをしましょう。エンジニアの世界はGive and Takeによって成り立っています。これからも無料で良質な情報にアクセスできるよう、Giveする人への感謝をリアクションで示しましょう!

この記事をシェアする

自身のブログ等で使用する場合は引用を忘れずに!

また、寄付も受け付けています。コーヒー1杯でとても喜びます(*˘︶˘*)

 Amazonでギフト券(アマギフ)を贈る

こちらのリンク から金額を指定してお贈りください。(デフォルトで10000円になっているのでご変更ください)

配送:Eメール
受取人:staffあっとvigne-cla.com
贈り主:あなたのお名前やニックネーム
メッセージ:◯◯の記事が参考になりました。など

のようにご入力ください。見返りはありませんのでご了承ください。

 Amazonで食事券(すかいらーく優待券)を贈る

500円 1000円 2000円 5000円 からお贈りください。

配送:Eメール
受取人:staffあっとvigne-cla.com
贈り主:あなたのお名前やニックネーム
メッセージ:◯◯の記事が参考になりました。など

のようにご入力ください。見返りはありませんのでご了承ください。

 その他、ギフト券やクーポン券をメールで贈る

デジタルのギフト券/クーポン券はメールアドレス(staffあっとvigne-cla.com)までお送りください。受領の返信をいたします。
紙のギフト券/クーポン券は 「郵便物はこちらへ」の住所 まで送付してください。名刺やメールアドレスを同封していただければ受領の連絡をいたします。
余った株主優待券等の処理におすすめです。
いずれも見返りはありませんのでご了承ください。

不明点はSNSでお気軽にご連絡ください

ビネクラのTwitter・Youtubeでコメントをください!


Slack・Discordの場合はこちらの公開グループに参加してShoya YasudaまでDMをください!


※当ブログに関することは何でもご相談・ご依頼可能です。

この記事を書いた人
Yasuda

博士(理学)。専門は免疫細胞、数理モデル、シミュレーション。米国、中国で研究に携わった。遺伝的アルゴリズム信者。物価上昇のため半額弁当とともに絶滅寸前。

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