カロタンパズルをAlloyで解く
今日、twitterで @mr_konn さんがこのような発言をなされました。
……
ほほぅ……
……
というのはウソですが、これくらいの論理パズルが向かないってことはないだろー。
と思い、解いてみました。
ちなみに、カロタンパズルはこんなの(こちらから引用)。
カロタンは奇妙な癖のある種族です。男は常に真実を語り、女はいちどきに 2 つの真実は言わない、あるいは、いちどきに 2 つの嘘は言わないというものです。
ある人類学者(彼をウォルフと呼びましょう)が彼らの研究を始めました。ウォル フはまだ、カロタンの言葉を知りません。ある日、カロタンのカップル(異性)と その子どものキビと出会いました。ウォルフはキビに「きみは男の子?」とたず ねました。キビはカロタン語で答えたので、ウォルフには分りませんでした。
ウォルフは両親(英語を知っている)に説明を求めました。ひとりが、「キビは、 自分は男の子だといっている」と言いもうひとりが、「キビは女の子。キビは嘘 をついた」と付け加えました。
この両親の性別とキビの性別をあててください。
abstract sig カロタン {
性別: 男か女か,
発言1: Prop,
発言2: lone Prop
}
{
// 男なら常に真実を語る
性別 in 男性 => 発言1.真偽 in ホント and (some 発言2 =>発言2.真偽 in ホント)
// 女はどっちかホントでどっちかがウソ
else some 発言2 => 発言1.真偽 != 発言2.真偽
}
enum 男か女か { 男性, 女性 }
one sig キビ extends カロタン {}
{
// 自分を男といったか、女といったかのどちらか
発言1 in キビは男の子 + キビは女の子
no 発言2
}
one sig 親A extends カロタン {}
{
発言1 in キビは男の子と言っている
no 発言2
}
one sig 親B extends カロタン {}
{
発言1 in キビは女の子
some 発言2
発言2 in キビはウソをついている
}
fact 親の性別はたぶん別々 {
親A.性別 != 親B.性別
}
/** 皆さんの発言(命題)*/
abstract sig Prop {
真偽: ホントかウソか
}
enum ホントかウソか { ウソ, ホント }
one sig キビは男の子 extends Prop {}
{
真偽 in ホント <=> キビ.性別 in 男性
}
one sig キビは女の子 extends Prop {}
{
真偽 in ホント <=> キビ.性別 in 女性
}
one sig キビは男の子と言っている extends Prop {}
{
真偽 in ホント <=> キビ.発言1 in キビは男の子
}
one sig キビはウソをついている extends Prop {}
{
真偽 in ホント <=> キビ.発言1.@真偽 in ウソ
}
run { } [追記] ミソは、カロタン親子の発言をどうモデル化するかです。
特に、「キビが男の子である」という事実と、「キビは(自分を)男の子と(あるいは女の子と)言った」という事実と、更にそれを言明する親の発言とを、ナイーブにAlloyの制約式にしてしまうと同列にモデル化できないわけです。
得てして高階論理で書きたくなるかもしれませんが、Alloyは一階論理しか扱えません(mr_konnさんが「向かない」と思ったのも、たぶんこの辺り)。
その解決策として、ここでは各発言(命題)を述語やファクトでなく、シグネチャでモデル化してます。こうすることで、各発言やその真偽みたいなものを、Alloyのモデル上で統一的に扱えるようにしているのです。[/追記]


