0

我有一个 prolog 计划器,它可以正确处理一个主要问题,即当时只生成一个计划。该计划是正确的,但对于我的申请,我真的需要制定所有可能的计划。

plan(State, Goal, _, Moves) :-  subsetB(Goal,State),
                            write('moves are'), nl,
                            reverse_print_stack(Moves).
plan(State, Goal, Been_list, Moves) :-
                            effects(Name, [Preconditions, Add,Delete]),  //a list of of rules governing the domain
                            conditions_met(Preconditions, State),       //checks if all preconditions are present in the state
                            change_state(State, Add,Delete, Child_state), //add predicates from Add list, removes predicates in the Delete list and stores result in Child_state
                            \+(member_state(Child_state, Been_list)),     //checks if Child_state hasn't been previously visited
                            stack(Child_state, Been_list, New_been_list),
                            stack(Name, Moves, New_moves),
                    plan(Child_state, Goal, New_been_list, New_moves).


change_state(S, [],[], S).
change_state(S, [], Delete, S_new) :-   change_state(S, [],[], S2),
                                    apply_del(Delete, S2, S_new).
change_state(S, Add,Delete, S_new) :-   change_state(S, [], Delete, S2),
                                    apply_add(Add, S2, S_new).


apply_add([],State,State).
apply_add([activate(App)|Rest],State,InterimState) :-apply_add(Rest,State,S2),find_stones(App,State,StonesToBeActivated), make_active(StonesToBeActivated,S2, InterimState).
apply_add([First|Rest],State,InterimState) :- apply_add(Rest,State,S2),add_element(First, S2, InterimState).


apply_del([],InterimState,InterimState).
apply_del([First|Rest],InterimState,NewState) :- apply_del(Rest, InterimState,S2),del_element(First, S2, NewState).



subsetB([],_).
subsetB([F|R],S) :- member(F,S),subsetB(R,S).



%dropping a stone inside app1 
 effects(drop(X,app1),                     %action
   [[stone(X),active(X)],                  %preconditions
    [in(app1,X)],                          %postconditions : add list
    [active(X)]]).                         %postconditions : delete list

go(S,G,AllPlans):- findall(Moves, plan(S,G,[S],Moves),AllMoves).

conditions_met(P, S) :- subsetB(P, S).

示例调用 go([in(app1,s1),stone(s2),active(s2),stone(s3),active(s3)],[in(app1,s1),in(app1,s3),in( app1,s2)],AllPlans)。

回答:

drop(s2,app1) drop(s3,app1) //正确 _2368 _2366 _2364 _2362 _2360 _2358 _2356 _2354 _2352 _2350 _2348 _2346 _2344 _2342 _2340 _2338 _2336 等...无限

4

1 回答 1

2

要找到目标的所有解决方案,请查看bagof 或 findall。还是我错过了什么?

像这样:

?- findall(Moves, plan(State, Goal, _, Moves), AllMoves).

这些谓词的整个想法是,您说出要收集哪些参数并获取该谓词下所有可能的实例化的列表。从这个意义上说,您通常有一个“返回”值(一个用结果实例化的参数),然后您可以查看或打印它,而不是在找到解决方案的谓词中显式打印它。

一个简单的例子:

foo(1). foo(2). foo(3). foo(4). foo(5). foo(6).
bar(R) :- foo(A), A mod 2 =:= 0.

findall(R, bar(R), Even).

现在递归:它是如何工作的?您不能在同一谓词的不同子句之间共享变量。例如,这是错误的:

baz(0, B).
baz(X, B) :- X0 is X - 1, B1 is B + 1, baz(X0, B1).

因为 B 是 的第一个子句中的单例变量baz。相反,您可以这样做:

baz(0, B, B).
baz(X, B, Result) :- X0 is X - 1, B1 is B + 1, baz(X0, B1, Result).

您现在可以调用:

?- baz(10, 2, Result).
Result = 12

但是在第一个答案之后您仍然会遇到问题。

你得到一个正确的计划可能是因为第一个子句plan不符合 的要求subsetB,然后你得到第二个子句。在那里,您制作了一个在其尾部有一个自由变量的Move,但这还不是问题。然而,问题是,当您找到第一个解决方案时(全部在第二plan个子句中,递归地),Moves现在绑定到一个动作列表,而不是开始寻找新的解决方案,您进入第二个子句再次回溯,已经填写了Moves,这可能会弄乱算法的其余部分。

为了使它正确,您可能需要确保当您plan回溯时,它开始寻找新的解决方案,并使用干净的Moves。您可以首先将Move实例化到一个空列表并在累加器中收集结果,如上面的简单baz谓词所示。

于 2013-06-17T21:32:00.253 回答