Men*_*sch 11 logic artificial-intelligence prolog axiom clpfd
如何使用谓词包含(b,l,t)正确地写出空(b,t)-action的效果公理如果桶b在时间t保持l升水,则谓词评估为True.
空(b,t):在时间t完全清空桶b.在时间t + 1可以看到转移的影响
转移(b,b',t):尽可能多的水从桶b转移到桶b',而不会在时间t溢出任何开始.在时间t + 1可以看到转移的影响.
铲斗1装满水并容纳7升水.铲斗2是空的并且容纳3升.目标状态是b2含有1升水.
我会说正确的解决方案是:
to any b,t,l( empty(b,t) -> contains(b,l,t))
Run Code Online (Sandbox Code Playgroud)
这是正确的还是我应该将升的数量设置为l = 5,例如?
对于此问题,不需要显式时间,因此我们将历史记录表示为操作列表.另一方面,您需要明确表示系统的状态,即三个存储桶的当前内容.原因是Prolog数据结构(即术语)一旦创建就无法更改.由于存在许多无意义的术语,因此最好先通过is_type/1谓词定义数据类型.因为你将在某些时候使用算术(当你将水从一个桶倒入另一个桶时),我将使用算术约束而不是古代is/2谓词.
:- use_module(library(clpfd)).
Run Code Online (Sandbox Code Playgroud)
首先我们说有3个桶,由原子b1,b2和b3表示:
is_bucket(b1).
is_bucket(b2).
is_bucket(b3).
Run Code Online (Sandbox Code Playgroud)
然后我们需要定义我们的状态.我们只使用一个术语buckets/3,其中第一个参数保持b1的容量,同样适用于其他两个.
is_state(buckets(X,Y,Z)) :-
% each bucket contains at least 0 liters
[X,Y,Z] ins 0 .. sup.
Run Code Online (Sandbox Code Playgroud)
所有容器可能不会变为负数,因此我们将其域设置为从零到(正)无穷大.
现在有什么动作?到目前为止,你描述了清空和倾倒:
is_action(empty(B)) :-
is_bucket(B).
is_action(pour(From, To)) :-
is_bucket(From),
is_bucket(To).
Run Code Online (Sandbox Code Playgroud)
要清空水桶,我们只需知道哪一个.如果我们将水从一个倒到另一个,我们需要描述两者.由于我们已经有一个描述存储桶的谓词,因此我们可以将规则称为"如果From和To是存储桶,那么pour(From, To)就是一个操作.
现在我们需要解释一个动作如何改变一个状态.这是旧州,新州之间的关系,因为我们想知道会发生什么,也就是历史.
% initial state
state_goesto_action(buckets(7,5,3), buckets(7,5,3), []).
Run Code Online (Sandbox Code Playgroud)
初始状态的转换不会改变任何内容并且具有空的历史记录([]).
% state transitions for moving
state_goesto_action(buckets(X,Y,Z), buckets(0,Y,Z), [empty(b1) | History]) :-
state_goesto_action(_S0, buckets(X,Y,Z), History).
Run Code Online (Sandbox Code Playgroud)
这条规则可以理解为"如果我们有一个动作,从一些国家的未来_S0导致国家buckets(X,Y,Z)的一些History,那么我们就可以进行empty(b1)下一步的行动,我们将达到国家buckets(0,Y,Z)".换句话说,更新状态并将操作添加到历史记录之前.对称规则适用于其他存储桶:
state_goesto_action(buckets(X,Y,Z), buckets(X,0,Z), [empty(b2) | History]) :-
state_goesto_action(_S0, buckets(X,Y,Z), History).
state_goesto_action(buckets(X,Y,Z), buckets(X,Y,0), [empty(b3) | History]) :-
state_goesto_action(_S0, buckets(X,Y,Z), History).
Run Code Online (Sandbox Code Playgroud)
我们如何检查这是否有意义?让我们看看长度为2的历史:
?- state_goesto_action(_,S1,[H1,H2]).
S1 = buckets(0, 3, 5),
H1 = H2, H2 = empty(b1) .
Run Code Online (Sandbox Code Playgroud)
好的,如果两个动作都是empty(b1),那么第一个桶是空的而其他桶是未触及的.让我们看看进一步的解决方案:
S1 = buckets(0, 0, 5),
H1 = empty(b1),
H2 = empty(b2) ;
S1 = buckets(0, 3, 0),
H1 = empty(b1),
H2 = empty(b3) ;
S1 = buckets(0, 0, 5),
H1 = empty(b2),
H2 = empty(b1) ;
S1 = buckets(7, 0, 5),
H1 = H2, H2 = empty(b2) ;
S1 = buckets(7, 0, 0),
H1 = empty(b2),
H2 = empty(b3) ;
S1 = buckets(0, 3, 0),
H1 = empty(b3),
H2 = empty(b1) ;
S1 = buckets(7, 0, 0),
H1 = empty(b3),
H2 = empty(b2) ;
S1 = buckets(7, 3, 0),
H1 = H2, H2 = empty(b3).
Run Code Online (Sandbox Code Playgroud)
看起来我们得到了清空水桶的所有可能性(仅此而已:-)).现在您需要添加从一个桶倒到另一个桶的规则.祝好运!
(编辑:拼写错误,第二条规则中的错误)