delete all occurences of a term in a list - prolog

I know this sounds "duplicate" but please help me out
I have defined three terms as follows:
type([a, b, c, d]:location).
type([coffee, tea, lemonade, water, biscuits]: object).
type([order(object, location)]: order).
I have a piece of code that then generates a list of random orders.
I now need a predicate that deletes all the terms that unify with order(X, a), that is, deletes all the orders that have a as location from that list.
For instance, this is an example of list (printed this way to make it readable):
order(tea,a)
order(tea,b)
order(coffee,b)
order(water,c)
order(lemonade,d)
order(biscuits,a)
order(water,c)
order(tea,c)
order(coffee,d)
order(water,d)
applying such needed predicate my_delete(List, [order(_, a), order(_, b)], Result) would give:
order(water,c)
order(lemonade,d)
order(water,c)
order(tea,c)
order(coffee,d)
order(water,d)
So far I've tried to remove a sublist from the main list, but what it does is just delete a single element for a and a single element for b, not all of them. This is the code for such predicate (thanks also to this reference):
remove_list([], _, []).
remove_list([X|Tail], L2, Result):-
member(X, L2),
!,
remove_list(Tail, L2, Result).
remove_list([X|Tail], L2, [X|Result]):-
remove_list(Tail, L2, Result).
and a query that I tried, but didn't work as expected, was:
remove_list(Input_list, [ordine(_, a), ordine(_, b)], Result).
Notice that I need duplicates, so using sets won't work.

You can use negation \+ to avoid further unification over recursion of your filter list:
remove_list([], _, []).
remove_list([X|Tail], ToDelete, Result):-
(\+( memberchk(X, ToDelete) ) ->
Result=[X|NResult] ;
Result=NResult
),
remove_list(Tail, ToDelete, NResult).

Using exclude/3, which takes a predicate, input list and output list:
rev_memberchk(List, Member) :-
memberchk(Member, List).
my_delete(Input_List, Orders, Result) :-
exclude(rev_memberchk(Orders), Input_List, Result).
Using memberchk/1 rather than member/2 for efficiency; you don't need the bound output, just to know if it can unify. If you also have lambda expressions, this can be turned into a one-liner by removing the need to write a predicate with re-ordered arguments:
my_delete(Input_List, Orders, Result) :-
exclude({Orders}/[X]>>memberchk(X, Orders), Input_List, Result).

Related

Prolog: Appending to a list while reusing the same list(out of local stack error)

I have a predicate that takes a list, for example:
[car(blue,2000), car(blue,1000), car(red,2000), car(red,3000)]
And two criteria , example I need to pick the first blue car, and from the remaining list, the first car that cost 2000. I need to return a list of the selected car, which should be
[car(blue,2000),car(red,2000)]
The predicate that I have returns a out of local stack error. From trace , it seems to say that is because I'm doing append(_8757416, [car(blue,2000)], _8757416) , which I'm not really doing. I thought the two append with a temporary list would avoid this kind of bug. Here is the code, hope it can help to understand better want I'm talking about.
checkCriteria([],_,_).
checkCriteria(_,[],_).
checkCriteria([Criteria|T],Cars, ChosenCar):-
include(
goal([Criteria]),
Cars,
FilteredList),
[H|_] = FilteredList,
append([], ChosenCar, Temp ),
append(Temp, [H], ChosenCar),
delete(H, FilteredList, NewList),
checkCriteria(T,NewList, ChosenCar).
% this predicate deletes an element from a list
delete(Y, [Y], []).
delete(X, [X|L1], L1).
delete(X, [Y|L], [Y|L1]):-delete(X,L,L1).
% this predicate check if a element respect a criteria
goal([],_).
goal([Criteria|Cs],Element) :-
criteria(Criteria,Element),
goal(Cs,Element).
:- dynamic criteria/2.
criteria(blue,(car(Color, _))) :- Color = blue, car(Color, _).
criteria(price,(car(_, Price))) :- Price = 2000, car(_,Price).
:- dynamic car/2.
car(blue,2000).
car(blue,1000).
car(red,2000).
car(red,3000).
How to avoid the out of local stack error?
Here is the command that cause the error :
?- checkCriteria([blue, price], [car(blue,2000), car(blue,1000), car(red,2000), car(red,3000)], X).
I had a try and found a few issues, which I (mostly) fixed below. It works with the example, maybe it helps:
The list ChosenCar was never instantiated and hence the appending to it failed. I added an extra parameter to checkCriteria as an accumulator list to collect the results. This is assigned to ChosenCar in the recursion anchors.
You deleted the car that met the criteria from the FilteredList for the next recusion step, but it should be deleted from Cars, so that the next criteria could be checked with the remaining cars.
Your delete predicate can not handle empty lists, and also checkCriteria assumes every criteria to be met by one of the remaining cars. You may want to look into that as well: Handle empty lists in delete and also the case where FilteredList is empty after the include.
checkCriteria([],_,ACC,ACC).
checkCriteria(_,[],ACC,ACC).
checkCriteria([Criteria|T],Cars, ACC, ChosenCar):-
include(
goal([Criteria]),
Cars,
FilteredList),
[H|_] = FilteredList,
append(ACC, [H], ACC1),
delete(H, Cars, NewList),
checkCriteria(T,NewList, ACC1, ChosenCar).
% this predicate deletes an element from a list
delete(Y, [Y], []).
delete(X, [X|L1], L1).
delete(X, [Y|L], [Y|L1]):-delete(X,L,L1).
% this predicate check if a element respect a criteria
goal([],_).
goal([Criteria|Cs],Element) :- criteria(Criteria,Element), goal(Cs,Element).
:- dynamic criteria/2.
criteria(blue,car(Color, _)) :- Color = blue, car(Color, _).
criteria(price,car(_, Price)) :- Price = 2000, car(_,Price).
:- dynamic car/2.
car(blue,2000).
car(blue,1000).
car(red,2000).
car(red,3000).

