逻辑任务中的互斥
Mutually exclusion in a logic task
有三个朋友 - misha、petya、vova。
姓氏:伊万诺夫、谢苗诺夫、格拉西莫夫。
name(misha).
name(vova).
name(petya).
surname(ivanov).
surname(semyonov).
surname(gerasimov).
misha 不是 gerasimov。
full_name(misha,X) :-
surname(X),
X \= gerasimov.
vova 正在读六年级。格拉西莫夫排在第五位。
如何定义 vova 的姓氏(多个)?
vova的父亲是工程师,ivanov的父亲是锁匠。
father(vova,ingeneer).
father(ivanov,locksmith).
vova的(一)姓怎么定义?
首先我们需要了解每个名字都有一个给定的姓氏这一事实。
is_one_of(Name, [ivanov, semyonov, gerasimov]) :-
member(Name, [misha, vova, petya]).
我们还被赋予了名字和姓氏的特征(学习,父亲),每个特征都有不同的值。这是由以下谓词捕获的。
name_characteristic(vova, studying, sixth_grade).
name_characteristic(vova, father, ingeneer).
surname_characteristic(gerasimov, studying, fifth_grade).
surname_characteristic(ivanov, father, locksmith).
我们还得到gerasimov
is_not
misha
的姓氏。
is_not(misha, gerasimov).
规则 1:Name
不能有 Surname
如果对于某些共同特征,它们的值不同。
is_not(Name, Surname) :-
name_characteristic(Name, Characteristic, Value1),
surname_characteristic(Surname, Characteristic, Value2),
Value1 \= Value2.
规则 2:如果其他可能姓氏中的 none 是 Name
的姓氏,则 Name
必须有 Surname
。
is_(Name, Surname) :-
is_one_of(Name, Surnames),
select(Surname, Surnames, RemainingSurnames),
is_none_of(Name, RemainingSurnames).
is_none_of(_, []).
is_none_of(Name, [Surname | RemainingSurnames]) :-
is_not(Name, Surname),
is_none_of(Name, RemainingSurnames).
查询 is(vova, Surname)
产生:
Surname = semyonov
查询 is_not(Name, Surname)
产生:
Name = misha,
Surname = gerasimov
Name = vova,
Surname = gerasimov
Name = vova,
Surname = ivanov
此解决方案使用 chr
库,它实际上是一种与 Prolog 稍有不同的语言。我现在自己正在学习 CHR,这实际上是我用它编写的第二个程序。它可能与我在邮件列表中获得的版本或改进版本过于相似。所以对它持保留态度。
在我看来,CHR 非常适合那些从很多可能性开始然后取消不良可能性的程序。也许取消可以继续,直到您找到解决方案。这就是这个程序的工作方式,我们生成所有可能的 name/surname 集合,然后使用我们的不可能约束来减少可能的姓氏集合,直到它们收敛到一个,然后我们将它们从其他 name/surname 集合中删除,直到一切都会收敛。
前两行介绍库和我们将使用的约束:
:- use_module(library(chr)).
:- chr_constraint name/1, surnames/1, impossible/2, matched/2, possible/2.
第一个约束生成我们需要走过的可能性。
gen_possibilities @
name(Name), surnames(Surnames)
==> possible(Name, Surnames).
这里的想法是我们已经将姓氏列在一个列表中,我们只是在每个名字和所有可能的姓氏之间创建一个名为 possible
的对。
impossibility @
impossible(Name, Surname), possible(Name, Surnames)
<=> select(Surname, Surnames, Remaining)
| possible(Name, Remaining).
一旦我们被告知某件事是不可能的,我们可以简单地将它从该名字的可能姓氏列表中删除。 select/3
对于从列表中删除单个项目并为您提供余数很有用。我们在这里使用一个守卫,以防姓氏已经不存在于可能的姓氏列表中,这可能发生在应用第四个约束之后。
only_possiblity @
possible(Name, [Surname])
<=> matched(Name, Surname).
一旦可能性列表减少到一个名字,我们就成功匹配了。
remove_matched @
matched(_, Surname), possible(Name, _)
==> impossible(Name, Surname).
如果我们匹配了,那么所有其他名字都不可能使用该姓氏。
如果因为名称已被处理而无法吸收不可能约束,则可以添加但不是必需的额外清理约束:
irrelevant_impossibility @
possible(Name, Surnames)
\ impossible(Name, Surname)
<=> \+ memberchk(Surname, Surnames)
| true.
现在我们可以运行程序了。我冒昧地为 5 年级/6 年级和不同的父亲内联了逻辑。我觉得通过阅读很容易理解意图,而且我不认为通过专门对其建模我会收获很多。感谢@RobertBaron 在他的解决方案中解决问题![=21=]
main :-
name(misha),
name(vova),
name(petya),
surnames([ivanov, semyonov, gerasimov]),
impossible(misha, gerasimov), % stated impossible
impossible(vova, gerasimov), % different grades
impossible(vova, ivanov). % different fathers
执行结果为:
?- main.
name(petya),
name(vova),
name(misha),
surnames([ivanov, semyonov, gerasimov]),
matched(petya, gerasimov),
matched(misha, ivanov),
matched(vova, semyonov).
我相信这满足了摆在您面前的限制条件。
有三个朋友 - misha、petya、vova。 姓氏:伊万诺夫、谢苗诺夫、格拉西莫夫。
name(misha).
name(vova).
name(petya).
surname(ivanov).
surname(semyonov).
surname(gerasimov).
misha 不是 gerasimov。
full_name(misha,X) :-
surname(X),
X \= gerasimov.
vova 正在读六年级。格拉西莫夫排在第五位。 如何定义 vova 的姓氏(多个)?
vova的父亲是工程师,ivanov的父亲是锁匠。
father(vova,ingeneer).
father(ivanov,locksmith).
vova的(一)姓怎么定义?
首先我们需要了解每个名字都有一个给定的姓氏这一事实。
is_one_of(Name, [ivanov, semyonov, gerasimov]) :-
member(Name, [misha, vova, petya]).
我们还被赋予了名字和姓氏的特征(学习,父亲),每个特征都有不同的值。这是由以下谓词捕获的。
name_characteristic(vova, studying, sixth_grade).
name_characteristic(vova, father, ingeneer).
surname_characteristic(gerasimov, studying, fifth_grade).
surname_characteristic(ivanov, father, locksmith).
我们还得到gerasimov
is_not
misha
的姓氏。
is_not(misha, gerasimov).
规则 1:Name
不能有 Surname
如果对于某些共同特征,它们的值不同。
is_not(Name, Surname) :-
name_characteristic(Name, Characteristic, Value1),
surname_characteristic(Surname, Characteristic, Value2),
Value1 \= Value2.
规则 2:如果其他可能姓氏中的 none 是 Name
的姓氏,则 Name
必须有 Surname
。
is_(Name, Surname) :-
is_one_of(Name, Surnames),
select(Surname, Surnames, RemainingSurnames),
is_none_of(Name, RemainingSurnames).
is_none_of(_, []).
is_none_of(Name, [Surname | RemainingSurnames]) :-
is_not(Name, Surname),
is_none_of(Name, RemainingSurnames).
查询 is(vova, Surname)
产生:
Surname = semyonov
查询 is_not(Name, Surname)
产生:
Name = misha,
Surname = gerasimov
Name = vova,
Surname = gerasimov
Name = vova,
Surname = ivanov
此解决方案使用 chr
库,它实际上是一种与 Prolog 稍有不同的语言。我现在自己正在学习 CHR,这实际上是我用它编写的第二个程序。它可能与我在邮件列表中获得的版本或改进版本过于相似。所以对它持保留态度。
在我看来,CHR 非常适合那些从很多可能性开始然后取消不良可能性的程序。也许取消可以继续,直到您找到解决方案。这就是这个程序的工作方式,我们生成所有可能的 name/surname 集合,然后使用我们的不可能约束来减少可能的姓氏集合,直到它们收敛到一个,然后我们将它们从其他 name/surname 集合中删除,直到一切都会收敛。
前两行介绍库和我们将使用的约束:
:- use_module(library(chr)).
:- chr_constraint name/1, surnames/1, impossible/2, matched/2, possible/2.
第一个约束生成我们需要走过的可能性。
gen_possibilities @
name(Name), surnames(Surnames)
==> possible(Name, Surnames).
这里的想法是我们已经将姓氏列在一个列表中,我们只是在每个名字和所有可能的姓氏之间创建一个名为 possible
的对。
impossibility @
impossible(Name, Surname), possible(Name, Surnames)
<=> select(Surname, Surnames, Remaining)
| possible(Name, Remaining).
一旦我们被告知某件事是不可能的,我们可以简单地将它从该名字的可能姓氏列表中删除。 select/3
对于从列表中删除单个项目并为您提供余数很有用。我们在这里使用一个守卫,以防姓氏已经不存在于可能的姓氏列表中,这可能发生在应用第四个约束之后。
only_possiblity @
possible(Name, [Surname])
<=> matched(Name, Surname).
一旦可能性列表减少到一个名字,我们就成功匹配了。
remove_matched @
matched(_, Surname), possible(Name, _)
==> impossible(Name, Surname).
如果我们匹配了,那么所有其他名字都不可能使用该姓氏。
如果因为名称已被处理而无法吸收不可能约束,则可以添加但不是必需的额外清理约束:
irrelevant_impossibility @
possible(Name, Surnames)
\ impossible(Name, Surname)
<=> \+ memberchk(Surname, Surnames)
| true.
现在我们可以运行程序了。我冒昧地为 5 年级/6 年级和不同的父亲内联了逻辑。我觉得通过阅读很容易理解意图,而且我不认为通过专门对其建模我会收获很多。感谢@RobertBaron 在他的解决方案中解决问题![=21=]
main :-
name(misha),
name(vova),
name(petya),
surnames([ivanov, semyonov, gerasimov]),
impossible(misha, gerasimov), % stated impossible
impossible(vova, gerasimov), % different grades
impossible(vova, ivanov). % different fathers
执行结果为:
?- main.
name(petya),
name(vova),
name(misha),
surnames([ivanov, semyonov, gerasimov]),
matched(petya, gerasimov),
matched(misha, ivanov),
matched(vova, semyonov).
我相信这满足了摆在您面前的限制条件。