Removing elements from list above/below certain value - prolog

I have written a small Prolog script which, taken a list, removes all values below a threshold N:
rem_under([], []).
rem_under([X|Xs], [X|Ys]) :-
X >= 10,
rem_under(Xs, Ys).
rem_under([X|Xs], Ys) :-
X < 10,
rem_under(Xs, Ys).
So, for example:
2 ?- rem_under([2,15,16,3,5,19],L).
L = [15, 16, 19]
I then wanted to make a similar function which removed all elements ABOVE a threshold N:
rem_over([], []).
rem_over([X|Xs], [Ys]) :-
X > 10,
rem_over(Xs, Ys).
rem_over([X|Xs], [X|Ys]) :-
X <= 10,
rem_over(Xs, Ys).
Which however returns:
1 ?- rem_over([2,15,17,6],L).
false.
Any idea why this is? Other than a few cosmetic changes, I have only swapped the < and > signs.

Your second clause is incorrect, because its second argument is [Ys] — a list of length 1:
rem_over( [X|Xs] , [Ys] ) :-
X > 10,
rem_over(Xs, Ys).
Once you've decided the head of the source list is greater than 10, you recurse down on the tail of the source list and the the contents of the result list.
Try this:
rem_over( [] , [] ) . % source list exhausted? success!
rem_over( [X|Xs] , Ys ) :- % source list non-empty?
X > 10, % - head greater than the threshold?
rem_over(Xs, Ys) % - chuck it and recurse down on the remainder of the source list
. %
rem_over( [X|Xs] , [X|Ys] ) :- % source list non-empty? add the head to the result
X =< 10, % - IF it's less than or equal to the threshold
rem_over(Xs, Ys). % - then recurse down on the remainder
Another way to get there:
rem_over( [] , [] ) .
rem_over( [X|Xs] , Ys ) :-
( X > 10 -> Y1 = Ys ; Y1 = [X|Ys] ) ,
rem_over(Xs,Y1)
.

HINT: because you have a singleton variable (that is considered to be a list) inside [].
ANSWER: in the head of the 2nd clause should be
rem_over([X|Xs], Ys) :-

Related

Removing duplicates from a list in prolog

