使用 prolog 在信念网络中进行推理
reasoning in belief network with prolog
我的期末项目在 Prolog 中遇到问题。我尝试使用贝叶斯网络和序言来推理火车系统中断模式。我的贝叶斯网络如下图所示:
Bayesian Network Picture
我阅读了 Ivan Bratko 的 Prolog Programming for Articial Intellegent 3rd addtion 一书,我发现了如何在 Prolog 中表示贝叶斯网络。
您可以看到 Prolog 代码如下:
%here is the rule for reasoning in bayesian network from the book :
prob([X|Xs],Cond,P) :- !,
prob(X, Cond, Px),
prob(Xs, [X|Cond], PRest),
P is Px * PRest.
prob([],_,1):- !.
prob(X, Cond, 1) :-
member(X, Cond),!.
prob(X, Cond, 0) :-
member(\+ X, Cond), !.
prob(\+ X, Cond, P) :- !,
prob(X, Cond, P0),
P is 1-P0.
%Use Bayes rule if condition involves a descendant of X
prob(X, Cond0, P):-
delete(Y, Cond0, Cond),
predecessor(X,Y),!, %Y is a descendant of X
prob(X, Cond, Px),
prob(Y, [X|Cond], PyGivenX),
prob(Y, Cond, Py),
P is Px * PyGivenX / Py. %Assuming Py > 0
%Cases when condition does not involves a descendant
prob(X, Cond, P) :-
p(X, P),!. % X a root cause - its probability given
prob(X, Cond, P) :- !,
findall((CONDi, Pi), p(X,CONDi,Pi), CPlist), %Condition on parents
sum_probs(CPlist, Cond, P).
sum_probs([],_,0).
sum_probs([(COND1,P1) | CondsProbs], COND, P) :-
prob(COND1, COND, PC1),
sum_probs(CondsProbs, COND, PRest),
P is P1 * PC1 + PRest.
predecessor(X, \+ Y) :- !, %Negated variable Y
predecessor(X,Y).
predecessor(X,Y) :-
parent(X,Y).
predecessor(X,Z) :-
parent(X,Y),
predecessor(Y,Z).
member(X, [X|_]).
member(X, [_|L]) :-
member(X,L).
delete(X, [X|L], L).
delete(X, [Y|L], [Y|L2]) :-
delete(X, L, L2).
这里还有一些贝叶斯网络在prolog中的实现信息(因为太长所以只加了一部分):
p(static_inverter, [overhead_line], 0.005050505).
p(static_inverter, [\+ overhead_line], 0.000213767).
p(ac, [static_inverter], 0.5).
p(ac, [\+ static_inverter], 0.029749692).
p(door, [compressor], 0.026315789).
p(door, [\+ compressor], 0.006821).
p(horn, [compressor], 0.026315789).
p(horn, [\+ compressor], 0.000206697).
p(brake, [compressor], 0.026315789).
p(brake, [\+ compressor], 0.004340637).
p(switch, [signal, service_table], 0.5).
p(switch, [\+ signal, service_table], 0.346153846).
p(switch, [signal, \+ service_table], 0.054098361).
p(switch, [\+ signal, \+ service_table], 0.041364933).
p(overhead_line, [fire, fallen_tree], 0.5).
p(overhead_line, [fire, \+ fallen_tree], 0.005882353).
p(overhead_line, [\+ fire, fallen_tree], 0.304878049).
p(overhead_line, [\+ fire, \+ fallen_tree], 0.038850284).
p(pantograph, [overhead_line, fallen_tree], 0.038461538).
p(pantograph, [overhead_line, \+ fallen_tree], 0.002702703).
p(pantograph, [\+ overhead_line, fallen_tree], 0.017241379).
p(pantograph, [\+ overhead_line, \+ fallen_tree], 0.00440955).
您可能会在 here
上看到完整的代码
不幸的是,我在尝试推理某些概率时遇到了问题,例如:
?- prob(series, [horn], P).
?- prob(series, [brake], P).
?- prob(pantograph, [overhead_line], P).
据说错误是这样的:
ERROR: Arithmetic: evaluation error: `zero_divisor'
ERROR: In:
ERROR: [27] _43124 is 0.045454539961694*0/0
ERROR: [25] prob([compressor],[\+brake,traction|...],_43166) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:2
ERROR: [24] sum_probs([(...,0.026315789),...],[\+brake,traction|...],_43216) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:37
ERROR: [22] prob([horn,door|...],[\+brake,traction|...],_43278) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:2
ERROR: [21] prob([\+brake,horn|...],[traction,wiper|...],_43334) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:3
ERROR: [20] prob([traction,...|...],[wiper,speedometer|...],_43390) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:3
谁能帮我解决这个错误?提前致谢。
引入安全测试后,
...
prob(Y, Cond, Py),
Py > 0,
P is Px * PyGivenX / Py. %Assuming Py > 0
并更正了您 github 代码中的一个拼写错误和几个 singleton warnings,我得到了这些结果:
?- prob(series, [horn], P).
false.
?- prob(series, [brake], P).
P = 0.086661842800551.
?- prob(pantograph, [overhead_line], P).
false.
所以您现在可以尝试理解为什么代码产生 false
而不是 P = 0.0
...
我明白为什么解释器会得到 zero_divisor 错误的答案,因为当我用 :
查询时
?- prob(series, [horn], P).
?- prob(series, [brake], P).
?- prob(pantograph, [overhead_line], P)
所有这些都按照规则处理:
prob(X, Cond0, P):-
delete(Y, Cond0, Cond),
predecessor(X,Y),!, %Y is a descendant of X
prob(X, Cond, Px),
prob(Y, [X|Cond], PyGivenX),
prob(Y, Cond, Py),
P is Px * PyGivenX / Py. %Assuming Py > 0
而它们应该按照下面的规则进行处理:
prob(X, Cond, P) :-
p(X, P),!. % X a root cause - its probability given
prob(X, Cond, P) :- !,
findall((CONDi, Pi), p(X,CONDi,Pi), CPlist), %Condition on parents
sum_probs(CPlist, Cond, P).
因为查询不涉及X的后代
有什么办法可以区分这两种规则吗?因为我后面还是递归的使用这两个规则?
我已经尝试在 prob(X, Cond0, P)
中添加条件 parent(X, Cond0)
,但是当我查询条件涉及 X 的后代时,答案是错误的
我的期末项目在 Prolog 中遇到问题。我尝试使用贝叶斯网络和序言来推理火车系统中断模式。我的贝叶斯网络如下图所示: Bayesian Network Picture
我阅读了 Ivan Bratko 的 Prolog Programming for Articial Intellegent 3rd addtion 一书,我发现了如何在 Prolog 中表示贝叶斯网络。 您可以看到 Prolog 代码如下:
%here is the rule for reasoning in bayesian network from the book :
prob([X|Xs],Cond,P) :- !,
prob(X, Cond, Px),
prob(Xs, [X|Cond], PRest),
P is Px * PRest.
prob([],_,1):- !.
prob(X, Cond, 1) :-
member(X, Cond),!.
prob(X, Cond, 0) :-
member(\+ X, Cond), !.
prob(\+ X, Cond, P) :- !,
prob(X, Cond, P0),
P is 1-P0.
%Use Bayes rule if condition involves a descendant of X
prob(X, Cond0, P):-
delete(Y, Cond0, Cond),
predecessor(X,Y),!, %Y is a descendant of X
prob(X, Cond, Px),
prob(Y, [X|Cond], PyGivenX),
prob(Y, Cond, Py),
P is Px * PyGivenX / Py. %Assuming Py > 0
%Cases when condition does not involves a descendant
prob(X, Cond, P) :-
p(X, P),!. % X a root cause - its probability given
prob(X, Cond, P) :- !,
findall((CONDi, Pi), p(X,CONDi,Pi), CPlist), %Condition on parents
sum_probs(CPlist, Cond, P).
sum_probs([],_,0).
sum_probs([(COND1,P1) | CondsProbs], COND, P) :-
prob(COND1, COND, PC1),
sum_probs(CondsProbs, COND, PRest),
P is P1 * PC1 + PRest.
predecessor(X, \+ Y) :- !, %Negated variable Y
predecessor(X,Y).
predecessor(X,Y) :-
parent(X,Y).
predecessor(X,Z) :-
parent(X,Y),
predecessor(Y,Z).
member(X, [X|_]).
member(X, [_|L]) :-
member(X,L).
delete(X, [X|L], L).
delete(X, [Y|L], [Y|L2]) :-
delete(X, L, L2).
这里还有一些贝叶斯网络在prolog中的实现信息(因为太长所以只加了一部分):
p(static_inverter, [overhead_line], 0.005050505).
p(static_inverter, [\+ overhead_line], 0.000213767).
p(ac, [static_inverter], 0.5).
p(ac, [\+ static_inverter], 0.029749692).
p(door, [compressor], 0.026315789).
p(door, [\+ compressor], 0.006821).
p(horn, [compressor], 0.026315789).
p(horn, [\+ compressor], 0.000206697).
p(brake, [compressor], 0.026315789).
p(brake, [\+ compressor], 0.004340637).
p(switch, [signal, service_table], 0.5).
p(switch, [\+ signal, service_table], 0.346153846).
p(switch, [signal, \+ service_table], 0.054098361).
p(switch, [\+ signal, \+ service_table], 0.041364933).
p(overhead_line, [fire, fallen_tree], 0.5).
p(overhead_line, [fire, \+ fallen_tree], 0.005882353).
p(overhead_line, [\+ fire, fallen_tree], 0.304878049).
p(overhead_line, [\+ fire, \+ fallen_tree], 0.038850284).
p(pantograph, [overhead_line, fallen_tree], 0.038461538).
p(pantograph, [overhead_line, \+ fallen_tree], 0.002702703).
p(pantograph, [\+ overhead_line, fallen_tree], 0.017241379).
p(pantograph, [\+ overhead_line, \+ fallen_tree], 0.00440955).
您可能会在 here
上看到完整的代码不幸的是,我在尝试推理某些概率时遇到了问题,例如:
?- prob(series, [horn], P).
?- prob(series, [brake], P).
?- prob(pantograph, [overhead_line], P).
据说错误是这样的:
ERROR: Arithmetic: evaluation error: `zero_divisor'
ERROR: In:
ERROR: [27] _43124 is 0.045454539961694*0/0
ERROR: [25] prob([compressor],[\+brake,traction|...],_43166) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:2
ERROR: [24] sum_probs([(...,0.026315789),...],[\+brake,traction|...],_43216) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:37
ERROR: [22] prob([horn,door|...],[\+brake,traction|...],_43278) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:2
ERROR: [21] prob([\+brake,horn|...],[traction,wiper|...],_43334) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:3
ERROR: [20] prob([traction,...|...],[wiper,speedometer|...],_43390) at d:/kuliah/tugas/semester 8/for ta/[2] ta program/reasoningtraindisruptionwithprolog/rules.pl:3
谁能帮我解决这个错误?提前致谢。
引入安全测试后,
...
prob(Y, Cond, Py),
Py > 0,
P is Px * PyGivenX / Py. %Assuming Py > 0
并更正了您 github 代码中的一个拼写错误和几个 singleton warnings,我得到了这些结果:
?- prob(series, [horn], P).
false.
?- prob(series, [brake], P).
P = 0.086661842800551.
?- prob(pantograph, [overhead_line], P).
false.
所以您现在可以尝试理解为什么代码产生 false
而不是 P = 0.0
...
我明白为什么解释器会得到 zero_divisor 错误的答案,因为当我用 :
查询时?- prob(series, [horn], P).
?- prob(series, [brake], P).
?- prob(pantograph, [overhead_line], P)
所有这些都按照规则处理:
prob(X, Cond0, P):-
delete(Y, Cond0, Cond),
predecessor(X,Y),!, %Y is a descendant of X
prob(X, Cond, Px),
prob(Y, [X|Cond], PyGivenX),
prob(Y, Cond, Py),
P is Px * PyGivenX / Py. %Assuming Py > 0
而它们应该按照下面的规则进行处理:
prob(X, Cond, P) :-
p(X, P),!. % X a root cause - its probability given
prob(X, Cond, P) :- !,
findall((CONDi, Pi), p(X,CONDi,Pi), CPlist), %Condition on parents
sum_probs(CPlist, Cond, P).
因为查询不涉及X的后代
有什么办法可以区分这两种规则吗?因为我后面还是递归的使用这两个规则?
我已经尝试在 prob(X, Cond0, P)
中添加条件 parent(X, Cond0)
,但是当我查询条件涉及 X 的后代时,答案是错误的