I am writing a program in Prolog (gprolog) that pathfinds on a graph. I based it partially off of this SO post.
Let me give an example. Here is an example graph I drew:
And here is what the code initially looked like:
path([Goal],Goal,Goal).
path(P,Start,Goal) :- adjacent(Start,X),
\+ (memberchk(X,P)),
(
Goal=X
;
path([Start|P],X,Goal)
).
Regardless of whether that base case is redundant, here is the problem. I want an input style of
| ?- path(P,a,f).
and for that input, I would get output of
P = [a,s,f]
true ?
However, the problem with the code as it stands lies with memberchk. For memberchk(a,P), it attempt to unify, calls memberchk(a,[a|_]), and returns true. I don't want this to happen, so I first check if P is instantiated using the var/1 predicate. Thus, my code changed to
path([Goal],Goal,Goal).
path(P,Start,Goal) :- var(P),
path([],Start,Goal).
path(P,Start,Goal) :- adjacent(Start,X),
\+ (memberchk(X,P)),
(
Goal=X
;
path([Start|P],X,Goal)
).
Now if P is uninstantiated, we call path/3 with the empty list. My problem is this: now I cannot print P at the end, as I call path([],Start,Goal) and P is no longer associated with [].
I have tried using the write/1 predicate, but it either printed out P at every step or printed P = _26 (meaning it's printing the uninstantiated P, not the final value of P).
I hope this is a simple problem, I'm just awfully new to Prolog.
Apologies if something similar has been asked; I would love to be pointed to other questions that could help. I searched through SO and Google before posting this.
The concept you need is that of accumulators
You were actually very close: you realized indeed that initializing P to [], and filling it with [Start|P] as you recurse was a working strategy. This is called an accumulator, and to get the final result you simply need to add another argument.
Here is your new path/3 predicate that you query:
path(P, Start, Goal) :-
path([], P, Start, Goal).
As you can see, here we add the [] as a first argument to path/4, which we implement like this:
path(L, P, Goal, Goal) :-
reverse([Goal|L], P).
path(L, P, Start, Goal) :-
adjacent(Start, X),
\+ (memberchk(X, L)),
path([Start|L], P, X, Goal).
The first clause is here to terminate the recursion. Once the Start and Goal arguments are the same as you had noted, the recursion should be over. When using an accumulator this means that we unify the accumulator with the output argument. However, the accumulator contains the answer reversed (and lacks the final goal), so we have reverse([Goal|L], P).
The second clause is very similar to what you had written, with the exception that we now need to pass P as is to the recursive clause. Note that I have removed your disjunction in that clause, it isn't needed in that case.
The complete code:
path(P, Start, Goal) :-
path([], P, Start, Goal).
path(L, P, Goal, Goal) :-
reverse([Goal|L], P).
path(L, P, Start, Goal) :-
adjacent(Start, X),
\+ (memberchk(X, L)),
path([Start|L], P, X, Goal).
I solved my problem. The solution relies on:
Keeping track of visited nodes
When recursing, recursing on a smaller list
Checking if something is not a member of a list to prevent unification when not wanted
My code is as follows:
connected(X,Y) :- adjacent(X,Y);adjacent(Y,X).
not_member(_, []).
not_member(X, [Head|Tail]) :- X \== Head, not_member(X, Tail).
path(P,A,B):-path_helper(P,A,B,[Start]).
path_helper([X,Y],X,Y,_):-connected(X,Y).
path_helper([Goal],Goal,Goal,_).
path_helper([Start|[Head|P]],Start,Goal,Visited):-connected(Start,Head),not_member(Head,Visited),path_helper([Head|P],Head,Goal,[Head|Visited]).
Related
All of these predicates are defined in pretty much the same way. The base case is defined for the empty list. For non-empty lists we unify in the head of the clause when a certain predicate holds, but do not unify if that predicate does not hold. These predicates look too similar for me to think it is a coincidence. Is there a name for this, or a defined abstraction?
intersect([],_,[]).
intersect(_,[],[]).
intersect([X|Xs],Ys,[X|Acc]) :-
member(X,Ys),
intersect(Xs,Ys,Acc).
intersect([X|Xs],Ys,Acc) :-
\+ member(X,Ys),
intersect(Xs,Ys,Acc).
without_duplicates([],[]).
without_duplicates([X|Xs],[X|Acc]) :-
\+ member(X,Acc),
without_duplicates(Xs,Acc).
without_duplicates([X|Xs],Acc) :-
member(X,Acc),
without_duplicates(Xs,Acc).
difference([],_,[]).
difference([X|Xs],Ys,[X|Acc]) :-
\+ member(X,Ys),
difference(Xs,Ys,Acc).
difference([X|Xs],Ys,Acc) :-
member(X,Ys),
difference(Xs,Ys,Acc).
delete(_,[],[]).
delete(E,[X|Xs],[X|Ans]) :-
E \= X,
delete(E,Xs,Ans).
delete(E,[X|Xs],Ans) :-
E = X,
delete(E,Xs,Ans).
There is an abstraction for "keep elements in list for which condition holds".
The names are inclide, exclude. There is a library for those in SWI-Prolog that you can use or copy. Your predicates intersect/3, difference/3, and delete/3 would look like this:
:- use_module(library(apply)).
intersect(L1, L2, L) :-
include(member_in(L1), L2, L).
difference(L1, L2, L) :-
exclude(member_in(L2), L1, L).
member_in(List, Member) :-
memberchk(Member, List).
delete(E, L1, L) :-
exclude(=(E), L1, L).
But please take a look at the implementation of include/3 and exclude/3, here:
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/apply.pl?show=src#include/3
Also in SWI-Prolog, in another library, there are versions of those predicates called intersection/3, subtract/3, delete/3:
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#intersection/3
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#subtract/3
https://www.swi-prolog.org/pldoc/doc_for?object=delete/3
Those are similar in spirit to your solutions.
Your next predicate, without_duplicates, cannot be re-written like that with include/3 or exclude/3. Your implementation doesn't work, either. Try even something easy, like:
?- without_duplicates([a,b], L).
What happens?
But yeah, it is not the same as the others. To implement it correctly, depending on whether you need the original order or not.
If you don't need to keep the initial order, you can simply sort; this removes duplicates. Like this:
?- sort(List_with_duplicates, No_duplicates).
If you want to keep the original order, you need to pass the accumulated list to the recursive call.
without_duplicates([], []).
without_duplicates([H|T], [H|Result]) :-
without_duplicates_1(T, [H], Result).
without_duplicates_1([], _, []).
without_duplicates_1([H|T], Seen0, Result) :-
( memberchk(H, Seen0)
-> Seen = Seen0 , Result = Result0
; Seen = [H|Seen0], Result = [H|Result0]
),
without_duplicates_1(T, Seen, Result0).
You could get rid of one argument if you use a DCG:
without_duplicates([], []).
without_duplicates([H|T], [H|No_duplicates]) :-
phrase(no_dups(T, [H]), No_duplicates).
no_dups([], _) --> [].
no_dups([H|T], Seen) -->
{ memberchk(H, Seen) },
!,
no_dups(T, Seen).
no_dups([H|T], Seen) -->
[H],
no_dups(T, [H|Seen]).
Well, these are the "while loops" of Prolog on the one hand, and the inductive definitions of mathematical logic on the other hand (See also: Logic Programming, Functional Programming, and Inductive Definitions, Lawrence C. Paulson, Andrew W. Smith, 2001), so it's not surprising to find them multiple times in a program - syntactically similar, with slight deviations.
In this case, you just have a binary decision - whether something is the case or not - and you "branch" (or rather, decide to not fail the body and press on with the selected clause) on that. The "guard" (the test which supplements the head unification), in this case member(X,Ys) or \+ member(X,Ys) is a binary decision (it also is exhaustive, i.e. covers the whole space of possible X)
intersect([X|Xs],Ys,[X|Acc]) :- % if the head could unify with the goal
member(X,Ys), % then additionally check that ("guard")
(...action...). % and then do something
intersect([X|Xs],Ys,Acc) :- % if the head could unify with the goal
\+ member(X,Ys), % then additionally check that ("guard")
(...action...). % and then do something
Other applications may need the equivalent of a multiple-decision switch statement here, and so N>2 clauses may have to be written instead of 2.
foo(X) :-
member(X,Set1),
(...action...).
foo(X) :-
member(X,Set2),
(...action...).
foo(X) :-
member(X,Set3),
(...action...).
% inefficient pseudocode for the case where Set1, Set2, Set3
% do not cover the whole range of X. Such a predicate may or
% may not be necessary; the default behaviour would be "failure"
% of foo/1 if this clause does not exist:
foo(X) :-
\+ (member(X,Set1);member(X,Set2);member(X,Set3)),
(...action...).
Note:
Use memberchk/2 (which fails or succeeds-once) instead of member/2 (which fails or succeeds-and-then-tries-to-succeed-again-for-the-rest-of-the-set) to make the program deterministic in its decision whether member(X,L).
Similarly, "cut" after the clause guard to tell Prolog that if a guard of one clause succeeds, there is no point in trying the other clauses because they will all turn out false: member(X,Ys),!,...
Finally, use term comparison == and \== instead of unification = or unification failure \= for delete/3.
I am trying to parse a list, for example:
[1,3,3,2,2,7,2,9]
Let's say I have the following code, where isTwo will print No and fail if it is anything other than two. I WANT it to fail if it is anything other than two. If it is a two, it will print Yes and succeed.
isTwo(2) :-
write('Yes'), !.
isTwo(_) :-
write('No'), fail.
My issue is that I have something along the lines of an iterator defined, and I want to parse an entire list to find the first success.
iter([]).
iter([Head|Tail]) :-
isTwo(Head),
iter(Tail).
This works fine but will stop parsing the rest of the list as soon as failure is found. If we go back to the original list, [1,3,3,2,2,7,2,9], we get false as our output.
My question here is: how can I continue to parse in prolog while still ensuring that isTwo(_) (where it is not equal to two) will still fail, so that I can get an output of something such as NoNoNoYesYesNoYesNo in this case. Preferably without using an if-then-else clause.
This may help:
expected output: NoNoNoYesYesNoYesNo
observed output: No
Well an easy solution would be to use a second variable in iter that will help you understand if an number different than 2 is found:
isTwo(2, X, X) :-
write('Yes').
isTwo(_, _, 0) :-
write('No').
iter([], 0):- fail,!.
iter([], 1).
iter([Head|Tail], X) :-
isTwo(Head, X, Y),
iter(Tail, Y).
iter(L) :- iter(L, 1).
If you want a more concise solution, using maplist/2 you can do something like:
isTwo(2) :- write('Yes'), !.
isTwo(_):- write('No').
test(L):-
maplist(isTwo,L).
?- test([1,3,3,2,2,7,2,9]).
NoNoNoYesYesNoYesNo
true
test/1 is not mandatory, i've added it only for sake of clarity...
The other answers are both fine but the haphazard mixing in of side effects makes me a bit nervous. Also, you have a problem if the list you are "parsing" has a free variable (it will become 2 silently).
Why not like this:
is_two(X) :- X == 2, !, format("Yes").
is_two(X) :- X \== 2, !, format("No").
and then:
?- forall(member(X, [1,3,3,2,2,7,2,9]), is_two(X)).
NoNoNoYesYesNoYesNo
true.
?- forall(member(X, [Y, 2, Z]), is_two(X)).
NoYesNo
true.
Use == and \== to compare without unifying. Use forall and member to make it clear that you are doing it for the side effect. Traversing a list (or using maplist) is a bit deceiving.
forall is just a clearer way to do a failure-driven loop using negation instead of cuts and fails. The query above is identical to:
?- \+ ( member(X, [1,3,3,2,2,7,2,9]), \+ is_two(X) ).
I have a prolog planner which works correctly with one major problem of only generating one plan at the time. The plan is correct but for my application I really need to have all the possible plans.
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).
Sample call
go([in(app1,s1), stone(s2), active(s2),stone(s3),active(s3)],[in(app1,s1),in(app1,s3),in(app1,s2)],AllPlans).
Answer:
drop(s2,app1)
drop(s3,app1) //correct
_2368
_2366
_2364
_2362
_2360
_2358
_2356
_2354
_2352
_2350
_2348
_2346
_2344
_2342
_2340
_2338
_2336
etc... infinitely
For finding all solutions to a goal, look at bagof or findall. Or am I missing something?
Like this:
?- findall(Moves, plan(State, Goal, _, Moves), AllMoves).
The whole idea of these predicates is that you say which arguments you want to collect and get a list of all possible instantiations under that predicate. In this sense you normally have a "return" value (an argument that gets instantiated with the result) that you can then look at or print, instead of printing it explicitly in the predicate that finds solutions.
A simplistic example:
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).
Now to recursion: how does it work? You cannot share variables between different clauses of the same predicate. For example, this is wrong:
baz(0, B).
baz(X, B) :- X0 is X - 1, B1 is B + 1, baz(X0, B1).
because B is a singleton variable in the first clause of baz. Instead, you can do:
baz(0, B, B).
baz(X, B, Result) :- X0 is X - 1, B1 is B + 1, baz(X0, B1, Result).
which you can now call:
?- baz(10, 2, Result).
Result = 12
but you will still run into problems after the first answer.
You get the single correct plan probably because the first clause of plan does not meet the requirements of subsetB, and you get to the second clause. There, you make a Moves that has a free variable at its Tail, but this is not a problem yet. The problem is, however, that when you find your first solution (all in the second plan clause, recursively), Moves is now bound to a list of actions, and instead of starting to look for a new solution, you get into the second clause again by backtracking, with the already filled in Moves, which probably messes up the rest of the algorithm.
To make it correct, you probably need to make sure that when your plan backtracks, it starts to look for a new solution, with a clean Moves. You can start by instantiating Moves to an empty list and collecting results in an accumulator, as shown in the simplistic baz predicate above.
i have to get list difference between two integer list (both ordinate).
i white this:
difference(L,[],L) :- !.
difference([],_,[]) :- !.
difference([],[],W).
difference([H|T1],[D|T2],T3) :- difference(T1,[D|T2],[H|T3]).
difference([H|T1],[H|T2],T3) :- difference(T1,T2,T3).
but why i can't get my list difference?
if i write this:
difference([],[],W):- write(X).
and this example:
| ?- difference([1,4,4],[1,4],R).
[4|_27]
it makes right!
NB if i have duplicate number i have to show it!
I find your code rather odd. For instance, your third clause: what's W for? Seems like you mean to say:
difference([],[],_).
Second problem: in the fourth clause, there's nothing stopping H and D from being independent variables with the same binding. I suspect you mean something like this:
difference([H|T1],[D|T2],T3) :- H \= D, difference(T1,[D|T2],[H|T3]).
Fixing these things seems to fix the predicate to give a reasonable looking answer:
| ?- difference([1,4,4], [1,4], R).
R = [4]
I think your first several clauses are trying to handle different sorts of base cases, is that right? E.g.:
difference(L, [], L) % handles the case where the second list is exhausted
difference([], _, []) % handles the case where the first list is exhausted
difference([], [], W) % handles the case where the lists are exhausted at the same time
One problem with this is that L = [] is a legitimate binding, so the first and third clauses mean the same thing. You can probably safely remove the third one, because it would have matched and produced the same answer on the first. The second clause is more interesting, because it seems to say that regardless of whatever work we've done so far, if the first list is empty, the result is empty. I find that possibility a bit jarring--is it possible you actually want these two base cases? :
difference([], L, L).
difference(L, [], L).
I remain unconvinced, but until I have a better idea what you're trying to accomplish I may not be able to help more. For instance, what should happen with difference([1, 4], [1, 4, 4], R)? I posit you probably want R = [4], but your code will produce R = [].
Also, I find it unlikely that
difference([],[],W):- write(X).
is going to be a helpful debugging strategy, because Prolog will generate a new variable binding for X because there's nothing for it to refer to.
The final version I have with all my changes looks like this:
difference(L, [], L) :- !.
difference([], L, L) :- !.
difference([H|T1], [D|T2], T3) :- D \= H, difference(T1, [D|T2], [H|T3]).
difference([H|T1], [H|T2], T3) :- difference(T1, T2, T3).
Edit: does this implement your requirements?
not_in1(X, Left, Right) :- member(X, Left), \+ member(X, Right).
not_in(X, Left, Right) :- not_in1(X, Left, Right).
not_in(X, Left, Right) :- not_in1(X, Right, Left).
differences(Left, Right, Differences) :-
findall(X, not_in(X, Left, Right), Differences).
?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]
If so, I'll try to get your original code to produce answers that match.
Edit 2: OK, so the problem with the solution above is that it is O(N^2). In the worst case (two totally distinct lists) it will have to compare every item from list 1 to every item of list 2. It's not exploiting the fact that both lists are ordered (I believe that's what you mean by 'ordinate').
The result looks a lot more like your original code, but your original code is not taking advantage of the fact that the items are ordered. This is why the fourth and fifth cases are confusing looking: you should recur down one of the lists or the other depending on which number is larger. The corrected code looks like this:
differences([], Result, Result).
differences(Result, [], Result).
differences([H|Ls], [H|Rs], Result) :- differences(Ls, Rs, Result).
differences([L|Ls], [R|Rs], [L|Result]) :-
L < R,
differences(Ls, [R|Rs], Result).
differences([L|Ls], [R|Rs], [R|Result]) :-
L > R,
differences([L|Ls], Rs, Result).
You can see this produces the same result as the O(N^2) method:
?- differences([1,2,3,4], [1,3,5], X).
X = [2,4,5]
You were right, you do need both base cases. This is so the remainder of either list becomes part of the result. Presumably these will be the largest values ([5] in the example).
Now I have three inductive cases: one for <, one for > and one for =. The equality case is intuitive: recur on both lists, discarding the head of both lists. The next case basically says if the left head is less than the right head, add it to the result and recur on the left's tail. The right is unchanged in that case. The other case is the mirror of this case.
Hope this helps!
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.