I'm trying to implement a simple predicate, that would simply remove items that occur more than once in a list.
For instace, for,
unique([a,b,a,b,c,c,a], R)
should be R = [a,b,c]
unique([], []).
unique([X], [X]).
unique([H|T], [H|R]) :-
not_contains(H, R),
unique(T, R).
unique([H|T], R) :-
contains(H, R),
unique(T, R).
contains(_, []).
contains(X, [X|T]).
not_contains(_, []).
not_contains(X, [H|T]) :-
X \= H,
not_contains(X, T).
I am unsure what I'm doing wrong. If the item is not contained within R, add to it and repeat, and if is, don't add it and proceed with iteration.
A fun way to do it that I just thought of:
nub(L,R):- maplist( p(R), L), length(R,_), !.
p(R,E):- memberchk(E,R).
nub(L,R) makes a unique list R out of an input list L. It assumes R is a non-instantiated variable before the call is made, and L is a fully ground list.
This uses the result list as its own uniqueness accumulator while it is being built!
Testing:
6 ?- nub([a,b,a,b,c,c,a], R).
R = [a, b, c].
The easiest way to make a list unique is just use the built-in sort/2:
unique(Xs,Ys) :- sort(Xs,Ys).
so unique( [c,a,b,a] , Rs ) yields Rs = [a,b,c].
If you want to maintain order, you need to decide on the strategy you want to use — in case of duplicates, which duplicate "wins": First or last?
The "last wins" strategy is the simplest to implement:
unique( [] , [] ) . % the empty list is itself a unique set
unique( [X|Xs] , Ys ) :- % A non-empty list is unique if . . .
contains(X,Xs), % - X is contained within the source list's tail,
!, - and (eliminating the choice point)
unique( Xs, Ys ) . - omitting X, the remainder of the list is (recursively) unique
unique( [X|Xs] , Ys ) :- % Otherwise, the non-empty list is unique if . . .
unique( Xs,[X|Ys] ) . % - adding X to the results, the remainder of the list is (recursively) unique .
Here, unique( [a,b,a,c,a], Rs ) yields Rs = [b,c,a].
If you want to use the "first wins" strategy, you'll be wanting to use a helper predicate with an accumulator that grows the result list in reverse order, which is then reversed. That gives us something like this:
unique( Xs , Ys ) :- unique(Xs,[],Zs), reverse(Zs,Ys) .
unique( [] , Ys , Ys ) . % Source list exhausted? we're done.
unique( [X|Xs] , Ts , Ys ) :- % Otherwise . . .
contains(X,Ts) , % - if X is found in the accumulator,
!, % - eliminate the choice point, and
unique(Xs,Ts,Ys) . % - recurse down, discarding X
unique( [X|Xs] , Ts , Ys ) :- % Otherwise (X is unique) . . .
unique(Xs,[X|Ts],Ys) . % - recurse down, prepending X to the accumulator
And here, unique( [a,b,a,c,a], Rs ) yields Rs = [a,b,c].
You can avoid the use of reverse/2 here, by building the 2 lists (accumulator and final set) in parallel. A trade-off, though: memory for speed:
unique( Xs , Ys ) :- unique(Xs,[],Ys) .
unique( [] , _ , [] ) .
unique( [X|Xs] , Ts , Ys ) :- memberchk(X,Ts), !, unique( Xs, Ts , Ys ) .
unique( [X|Xs] , Ts , [X|Ys] ) :- unique( Xs, [X|Ts] , Ys ) .
You don't really need a contains/2 predicate: the in-built member/2 and memberchk/2 do exactly what you want. member/2 is non-deterministic and will succeed once for every time the item is found in the list; memberchk/2 is non-deterministic and will succeed at most once.
Since this is testing for uniqueness, memberchk/2 is what you'd want, giving you this:
contains(X,Ys) :- memberchk(X,Ys) .
Or you can roll you own (it's trivial):
contains( X , [X|Ys] ) :- ! .
contains( X , [_|Ys] ) :- contains(X,Ys) .
Or even simpler, just a one-liner:
contains( X , [Y|Ys] ) :- X = Y -> true ; contains(X,Ys) .

How to compare sizes of every consecutive element in list - Prolog

Basically, I have an assignment where i need to compare sizes of every pair of elements in a List. The tricky part is:
The second element has to be larger than the first one,
The third element has to be smaller than the second one,
The fourth element has to be larger than the third one,
And so on an so forth alternating until the end od the list.
If this all checks out, then it returns yes, otherwise returns no.
Any ideas?
I know how to compare 2 elements in a list, but i can't wrap my head around comparing each consecutive one. I'm guessing it's supposed to be a recursion where I compare the first element to the second one, then remove the Head and do the same thing until the end, while keeping some kind of flag that tells me if it should be a bigger or a smaller number than the head.
Problem is i'm really new to prolog and i have no idea how to even start writing this properly.
I think this suits a grammar describing a list where you take the first element, look to step up from that to a larger element, then down from that to a smaller element, repeated until you get to the empty list (the end):
updown --> [A], up_from(A).
up_from(A) --> [B], {A<B}, (down_from(B) ; []), !.
down_from(A) --> [B], {A>B}, (up_from(B) ; []), !.
?- phrase(updown, [1,10,5,20]).
true
?- phrase(updown, [1,10,5,2]).
false
Like most recursive problems, there's one general, recursive case, and a few special cases that terminate the recursion.
Let's start with the general case: lists of length 3 or more, [X,Y,Z|Rest] succeeds if X < Y > Z, in which case we discard the first 2 elements, X and Y, and recurse down on the remainder:
alternating_values( [X,Y,Z|Ns] ) :- X < Y , Y > Z , alternating_values([Z|Ns]) .
The special, non-recursive, terminating cases deal with lists of lengths < 3:
The empty list ([]): this succeeds because there's nothing to compare:
alternating_values( [] ) .
Lists of length 1 ([X]): This likewise succeeds because there's nothing to which the single item can be compared, and if the original list was of length 3 or more, it was compared to item immediately preceding it in list in the previous iteration.
alternating_values( [_] ) .
Lists of length 2 ([X,Y]): This succeeds if X < Y.
alternating_values( [X,Y] ) :- X < Y .
Putting it all together, you get this, which you can fiddle with at SWI Prolog's Swish sandbox:
alternating_values( [] ) .
alternating_values( [_] ) .
alternating_values( [X,Y] ) :- X < Y .
alternating_values( [X,Y,Z|Ns] ) :- X < Y , Y > Z , alternating_values([Z|Ns]) .
Another approach might be to use a helper predicate that carries an additional bit of state. This eliminates the need to deals with lists of length 2, since we're only removing one element at a time:
alternating_values( Xs ) :- alternating_values( Xs , lt ) .
alternating_values( [] , _ ) .
alternating_values( [_] , _ ) .
alternating_values( [X,Y|Zs] , lt ) :- cmp(CC,X,Y,CC1), alternating_values([Y|Zs],CC1) .
alternating_values( [X,Y|Zs] , gt ) :- cmp(CC,X,Y,CC1), alternating_values([Y|Zs],CC1) .
cmp( lt , X , Y , gt ) :- X < Y .
cmp( gt , X , Y , lt ) :- X > Y .
But I like the first approach better. It's simpler and more straightforward.
% Allow list to terminate here
lower_higher_alternating([]).
lower_higher_alternating([H|T]) :-
lower_higher_alternating_(T, H).
lower_higher_alternating_([], _).
% P = previous element, H = head, T = tail
lower_higher_alternating_([H|T], P) :-
% Compare using "standard order"
P #< H,
higher_lower_alternating_(T, H).
higher_lower_alternating_([], _).
higher_lower_alternating_([H|T], P) :-
% Other comparison
P #> H,
% Check next 2 elements
lower_higher_alternating([H|T]).
Results in swi-prolog:
?- lower_higher_alternating([1,5,3,4,2]).
true.
?- lower_higher_alternating([1,0,3,4,2]).
false.
Alternative method, with same results:
lower_higher_alternating([]).
lower_higher_alternating([H|T]) :-
lower_higher_alternating_(T, H, <).
lower_higher_alternating_([], _, _).
% P = previous element, H = head, T = tail
lower_higher_alternating_([H|T], P, C) :-
compare(C, P, H),
next_comp(C, C1),
lower_higher_alternating_(T, H, C1).
next_comp(<, >).
next_comp(>, <).

SWI-Prolog predicates member and nth1 without unification?

If I use the predicates member or the nt1 in SWI-Prolog as follows:
?- member(X, [A]).
X = A.
or
nth1(N, [A], X).
N = 1,
A = X.
The interpreter unifies the variable A as X.
Is their some alternative version of this functions which does not use the unification. Means, if I call something like this:
?- _member(X, [A]).
it would give
false
as long as the call is not
?- member(X, [X]).
which would lead to
true
And in the same way
_nth1(N, [A], X).
would give false
but
_nth1(N, [X], X).
would give
N = 1
Seems like you just need to roll your own using ==/2 instead of =/2:
See https://swish.swi-prolog.org/p/DqhYGuEf.pl
is_member_of( X , [Y|_] ) :- X == Y .
is_member_of( X , [_|Ys] ) :- is_member_of(X,Ys) .
is_nth0( N , L , E ) :- is_nth(0,L,E,N) .
is_nth1( N , L , E ) :- is_nth(1,L,E,N) .
is_nth( N , [Y|_] , X , N ) :- X == Y .
is_nth( I , [_|Ys] , X , N ) :- J is I+1, is_nth(J,Ys,X,N) .

Definite Logic Program

The aim is to implement the predicate noDupl/2.
The first argument of this predicate is the list to analyze and second argument is the list of numbers which are no duplicate.
I could not understand code below and when I compiled it, it gave an error message that contained is undefined procedure, however as a hint it is written that we can use as predefined predicate contained and notContained. I think I need to define contained and notContained.
noDupl(XS, Res):-
help( XS, [],Res).
help([],_,[]).
help([X|XS],Seen,[X|Res]):-
notContained(X,XS),
notContained(X,Seen),
help(XS, [X|Seen], Res).
help([X|XS],Seen,Res):-
contained(X,Seen),
help(XS, Seen, Res).
help([X|XS],Seen,Res):-
contained(X,XS),
help(XS, [X|Seen], Res).
Could someone please explain me the problem.
The missing definitions might be:
contained(X,[X|_]).
contained(X,[E|Es]) :-
dif(X, E),
contained(X, Es).
notContained(_X, []).
notContained(X, [E|Es]) :-
dif(X, E),
notContained(X, Es).
(I like to call these relations rather memberd/2 and non_member/2.)
The definition you gave extends the relation with an extra argument for the elements considered so far.
To understand the meaning of each clause, read each right-to-left in the direction of the arrow (the :- is a 1970's ASCII-fication of ←). Let's take the first rule:
Provided, that X is not an element of XS, and
provided, that X is not an element of Seen, and
provided, that help(X, [X|Seen], Res) is true,
then also help([X|XS],Seen,[X|Res]) is true.
In other words, if X is neither in the list of visited elements Seen nor in the elements yet to be visited XS, then it does not possess a duplicate.
What is a bit difficult to understand is whether or not the clauses you gave are mutually exclusive - this is, strictly speaking, not your concern, as long as you are only interested in declarative properties, but it is a good idea to avoid such redundancies.
Here is a case, where such redundancy shows:
?- noDupl([a,a,a],U).
U = []
; U = []
; false.
Ideally, the system would give one determinate answer:
?- noDupl([a,a,a], U).
U = [].
Personally, I do not like a lot to split things into too many cases. Essentially, we could have two: it is a duplicate, and it is none.
It is possible to provide a definition that is correct and still fully determinate for the cases where determinism is possible - such as when the first argument is "sufficiently instantiated" (which includes a ground list). Let's see if there are some answers into that direction.
I've annotated your code for you:
noDupl( XS , Res ) :- % Res is the [unique] set of element from the bag XS
help( XS, [],Res) % if invoking the helper succeeds.
. %
help( [] , _ , [] ) . % the empty list is unique.
help( [X|XS] , Seen , [X|Res] ) :- % A non-empty list is unique, if...
notContained(X,XS), % - its head (X) is not contained in its tail (XS), and
notContained(X,Seen), % - X has not already been seen, and
help(XS, [X|Seen], Res). % - the remainder of the list is unique.
help( [X|XS] , Seen , Res ) :- % otherwise...
contained(X,Seen) , % - if X has been seen,
help(XS, Seen, Res). % - we discard it and recurse down on the tail.
help([X|XS],Seen,Res):- % otherwise...
contained(X,XS), % - if X is in the tail of the source list,
help(XS, [X|Seen], Res). % - we discard it (but add it to 'seen').
Your contained/2 and notContained/2` predicates might be defined as this:
contained( X , [X|_] ) :- ! .
contained( X , [Y|Ys] ) :- X \= Y , contained( X , Ys ) .
not_contained( _ , [] ) .
not_contained( X , [Y|Ys] ) :- X \= Y , not_contained(X,Ys) .
Now, I may be missing something in your code, but there's an awful lot of redundancy in it. You could simply write something like this (using the built-ins member/2 and reverse/2):
no_dupes( List , Unique ) :- no_dupes( Bag , [] , Set ) .
no_dupes( [] , V , S ) . % if we've exhausted the bag, the list of visited items is our set (in reverse order of the source)
reverse(V,S) % - reverset it
. % - to put our set in source order
no_dupes( [X|Xs] , V , S ) :- % otherwise ...
( member(X,V) -> % - if X is already in the set,
V1 = V % - then we discard X
; V1 = [X|V] % - else we add X to the set
) , % And...
no_dupes( Xs , V1 , S ) % we recurse down on the remainder
. % Easy!
Can this be done in a pure and efficient way?
Yes, by using
tpartition/4 and (=)/3 like so:
dups_gone([] ,[]).
dups_gone([X|Xs],Zs0) :-
tpartition(=(X),Xs,Ts,Fs),
if_(Ts=[], Zs0=[X|Zs], Zs0=Zs),
dups_gone(Fs,Zs).
Some sample ground queries (all of which succeed deterministically):
?- dups_gone([a,a,a],Xs).
Xs = [].
?- dups_gone([a,b,c],Xs).
Xs = [a, b, c].
?- dups_gone([a,b,c,b],Xs).
Xs = [a, c].
?- dups_gone([a,b,c,b,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a,c],Xs).
Xs = [].
This also works with more general queries. Consider:
?- length(Xs,N), dups_gone(Xs,Zs).
N = 0, Xs = [], Zs = []
; N = 1, Xs = [_A], Zs = [_A]
; N = 2, Xs = [_A,_A], Zs = []
; N = 2, Xs = [_A,_B], Zs = [_A,_B], dif(_A,_B)
; N = 3, Xs = [_A,_A,_A], Zs = []
; N = 3, Xs = [_A,_A,_B], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_A,_B,_A], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_B,_A,_A], Zs = [_B], dif(_A,_B), dif(_A,_B)
; N = 3, Xs = [_A,_B,_C], Zs = [_A,_B,_C], dif(_A,_B), dif(_A,_C), dif(_B,_C)
; N = 4, Xs = [_A,_A,_A,_A], Zs = []
...

How could you find and remove an element from a list in prolog?

I have a list I need to find an element and remove it.
The idea I'm going on is to remove it if it's the head and join that with removing it if it's the head of the tail. I have no idea how to do that though.
Any advice is appreciated.
This is what I've got
choice(8, X):-
nl, write('\tRemove a student from roster:'),nl,nl,
write('\tEnter student name or ID : '), read(S), remove(S, X, X2), nl, menu(X2).
remove(S, [], []):- write('\tStudent '), writef("%s", [S]), write(' is not in the roster.'),nl.
remove(S, [[I,N,G]|T], X):-
S = I -> X = T2, remove(S, T, T2);
T = [] -> X = [];
X = [[I,N,G]|T2], remove(S, T, T2).
I want it to remove all occurrences.
Stay pure by using meta-predicate tfilter/3 together with reified term inequality dif/3:
?- tfilter(dif(x),[x,1,2,x,3,4,5,x,6,x,x,7],Xs).
Xs = [1,2,3,4,5,6,7]. % succeeds deterministically
removes(S, [], []):- write('\tStudent '), writef("%s", [S]), write(' is not in the roster.'),nl.
removes(S, [[I,N,G]|T], X):- remove(S, [[I,N,G]|T], X).
remove(S, [], []).
remove(S, [[I,N,G]|T], X):-
S = I -> X = T2,
write('\tStudent '),writef("%s", [S]),write(' removed.'),nl,
remove(S, T, T2);
S = N -> X = T2,
write('\tStudent '),writef("%s", [S]),write(' removed.'),nl,
remove(S, T, T2);
X = [[I,N,G]|T2], remove(S, T, T2).
the link from lurker was helpful. I needed another function. Adding removes fixed it.
One way, using built-ins:
remove(X,L,R) :- % to remove all X from L:
append(P,[X|S],L), % - break L into a prefix P, X itself and a suffix S
append(P,S,T) , % - append the prefix and suffix together to form a new list
remove(X,T,R) % - and remove X from that list
. %
remove(X,L,L) :- % otherwise, succeed, leaving L unchanged
\+ member(X,L) % - if X is not contained in L
. %
Or you can do it the hard way — not that hard! — and roll your own:
remove( X , [] , [] ) . % removing X from the empty list yields the empty list
remove( X , [X|Ls] , R ) :- % removing X from a non-empty list consists of
remove( X , Ls , R ) % - tossing X if it's the head of the list, and
. % - recursing down.
remove( X , [L|Ls] , [L|R] ) :- % or ...
X \= L , % - if X is not the head of the list,
remove( X , Ls , R ) % - simply recursing down.
. % Easy!
Not that this is no less clear or elegant than than using append/3 and, probably faster/more efficient.

Resources