STRIPS Planner无限循环

时间:2016-12-26 00:42:25

标签: prolog failure-slice

我在Prolog中定义了一个STRIPS Planner来解决逻辑问题。经过一些其他更简单问题的试用后,我开始研究它是否可以解决更复杂的问题。我给了他一个STRIPS定义的peg纸牌,英文版,考虑到我们不能进行对角移动,最后一个球最终会在棋盘的中心进行尝试,程序会进入循环。问题在于:https://en.wikipedia.org/wiki/Peg_solitaire

这是我的解决方案:

%%%%%%%%%%%%%%%%%%%%%% PLAN %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

accao(nome : move(Xi,Yi,Xf,Yf),
condicoes : [empty(Xf,Yf),ball(Xi,Yi), ball(Xm,Ym)],
efeitos : [ball(Xf,Yf), -ball(Xm,Ym),-ball(Xi,Yi), empty(Xi,Yi), empty(Xm,Ym), -empty(Xf,Yf)],
restricoes : [abs(Xf-Xi)+abs(Yf-Yi)=:=2, abs(Xf-Xi)*abs(Yf-Yi)=:=0, Xi=<Xm, Xm=<Xf, Yi=<Ym, Ym=<Yf]).

inicial([empty(5,5), ball(1,4), ball(1,5), ball(1,6), 
        ball(2,4), ball(2,5), ball(2,6),
        ball(3,4), ball(3,5), ball(3,6),
 ball(4,1), ball(4,2), ball(4,3),ball(4,4), ball(4,5),              ball(4,6),ball(4,7), ball(4,8), ball(4,9),
 ball(5,1), ball(5,2), ball(5,3),ball(5,4),            ball(5,6),ball(5,7), ball(5,8), ball(5,9),
 ball(6,1), ball(6,2), ball(6,3),ball(6,4), ball(6,5), ball(6,6),ball(6,7), ball(6,8), ball(6,9),
        ball(7,4), ball(7,5), ball(7,6), 
        ball(8,4), ball(8,5), ball(8,6),
        ball(9,4), ball(9,5), ball(9,6)]).

objectivos([ball(5,5), empty(1,4), empty(1,5), empty(1,6), 
                    empty(2,4), empty(2,5), empty(2,6),
                    empty(3,4), empty(3,5), empty(3,6),
empty(4,1), empty(4,2), empty(4,3),empty(4,4), empty(4,5), empty(4,6),empty(4,7), empty(4,8), empty(4,9),
empty(5,1), empty(5,2), empty(5,3),empty(5,4),            empty(5,6),empty(5,7), empty(5,8), empty(5,9),
empty(6,1), empty(6,2), empty(6,3),empty(6,4), empty(6,5), empty(6,6),empty(6,7), empty(6,8), empty(6,9),
                    empty(7,4), empty(7,5), empty(7,6), 
                    empty(8,4), empty(8,5), empty(8,6),
                    empty(9,4), empty(9,5), empty(9,6)]).



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%




