STRIPS algorithm in prolog dosen't stop - prolog

I'm learning Prolog and I'm writing STRIPS algorithm. Exactly I try to write it because it doesn’t work and unfortunately, I can't understand why.
Simply, the program doesn't stop, it thinks what kind is next action but doesn't apply it. Below, I post a code of my program, I hope that there will be somebody with more experience could put me in right direction.
May be the recursion is wrong but I can't find a mistakes.
Thank you!
The plan/2 and action/4 are predicate written in world representation file.
strips(Plan):-
[worldblock_rap],
plan(Initstate,Goallist),
strip1(Initstate,Goallist,RevPlan,[]),
reverse(RevPlan, Plan).
%strips(+GoalList, +State, +Plan, +ForbiddenActions
strip1(State,Goallist,_,_):-
there_is(State, Goallist).
%strips(+GoalList, +State, +Plan, +ForbiddenActions
strip1(State,Goallist,Plan,ForibiddenActions):-
%*****choose the right action******
action(Ac,Prec,Del,Add),
there_is(Goal, Goallist),
\+there_is(Goal, State),
there_is(Add,Goal),
\+belongs(Ac,ForibiddenActions),
%*****************
%******achive its precondition*******
strip1(TmpState1,Prec,TmpPlan1,[Ac| ForibiddenActions]),
%********************************
%***********Update the new plan with precondition's subplan and this action
apply_rule(Ac,Del,Add,TmpState1,NewState),
append([Ac|TmpPlan1], Plan, NewPlan),
strip1(NewState,Goallist,NewPlan,[Ac|ForibiddenActions]).
apply_rule(Ac,Dellist,Addlist,State,NewState):-
nl,write("doing"), write(Ac), ttyflush,
delete_list(State, Dellist,TmpState),
append(Addlist,TmpState,NewState).
reverse([],A,A).
reverse([X|L],L1,A):-reverse(L,[X|L1],A).
delete_list([H|T], List, Final):-
remove(H, List, Tmp),
delete_list(T, Tmp, Final).
delete_list([], List, List).
remove(X, [X|T], T).
remove(X, [H|T], [H|R]):-
remove(X, T, R).
append([H|T], L1, [H|L2]):-
append(T, L1, L2).
append([], L, L).
belongs(X, [X|_]).
belongs(X, [_|T]):-
belongs(X, T).
there_is([], _).
there_is([X|T], L):-
belongs(X, L),
there_is(T, L).

This the predicate of world block representation:
plan([on(a,d),on(b,table),on(c,b),on(d,table),top(a),top(c)],
[on(a,table),on(b,a),on(c,b),on(d,c),top(d)]).
action(putdown(X),
[top(X)],
[top(X),on(X,Y)],
[on(X,table),top(Y)]).
action(pickup(X,Y),
[on(X,table),top(Y)],
[on(X,table),top(Y)],
[on(X,Y),top(X)]).
Below there is onother representation of monkey world. Also with this file the planner doesn't work.
plan([at(monkey,a),at(box,c),on(monkey,floor),on(box,floor),status(banana,notpick),at(banana,d)],
[on(monkey,box),on(box,floor),status(banana,pick),at(banana,d),at(monkey,d),at(box,d)]).
action(
go(X,Y),
[at(monkey,X),on(monkey,floor)],
[at(monkey,X)],
[at(monkey,Y)]).
action(
push(B,X,Y),
[at(monkey,X),at(B,X),on(B,floor),on(monkey,floor)],
[at(monkey,X),at(B,X)],
[at(monkey,Y),at(B,Y)]).
action(
climb_on(B),
[at(monkey,X),at(box,X),on(monkey,floor),on(box,floor)],
[on(monkey,floor)],
[on(monkey,B)]).
action(
grab(B),
[status(B,notpick),on(monkey,box),at(B,X),at(monkey,X),at(box,X)],
[status(B,notpick)],
[status(B,pick)]).

Related

Help with simple prolog exercise

I haven't been able to solve this prolog exercise. I was hoping someone here could give me some hints or post a solution. Thanks in advance.
Database:
lig(super, porto).
lig(super, benfica).
lig(super, sporting).
lig(honra, feirense).
lig(honra, guimaraes).
jog(sporting, ricardo, gr).
jog(guimaraes, cleber, de).
jog(feirense, edgar, me).
jog(porto, quaresma, av).
jog(porto, helton, gr).
jog(benfica, simao, av).
jog(sporting, moutinho, me).
The sample output:
?- calcula(Lista).
Lista = [super-[porto-[quaresma,helton], benfica-[simao], sporting-
[moutinho,ricardo]], honra-[ feirense-[edgar], guimarães-[cleber]]].
My procedure:
calcula(Lista) :-
findall(Lig-[Eq-[X]],
(lig(Lig, Eq), findall(Jog, jog(Eq, Jog, _), X)),
Lista).
My output (which is wrong!).
Lista = [super-[porto-[[quaresma, helton]]], super-[benfica-[[simao]]], super-[sporting-[[ricardo, moutinho]]], honra-[feirense-[[edgar]]]
I see in the zfm's solution, the predicate lig(Lig, _) becomes true 5 times so there is some duplication in the final list. You can use the predicate setof/3 and existential quantified variable Eq0^ to remove duplication:
calcula(T) :- setof(Lig-X, Eq0^(lig(Lig, Eq0),
findall(Eq-U, (lig(Lig,Eq), findall(Jog, jog(Eq, Jog, _), U)), X)), T).
Since I'm so interested to the question, I try it a lot.
Well, this is, I believe, not the best answer. However I get the result.
calcula(Ans):-findall(Lig-X, (lig(Lig, _),
findall(Eq-U, (lig(Lig,Eq), findall(Jog, jog(Eq, Jog, _), U)), X)), T),
removeEq(T,Ans).
removeEq([A-B,A-_|Tail], [A-B|TailChanged]) :- !, removeEq([A-B|Tail],
[A-B|TailChanged]).
removeEq([A-B,C-D|Tail], [A-B,C-D|TailChanged]) :- removeEq([A-B|Tail],
[A-B|TailTemp]), removeEq([C-D|TailTemp], [C-D|TailChanged]).
removeEq([X], [X]).
The removeEq is needed because there are duplicated answer (I don't know how not to duplicate it)
This is not shorter than zfm's answer, but it is "simpler" in the way that it only uses basic prolog constructs to construct the list directly. (No removal of duplicates afterward.) There is some code duplication which probably could be gotten rid of to get a shorter answer.
g(Second, [Third|Rest], Done) :- jog(Second, Third,_),
not(member(Third, Done)),!,
g(Second, Rest, [Third|Done]).
g(_,[],_).
f(First, [Second-New|Rest], Done) :- lig(First, Second),
not(member(Second, Done)),!,
g(Second, New, []),
f(First, Rest, [Second|Done]).
f(_,[],_).
h([First-X|Lista], Done):-
lig(First,_),
not(member(First, Done)),!,
f(First, X, []),
h(Lista,[First|Done]).
h([], _).
calcula(X) :- h(X, []).

Prolog unify Lists inside a list

I'm trying to define a relation over lists...
?- matrix_items([[a,b],[c,d],[e,f]],Rs).
Rs = [a,b,c,d,e,f]. % expected result
So far, I was able to do something like this; unfortunately it doesn't add up all the elements:
sift([],_).
sift([H|T],[H|Result]) :-
create(H,Result),
sift(H,Result).
create([],_).
create([H|T],[H|R]) :-
create(T,R).
Hope hear from you soon.
Try something like this. I've changed the name of the predicate to flatten_l as unify has other connotations in Prolog:
flatten_l([H|T], FL):-
flatten_l([H|T], [], FL).
flatten_l([], FL, FL):- !.
flatten_l([H|T], ML, FL):-
flatten_l(T, ML, NL),
!,
flatten_l(H, NL, FL).
flatten_l(X, FL, [X|FL]).
Note also that this predicate will give you a stack overflow error if the first argument is uninstantiated...
If you want to collapse all of the lists (even sub-lists), you can use flatten/2.
If you only want to collapse a single level, then the following should work:
unify([], []).
unify([X|Xs], Ret) :- unify(Xs, Rs), append(X, Rs, Ret).
If you use SWI-pl, you can call flatten/2 to flatten all levels of nesting or append/2 to flatten only one level.

Searching Prolog structures

I'm interested in formulae made up from lots of conjunctions (part of a larger problem). I want to write a program that takes something like this:
:- get_params(conj(conj(a,b),c),X)
and returns a list of all the parameters of the conjunctions i.e. X=[a,b,c]. At the moment I can do
:- get_params(conj(a,b),X) to get X=[a,b]
using simple Prolog pattern matching but how would you go about doing things such as
:- get_params(conj(conj(a,b),c),X) to get X=[a,b,c]
It seems really simple but I've been struggling all day!
Since you are describing a list, consider using DCG notation:
params(conj(A,B)) --> !, params(A), params(B).
params(X) --> [X].
Example:
?- phrase(params(conj(conj(a,b),c)), Ps).
Ps = [a, b, c].
Assuming that all conj functors are binary:
get_params(X, Y, L) :-
get_params(X, L1),
get_params(Y, L2),
append(L1, L2, L).
get_params(conj(X, Y), L) :-
get_params(X, Y, L), !.
get_params(A, [A]).

Prolog: Sentence Parser

Been sat here for hours now just staring at this code and have no idea what I'm doing wrong. I know what's happening from tracing the code through (it is going on an eternal loop when it hits verbPhrase). Any tips are more then welcome. Thank you.
% Knowledge-base
det(the).
det(a).
adjective(quick).
adjective(brown).
adjective(orange).
adjective(sweet).
noun(cat).
noun(mat).
noun(fox).
noun(cucumber).
noun(saw).
noun(mother).
noun(father).
noun(family).
noun(depression).
prep(on).
prep(with).
verb(sat).
verb(nibbled).
verb(ran).
verb(looked).
verb(is).
verb(has).
% Sentece Structures
sentence(Phrase) :-
append(NounPhrase, VerbPhrase, Phrase),
nounPhrase(NounPhrase),
verbPhrase(VerbPhrase).
sentence(Phrase) :-
verbPhrase(Phrase).
nounPhrase([]).
nounPhrase([Head | Tail]) :-
det(Head),
nounPhrase2(Tail).
nounPhrase(Phrase) :-
nounPhrase2(Phrase).
nounPhrase(Phrase) :-
append(NP, PP, Phrase),
nounPhrase(NP),
prepPhrase(PP).
nounPhrase2([]).
nounPhrase2(Word) :-
noun(Word).
nounPhrase2([Head | Tail]) :-
adjective(Head),
nounPhrase2(Tail).
prepPhrase([]).
prepPhrase([Head | Tail]) :-
prep(Head),
nounPhrase(Tail).
verbPhrase([]).
verbPhrase(Word) :-
verb(Word).
verbPhrase([Head | Tail]) :-
verb(Head),
nounPhrase(Tail).
verbPhrase(Phrase) :-
append(VP, PP, Phrase),
verbPhrase(VP),
prepPhrase(PP).
I figured it out now after a bit of trolling the internet, so will answer it here if anyone else struggles with it.
The problem was that the append was creating an empty list. This list was passed as a parameter, then split again into two empty lists. And this was repeated over and over again. To stop this, everytime the append function is used, there must be a check if the lists are empty.
For example
verbPhrase(Phrase):-
append(VP, PP, Phrase),
VP \= [],
PP \= [],
verbPhrase(VP),
prepPhrase(PP).

Prolog difference routine

I need some help with a routine that I am trying to create. I need to make a routine that will look something like this:
difference([(a,b),(a,c),(b,c),(d,e)],[(a,_)],X).
X = [(b,c),(d,e)].
I really need help on this one..
I have written a method so far that can remove the first occurrence that it finds.. however I need it to remove all occurrences. Here is what I have so far...
memberOf(A, [A|_]).
memberOf(A, [_|B]) :-
memberOf(A, B).
mapdiff([], _, []) :- !.
mapdiff([A|C], B, D) :-
memberOf(A, B), !,
mapdiff(C, B, D).
mapdiff([A|B], C, [A|D]) :-
mapdiff(B, C, D).
I have taken this code from listing(subtract).
I don't fully understand what it does, however I know it's almost what I want. I didn't use subtract because my final code has to be compatible with WIN-Prolog... I am testing it on SWI Prolog.
Tricky one! humble coffee has the right idea. Here's a fancy solution using double negation:
difference([], _, []).
difference([E|Es], DL, Res) :-
\+ \+ member(E, DL), !,
difference(Es, DL, Res).
difference([E|Es], DL, [E|Res]) :-
difference(Es, DL, Res).
Works on SWI-PROLOG. Explanation:
Clause 1: Base case. Nothing to diff against!
Clause 2: If E is in the difference list DL, the member/2 subgoal evaluates to true, but we don't want to accept the bindings that member/2 makes between variables present in terms in either list, as we'd like, for example, the variable in the term (a,_) to be reusable across other terms, and not bound to the first solution. So, the 1st \+ removes the variable bindings created by a successful evaluation of member/2, and the second \+ reverses the evaluation state to true, as required. The cut occurs after the check, excluding the 3rd clause, and throwing away the unifiable element.
Clause 3: Keep any element not unifiable across both lists.
I am not sure, but something like this could work. You can use findall to find all elements which can't be unified with the pattern:
?- findall(X, (member(X, [(a,b),(b,c),(a,c)]), X \= (a,_)), Res).
gets the reply
Res = [ (b, c) ]
So
removeAll(Pattern, List, Result) :-
findall(ZZ109, (member(ZZ109, List), ZZ109 \= Pattern), Result).
should work, assuming ZZ109 isn't a variable in Pattern (I don't know a way to get a fresh variable for this, unfortunately. There may be a non-portable one in WIN-Prolog). And then difference can be defined recursively:
difference(List, [], List).
difference(List, [Pattern|Patterns], Result) :-
removeAll(Pattern, List, Result1),
difference(Result1, Patterns, Result).
Your code can be easily modified to work by making it so that the memberOF predicate just checks to see that there is an element in the list that can be unified without actually unifying it. In SWI Prolog this can be done this way:
memberOf(A, [B|_]) :- unifiable(A,B,_).
But I'm not familiar with WIN-PRolog so don't know whether it has a predicate or operator which only tests whether arguments can be unified.

Resources