I have defined multiple predicates that seem to share a common form

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.

Prolog: Removing Duplicates

I am trying to remove duplicate entries from a list in prolog. So a list [a,b,a,c,b,a] would return [a,b,c]. I can not use any built in functions. I searched here and found this code.
member(X,[X|_]) :- !.
member(X,[_|T]) :- member(X,T).
set([],[]).
set([H|T],[H|Out]) :- not(member(H,T)), set(T,Out).
set([H|T],Out) :- member(H,T), set(T,Out).
But that would take my list and return [c,b,a] not [a,b,c]
I have remove code that will take an element and a list and return a list with occurrences of that element in the list removed. So I tried to incorporate that into my remove duplicate method but I don't really understand prolog very well so it is not working. Logically I want to take a list cons the head with the recursive call on the new list minus all occurrences of the head. This is what the code would look like in sml.
fun remv(_,nil) = nil
| remv(a,x::xs) = if x=a then remv(a,xs) else x::remv(a,xs);
fun remvdub (nil) = nil
| remvdub(x::xs) = x::remvdub(remv(x,xs));
So this is what I tried in prolog
remv(_,[],[]).
remv(X,[X|T],Ans) :- remv(X,T,Ans).
remv(X,[H|T],[H|K]) :- remv(X,T,K).
remvdub([],[]).
remvdub([H|T],[H|Ans]) :- remvdub(Ans1,Ans), remv(H,T,Ans1).
What am I missing?
% An empty list is a set.
set([], []).
% Put the head in the result,
% remove all occurrences of the head from the tail,
% make a set out of that.
set([H|T], [H|T1]) :-
remv(H, T, T2),
set(T2, T1).
% Removing anything from an empty list yields an empty list.
remv(_, [], []).
% If the head is the element we want to remove,
% do not keep the head and
% remove the element from the tail to get the new list.
remv(X, [X|T], T1) :- remv(X, T, T1).
% If the head is NOT the element we want to remove,
% keep the head and
% remove the element from the tail to get the new tail.
remv(X, [H|T], [H|T1]) :-
X \= H,
remv(X, T, T1).
The snippet of Prolog code that you posted is logically correct. If you would like to keep the first, as opposed to the last, copy of each duplicated item, you can change your code as follows:
member(X,[X|_]) :- !.
member(X,[_|T]) :- member(X,T).
set(A,B) :- set(A, B, []).
set([],[],_).
set([H|T],[H|Out],Seen) :- not(member(H,Seen)), set(T,Out, [H|Seen]).
set([H|T],Out, Seen) :- member(H,Seen), set(T,Out,Seen).
The idea is to add a third parameter, which represents the list of items that you have seen so far, and check the membership against it, rather than checking the membership against the remaining list. Note that set/2 is added to hide this third argument from the users of your predicate.
Demo on ideone.

Prolog planner only generates one plan

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.

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