%%%%%%%%%%%%%%%%%%%%%% PRINT FUNCTION %%%%%%%%%%%%%%%%%%%%%%%%%%%
printExec([]).
printExec([A,E|T]) :- write("Action performed: "),
                  write(A),nl,
                  write("Situation: "),
                  write(E),nl,
                  printExec(T).

 writeExec([I|T]):- write("Initial Situation"),
               write(I),nl,
               printExec(T),
               write("Goal: "),
               objectivos(G),
               write(G),
               write(" satisfied."),nl.
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%




 %%%%%%%%%%%%%%%%%%%% AUXILIAR FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%
 member(E,[E|_]).
 member(E,[_|T]):-member(E,T).

 sub([],_).
 sub([H|T],L):- member(H,L),
           sub(T,L).

 remove(_,[],[]):-!.
 remove(E1, [E2|T], T):- E1 == E2, !. 
 remove(E,[H|T1],[H|T2]):- remove(E,T1,T2).

 add(E,[],[E]):-!.
 add(E1,[E2|T],[E1,E2|T]):- E1 \== E2, !. 
 add(E,[H|T1],[H|T2]):-add(E,T1,T2).

 effects([],S,S).
 effects([-H|Fx],S,N) :-!, 
                   remove(H,S,NS), 
                   effects(Fx,NS,N).
 effects([H|Fx],S,N) :- !, 
                   add(H,S,NS), 
                   effects(Fx,NS,N).

 restriction([]).                                              
 restriction([R|T]) :- R,
                  restriction(T).            
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%




 %%%%%%%%%%%%%%%%%%%%%%% PLAN EXECUTE %%%%%%%%%%%%%%%%%%%%%%%%%%%
 planExecute(P):-testPlan(P,E),writeExec(E),!.

 satisfiedGoal(E):- objectivos(Fn),!,
               sub(Fn,E).

 testPlan(Plan,[I|Exec]) :- inicial(I),              
                       testPlan(Plan,I,Exec,Fn),
                       satisfiedGoal(Fn).   

 testPlan([],Fn,[],Fn).
 testPlan([H|T],S,[H,N|Exec],Fn) :- accao(nome:H, condicoes:C,efeitos:E, restricoes:R), 
                               sub(C,S), 
                               effects(E,S,N), 
                               restriction(R), 
                               testPlan(T,N,Exec,Fn).
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%




 %%%%%%%%%%%%%%%%%%%%%%% FIND PLAN %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 plano(P) :- progressivePlan(P, 0).

 progressivePlan(P, N) :- createPlan(P,_,0,N).
 progressivePlan(P, N) :- \+ createPlan(P,_,0,N),
                     NewN is N + 1, 
                     progressivePlan(P, NewN).

 createPlan(Plan,[I|Exec],N,Max) :- inicial(I),       
                               createPlan(Plan,I,Exec,Fn,N,Max),
                               satisfiedGoal(Fn).       

 createPlan([],Fn,[],Fn,Max,Max):- !.
 createPlan([H|T],S,[H,N|Exec],Fn,Acc, Max) :- accao(nome:H, condicoes:C, efeitos:E, restricoes:R), 
                                          sub(C,S), 
                                          effects(E,S,N),
                                          restriction(R),
                                          NewAcc is Acc+1, 
                                          createPlan(T,N,Exec,Fn,NewAcc, Max). 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%`

我尝试通过做一两个动作来简化目标,这个动作适用于一个动作,当两个动作不相互矛盾时,就像将一个大理石移动到已经移动过的大理石上一样,当他们这样做时,用两个动作进入循环,就像所说的目标一样:

objectivos([球(4,5),空(3,5),空(5,5),空(6,5)])。

我尝试过跟踪和调试,但我似乎无法找到问题,虽然我认为它位于问题的表述而不是Planner本身。任何想法?

1 个答案:

答案 0 :(得分:0)

您的代码中至少存在一个逻辑错误,并且可以进行一些简单的性能调整。这为您的问题提供了部分解决方案。

首先,对于逻辑错误:目标objectivos([ball(4,5), empty(3,5), empty(5,5), empty(6,5)])的预期解决方案似乎是计划P = [move(3, 5, 5, 5), move(6, 5, 4, 5)]。但是,根据您对restricoes的定义,这些举措中的第二步是不合法的:对于此移动,您有Xi = 6Xf = 4以及需要6 =< Xm和{{1}的条件},但这是不可能的。这些约束的想法是确保Xm <= 4在移动中的其他两个球之间。这是另一种确保这一点的配方:

ball(Xm,Ym)

这也排除了以前在跟踪代码时让我困惑的案例:以前使restricoes : [abs(Xf-Xi)+abs(Yf-Yi) =:= 2, abs(Xf-Xi)*abs(Yf-Yi) =:= 0, abs(Xf-Xm)+abs(Yf-Ym) =:= 1, abs(Xi-Xm)+abs(Yi-Ym) =:= 1] 合法是合法的。

其次,要提高效果,请在ball(Xi,Yi) = ball(Xm,Ym)的定义中交换目标effects(E,S,N)restriction(R)。以前你在检查合法性之前计算了移动的效果!因为策划者提出的大多数动作都是非法的,这浪费了很多时间。

然后,为了使整个事情更好用,您可以将createPlan/6plano/1的定义更改为:

createPlan/4

这比之前的定义更简单,而且行为也更好。我们可以通过一个完整的计划来检查它是否合法,或者只是传入一个固定长度的列表来询问该长度的计划是什么:

 plano(P) :-
     length(P, PlanLength),
     createPlan(P, _, 0, PlanLength).

 createPlan(Plan,[I|Exec],N,Max) :- inicial(I),
                               N =< Max,
                               createPlan(Plan,I,Exec,Fn,N,Max),
                               satisfiedGoal(Fn).

根据您的定义,这将继续循环并计算?- P = [_,_], plano(P). P = [move(3, 5, 5, 5), move(6, 5, 4, 5)] ; false. % no more solutions 计数器,搜索不存在的其他解决方案。

通过这种表述,我们可以切换到您的大目标,并尝试寻找解决方案(这部分特定于SWI-Prolog):

Max

此时我不得不打断搜索,它变得太慢了。当然可以进行更多的调整,我可能会继续关注它。