我正在测试Prolog测试矛盾的能力。为了测试这个,我想出了以下场景:
有三名嫌疑人:a,b和c,他们正在接受审判,其中一名嫌犯是有罪的,其余的是无辜的。
案件的事实是,
(事实1)如果a是无辜的,那么c必须是有罪的,并且
(事实2)如果a是无辜的,则c必须是无辜的。
对谁有罪的答案是怀疑'a',因为怀疑'c'不能既有罪又无辜。以下代码是我的实现:
who_guilty(Suspects) :-
% Knowledge Base
Suspects=[[Name1,Sentence1],
[Name2, Sentence2],
[Name3,Sentence3]],
% Suspects
Names=[a,b,c],
Names=[Name1,Name2,Name3],
% One Is Guilty
Sentences=[innocent,innocent,guilty],
permutation(Sentences,[Sentence1,Sentence2,Sentence3]),
% If A Innocent Then C Is Guilty
(member([a,innocent],Suspects) -> member([c,guilty], Suspects) ; true),
% If A Innocent Then C Is Innocent
(member([a,innocent],Suspects) -> member([c,innocent], Suspects) ; true).
要获得Prolog的答案,需要运行的查询是who_guilty(S)。然后Prolog将输出两个相同的答案:
S = [[a,有罪],[b,无辜],[c,无辜]]?
S = [[a,有罪],[b,无辜],[c,无辜]]
我的核心问题是,如何才能获得一个答案,而不是两个答案?
答案 0 :(得分:1)
使用clpb:
:- use_module(library(clpb)).
% 0 means guilty
% 1 means innocent
guilty(A,B,C) :-
% only one is guilty
sat(~A * B * C + A * ~B * C + A * B * ~C),
% Fact 1
sat(A =< ~C),
% Fact 2
sat(A =< C).
?- guilty(A,B,C).
A = 0,
B = C, C = 1.
答案 1 :(得分:1)
紧凑的解决方案,遵循您对表达事实的直觉。
who_guilty(L) :-
select(guilty,L,[innocent,innocent]),
( L = [innocent,_,_] -> L = [_,_,guilty] ; true ),
( L = [innocent,_,_] -> L = [_,_,innocent] ; true ).
的产率:
?- who_guilty(L).
L = [guilty, innocent, innocent] ;
false.
感谢joel76(+1),这是一个基于库的更合成的解决方案(clpb)
?- sat(card([1],[A,B,C])*(~A =< ~C)*(~A =< C)).
A = 1,
B = C, C = 0.
1意味着有罪......
答案 2 :(得分:0)
使用clpfd库,您可以轻松解决此问题:
solve(L):-
L = [A,B,C], %0 innocent, 1 guilty
L ins 0..1,
A + B + C #= 1, %one is guilty
A #= 0 #==> C #= 1, %if a is innocent then c must be guilty
A #= 0 #==> C #= 0, %if a is innocent then c must be innocent
label(L).
?- solve(L).
L = [1, 0, 0]
答案 3 :(得分:0)
你应该添加一个新的谓词,检查某人是否无辜和有罪,然后对是否存在矛盾的结果回答是。您正在给Prolog两个事实,这意味着对查询有两个正确的结论。你真正的问题是&#34;我是否有相互矛盾的事实?&#34;,这意味着A和NOT A同时都是真的。 contradiction(A, not(A)).
所有真理都是普遍存在的,你提出了两个与Prolog相矛盾的真理,所以两者都适用于Prolog。