Predicate to filter non constants from a list - prolog

I'm working on a predicate only_atoms/2(List+, Result-) that I'd like to filter non atoms.
For example :
only_atoms([1, 2, X, h(Y), 'aba'], Result).
should return
Result = [1, 2, 'aba'].
I do not care about the order.
Here is the piece of code I came up with :
only_atoms([], []) :- !.
only_atoms([Head | Tail], [Head | Result]) :-
atom(Head),
!,
only_atoms(Tail, Result).
only_atoms([_ | Tail], Result) :-
only_atoms(Tail, Result).
I thought this was the right kind of reasoning to handle such a problem but seem to be wrong since it yields me [](edit : it actually yields [aba], see precisions below, my bad !) no matter what. I'd appreciate some help !

A first hint: for 1 and 2, atom returns false.
By the way, I was looking for the filter predicate, in the standard library it happens to be called include, it's usually better if you use what the language already provides ;-)
?- include(atom, [1, 2, X, h(Y), 'aba'], Result).
Result = [aba].
or if you wanted just to filter out variables:
?- exclude(var, [1, 2, X, h(Y), 'aba'], Result).
Result = [1, 2, h(Y), aba].
Another by the way, one curious difference between your only_atoms and using include(atom, ...) is that yours will unify variables in the first list with atoms in the second list, whereas the include won't.
?- only_atoms([1, x, 2, Y], [x, y]).
Y = y.
?- include(atom, [1, x, 2, Y], [x, y]).
false.
Those subtleties of Prolog always astonish me (I guess that's because I didn't pay enough attention at the university xD).

You probably need to force the Head not to be an atom on the alternate clause, otherwise it is an option for atoms as well.
This returns Result = ['aba'] for me.
only_atoms([], []).
only_atoms([Head | Tail], [Head | Result]) :- atom(Head), !, only_atoms(Tail, Result).
only_atoms([Head | Tail], Result) :- \+atom(Head), !, only_atoms(Tail, Result).
Alternatively, you could try using findall/3.
atoms_list(List, Result) :- findall(Item, (member(Item, List), atom(Item)), Result).

Related

PROLOG: Determining if elements in list are equal if order does not matter

I'm trying to figure out a way to check if two lists are equal regardless of their order of elements.
My first attempt was:
areq([],[]).
areq([],[_|_]).
areq([H1|T1], L):- member(H1, L), areq(T1, L).
However, this only checks if all elements of the list on the left exist in the list on the right; meaning areq([1,2,3],[1,2,3,4]) => true. At this point, I need to find a way to be able to test thing in a bi-directional sense. My second attempt was the following:
areq([],[]).
areq([],[_|_]).
areq([H1|T1], L):- member(H1, L), areq(T1, L), append([H1], T1, U), areq(U, L).
Where I would try to rebuild the lest on the left and swap lists in the end; but this failed miserably.
My sense of recursion is extremely poor and simply don't know how to improve it, especially with Prolog. Any hints or suggestions would be appreciated at this point.
As a starting point, let's take the second implementation of equal_elements/2 by #CapelliC:
equal_elements([], []).
equal_elements([X|Xs], Ys) :-
select(X, Ys, Zs),
equal_elements(Xs, Zs).
Above implementation leaves useless choicepoints for queries like this one:
?- equal_elements([1,2,3],[3,2,1]).
true ; % succeeds, but leaves choicepoint
false.
What could we do? We could fix the efficiency issue by using
selectchk/3 instead of
select/3, but by doing so we would lose logical-purity! Can we do better?
We can!
Introducing selectd/3, a logically pure predicate that combines the determinism of selectchk/3 and the purity of select/3. selectd/3 is based on
if_/3 and (=)/3:
selectd(E,[A|As],Bs1) :-
if_(A = E, As = Bs1,
(Bs1 = [A|Bs], selectd(E,As,Bs))).
selectd/3 can be used a drop-in replacement for select/3, so putting it to use is easy!
equal_elementsB([], []).
equal_elementsB([X|Xs], Ys) :-
selectd(X, Ys, Zs),
equal_elementsB(Xs, Zs).
Let's see it in action!
?- equal_elementsB([1,2,3],[3,2,1]).
true. % succeeds deterministically
?- equal_elementsB([1,2,3],[A,B,C]), C=3,B=2,A=1.
A = 1, B = 2, C = 3 ; % still logically pure
false.
Edit 2015-05-14
The OP wasn't specific if the predicate
should enforce that items occur on both sides with
the same multiplicities.
equal_elementsB/2 does it like that, as shown by these two queries:
?- equal_elementsB([1,2,3,2,3],[3,3,2,1,2]).
true.
?- equal_elementsB([1,2,3,2,3],[3,3,2,1,2,3]).
false.
If we wanted the second query to succeed, we could relax the definition in a logically pure way by using meta-predicate
tfilter/3 and
reified inequality dif/3:
equal_elementsC([],[]).
equal_elementsC([X|Xs],Ys2) :-
selectd(X,Ys2,Ys1),
tfilter(dif(X),Ys1,Ys0),
tfilter(dif(X),Xs ,Xs0),
equal_elementsC(Xs0,Ys0).
Let's run two queries like the ones above, this time using equal_elementsC/2:
?- equal_elementsC([1,2,3,2,3],[3,3,2,1,2]).
true.
?- equal_elementsC([1,2,3,2,3],[3,3,2,1,2,3]).
true.
Edit 2015-05-17
As it is, equal_elementsB/2 does not universally terminate in cases like the following:
?- equal_elementsB([],Xs), false. % terminates universally
false.
?- equal_elementsB([_],Xs), false. % gives a single answer, but ...
%%% wait forever % ... does not terminate universally
If we flip the first and second argument, however, we get termination!
?- equal_elementsB(Xs,[]), false. % terminates universally
false.
?- equal_elementsB(Xs,[_]), false. % terminates universally
false.
Inspired by an answer given by #AmiTavory, we can improve the implementation of equal_elementsB/2 by "sharpening" the solution set like so:
equal_elementsBB(Xs,Ys) :-
same_length(Xs,Ys),
equal_elementsB(Xs,Ys).
To check if non-termination is gone, we put queries using both predicates head to head:
?- equal_elementsB([_],Xs), false.
%%% wait forever % does not terminate universally
?- equal_elementsBB([_],Xs), false.
false. % terminates universally
Note that the same "trick" does not work with equal_elementsC/2,
because of the size of solution set is infinite (for all but the most trivial instances of interest).
A simple solution using the sort/2 ISO standard built-in predicate, assuming that neither list contains duplicated elements:
equal_elements(List1, List2) :-
sort(List1, Sorted1),
sort(List2, Sorted2),
Sorted1 == Sorted2.
Some sample queries:
| ?- equal_elements([1,2,3],[1,2,3,4]).
no
| ?- equal_elements([1,2,3],[3,1,2]).
yes
| ?- equal_elements([a(X),a(Y),a(Z)],[a(1),a(2),a(3)]).
no
| ?- equal_elements([a(X),a(Y),a(Z)],[a(Z),a(X),a(Y)]).
yes
In Prolog you often can do exactly what you say
areq([],_).
areq([H1|T1], L):- member(H1, L), areq(T1, L).
bi_areq(L1, L2) :- areq(L1, L2), areq(L2, L1).
Rename if necessary.
a compact form:
member_(Ys, X) :- member(X, Ys).
equal_elements(Xs, Xs) :- maplist(member_(Ys), Xs).
but, using member/2 seems inefficient, and leave space to ambiguity about duplicates (on both sides). Instead, I would use select/3
?- [user].
equal_elements([], []).
equal_elements([X|Xs], Ys) :-
select(X, Ys, Zs),
equal_elements(Xs, Zs).
^D here
1 ?- equal_elements(X, [1,2,3]).
X = [1, 2, 3] ;
X = [1, 3, 2] ;
X = [2, 1, 3] ;
X = [2, 3, 1] ;
X = [3, 1, 2] ;
X = [3, 2, 1] ;
false.
2 ?- equal_elements([1,2,3,3], [1,2,3]).
false.
or, better,
equal_elements(Xs, Ys) :- permutation(Xs, Ys).
The other answers are all elegant (way above my own Prolog level), but it struck me that the question stated
efficient for the regular uses.
The accepted answer is O(max(|A| log(|A|), |B|log(|B|)), irrespective of whether the lists are equal (up to permutation) or not.
At the very least, it would pay to check the lengths before bothering to sort, which would decrease the runtime to something linear in the lengths of the lists in the case where they are not of equal length.
Expanding this, it is not difficult to modify the solution so that its runtime is effectively linear in the general case where the lists are not equal (up to permutation), using random digests.
Suppose we define
digest(L, D) :- digest(L, 1, D).
digest([], D, D) :- !.
digest([H|T], Acc, D) :-
term_hash(H, TH),
NewAcc is mod(Acc * TH, 1610612741),
digest(T, NewAcc, D).
This is the Prolog version of the mathematical function Prod_i h(a_i) | p, where h is the hash, and p is a prime. It effectively maps each list to a random (in the hashing sense) value in the range 0, ...., p - 1 (in the above, p is the large prime 1610612741).
We can now check if two lists have the same digest:
same_digests(A, B) :-
digest(A, DA),
digest(B, DB),
DA =:= DB.
If two lists have different digests, they cannot be equal. If two lists have the same digest, then there is a tiny chance that they are unequal, but this still needs to be checked. For this case I shamelessly stole Paulo Moura's excellent answer.
The final code is this:
equal_elements(A, B) :-
same_digests(A, B),
sort(A, SortedA),
sort(B, SortedB),
SortedA == SortedB.
same_digests(A, B) :-
digest(A, DA),
digest(B, DB),
DA =:= DB.
digest(L, D) :- digest(L, 1, D).
digest([], D, D) :- !.
digest([H|T], Acc, D) :-
term_hash(H, TH),
NewAcc is mod(Acc * TH, 1610612741),
digest(T, NewAcc, D).
One possibility, inspired on qsort:
split(_,[],[],[],[]) :- !.
split(X,[H|Q],S,E,G) :-
compare(R,X,H),
split(R,X,[H|Q],S,E,G).
split(<,X,[H|Q],[H|S],E,G) :-
split(X,Q,S,E,G).
split(=,X,[X|Q],S,[X|E],G) :-
split(X,Q,S,E,G).
split(>,X,[H|Q],S,E,[H|G]) :-
split(X,Q,S,E,G).
cmp([],[]).
cmp([H|Q],L2) :-
split(H,Q,S1,E1,G1),
split(H,L2,S2,[H|E1],G2),
cmp(S1,S2),
cmp(G1,G2).
A simple solution using cut.
areq(A,A):-!.
areq([A|B],[C|D]):-areq(A,C,D,E),areq(B,E).
areq(A,A,B,B):-!.
areq(A,B,[C|D],[B|E]):-areq(A,C,D,E).
Some sample queries:
?- areq([],[]).
true.
?- areq([1],[]).
false.
?- areq([],[1]).
false.
?- areq([1,2,3],[3,2,1]).
true.
?- areq([1,1,2,2],[2,1,2,1]).
true.

swi Prolog - Error arguments not sufficiently Instantiated

I am new to Prolog and when I query
sortedUnion([1,1,1,2,3,4,4,5], [0,1,3,3,6,7], [0,1,2,3,4,5,6,7]).
I get an error
Exception: (7) unite([_G114, _G162, _G201, _G231, _G243], [_G249, _G297, _G336, _G357, _G369], [0, 1, 2, 3, 4, 5, 6, 7]) ?
So I am hoping someone will be able to tell me where my code is mistaken and why it is wrong?
%undup(L, U) holds precisely when U can be obtained from L by eliminating repeating occurrences of the same element
undup([], []).
undup([X|Xs], [_|B]) :- remove(X,Xs,K), undup(K, B).
remove(_,[],[]).
remove(Y,[Y|T],D) :- remove(Y,T,D).
remove(Y,[S|T],[S|R]) :- not(Y = S), remove(Y,T,R).
%sortedUnion(L1,L2,U) holds when U contains exactly one instance of each element
%of L1 and L2
sortedunion([H|T], [S|R], [F|B]) :- undup([H|T], N), undup([S|R], M), unite(N,M,[F|B]).
unite([], [], []).
unite([X], [], [X]).
unite([], [X], [X]).
unite([H|T], [S|R], [X|Xs]) :- S=H, X is S, unite(T, R, Xs).
unite([H|T], [S|R], [X|Xs]) :- H<S, X is H, unite(T, [S|R], Xs).
unite([H|T], [S|R], [X|Xs]) :- S<H, X is S, unite([H|T], R, Xs).
An advice first: try to keep your code as simple as possible. Your code can reduce to this (that surely works)
sortedunion(A, B, S) :-
append(A, B, C),
sort(C, S).
but of course it's instructive to attempt to solve by yourself. Anyway, try to avoid useless complications.
sortedunion(A, B, S) :-
undup(A, N),
undup(B, M),
unite(N, M, S).
it's equivalent to your code, just simpler, because A = [H|T] and so on.
Then test undup/2:
1 ?- undup([1,1,1,2,3,4,4,5],L).
L = [_G2760, _G2808, _G2847, _G2877, _G2889] ;
false.
Clearly, not what you expect. The culprit should that anon var. Indeed, this works:
undup([], []).
undup([X|Xs], [X|B]) :- remove(X,Xs,K), undup(K, B).
2 ?- undup([1,1,1,2,3,4,4,5],L).
L = [1, 2, 3, 4, 5] ;
false.
Now, unite/3. First of all, is/2 is abused. It introduces arithmetic, then plain unification suffices here: X = S.
Then the base cases are hardcoded to work where lists' length differs at most by 1. Again, simpler code should work better:
unite([], [], []).
unite( X, [], X).
unite([], X, X).
...
Also, note the first clause is useless, being already covered by (both) second and third clauses.

Removing first occurrence in list - prolog

I need to remove only one occurrence in the list. Actually doesn't matter if it's first or last. One match needs to be removed.
I'm having trouble understanding why the following doesn't work as intended.
deleteOne(_,[],[]).
deleteOne(Term, [Term|Tail], Result) :-
deleteOne(Term, [], [Result|Tail]), !.
deleteOne(Term, [Head|Tail], [Head|TailResult]) :-
deleteOne(Term, Tail, TailResult), !.
Output
41 ?- deleteOne(5,[2,3,1,5,2,3,1],X).
X = [2, 3, 1, 5, 2, 3, 1].
It works when I replace term with an empty String or some random String.
deleteOne(Term, [Term|Tail], Result) :-
deleteOne("", Tail, Result), !.
Output
41 ?- deleteOne(5,[2,3,1,5,2,3,1],X).
X = [2, 3, 1, 2, 3, 1].
But I don't think this is the best solution for many reasons. Not for my current problem, but for example longer lists. Or if a list contains empty String - don't know if this is possible in Prolog.
Why wont the first example work? And what other solutions are there?
Your first one doesn't work because this doesn't make much sense:
deleteOne(Term, [Term|Tail], Result) :-
deleteOne(Term, [], [Result|Tail]), !.
That means the result of the next one has to have the current result as its head.
An better solution would be this:
delete_one(_, [], []).
delete_one(Term, [Term|Tail], Tail).
delete_one(Term, [Head|Tail], [Head|Result]) :-
delete_one(Term, Tail, Result).
If you want it to be determinative, add a cut on the second clause. As is, it can do this:
?- delete_one(2, [1, 2, 3, 1, 2, 3], X).
X = [1,3,1,2,3] ? ;
X = [1,2,3,1,3] ? ;
X = [1,2,3,1,2,3] ? ;
no
To delete only the first occurrence of an item X from a list L.Here I used cut operation.
delete(X,[X|T],T):-!.
delete(X,[Y|T],[Y|T1]):-delete(X,T,T1).

prolog lists and list manipulation

i am trying to write a binary predicate to take one list, compute mod 5 for each element and then put it in another list. so far, i have done this,
mod5(X,L):- R = [], modhelper(R,L), write(R).
modhelper(X,L):- memb(E,L), mod2(E,Z), addtolist(Z,X,X), modhelper(X,L).
%Get an element from the list L.
memb(E,[E|_]).
memb(E,[_|V]):- memb(E,V).
%If element is integer, return that integer mod 5 else return as is.
mod2(N,Z):- isInt(N) -> Z is N mod 5 ; Z = N.
%add this modified element to the output list.
addtolist(Y,[],[Y]).
addtolist(Y,[H|T],[H|N]):- addtolist(Y,T,N).
memb,mod2, addtolist work as expected but I'm doing something wrong in modhelper which I'm not able to figure out.
Any help is appreciated.
In SWI-Prolog:
mod5(X, Y) :-
Y is X mod 5.
apply_mod5_to_list(L1, L2) :-
maplist(mod5, L1, L2).
Usage:
?- apply_mod5_to_list([2, 4, 6, 8], L2).
L2 = [2, 4, 1, 3].
?- apply_mod5_to_list([2, 4.1, 6, 8], L2).
ERROR: mod/2: Type error: `integer' expected, found `4.1'
?- apply_mod5_to_list([2, not_number, 6, 8], L2).
ERROR: is/2: Arithmetic: `not_number/0' is not a function
You can easily modify this code if you want a slightly different behavior, e.g. if you want to tolerate non-integers (why do you want that btw?).
In case you cannot use maplist, you can implement it yourself, at least a more specialized version of it, e.g. something like this:
partition_the_list_into_first_and_rest([X | Xs], X, Xs).
% The result on an empty list is an empty list
apply_mod5_to_list([], []).
% If the input list contains at least one member
apply_mod5_to_list(L1, L2) :-
partition_the_list_into_first_and_rest(L1, X, Xs),
call(mod5, X, Y),
partition_the_list_into_first_and_rest(L2, Y, Ys),
apply_mod5_to_list(Xs, Ys).
To this code you can still apply a lot of syntactic simplification, which you should probably do to turn it into an acceptable homework solution...

Prolog - outputting a list?

I have the function
sublist(_,[_],_) :-
!.
sublist(X,[Y|T],Z) :-
R is X - Y,
sublist(X,T,[R|Z]).
an example call is sublist(2,[1,2,3],Z).
At the end of execution it just gives me 'yes', but i'd like to see the contents of Z.
I know it's something simple as i have other instructions that do similar things, but this one isn't working.
I'm also going to assume that sublist/3 is supposed to subtract a number from all items in the list.
The reason you're not getting any result for Z is because you're building the list on the way into the recursion. Which means that when the stopping predicate succeeds, Prolog works it's way back out of the recursion and Z becomes uninstantiated again.
Z is ?
|
Z is [-1]
|
Z is [-1, 0]
|
Z is [-1, 0, 1]
|
Z is [-1, 0]
|
Z is [-1]
|
Z is ?
Try going into the recursion first and building your list on the way out. Maybe like this:
subtract_list(_, [], []).
subtract_list(Number, [Head|Tail], [Subtracted|Result]):-
subtract_list(Number, Tail, Result),
Subtracted is Head - Number.
All we've changed is the order of the rules in the recursive predicate and the terms of the stopping condition. Now it recurses until it reaches an empty list, at which point it instantiates the result variable with an empty list as well. Then it bubbles back up adding values to the list as it does so.
?- subtract_list(1,[4,3,2],Z).
Z = [3, 2, 1]
Hope this helps. Tom
You don't really specify what sublist/3 is supposed to do but maybe you mean this:
sublist(_, [], []) :- !.
sublist(X, [Y | T], [R | Z]) :-
R is X - Y,
sublist(X, T, Z).
Usage example:
?- sublist(2, [1, 2, 3], Z).
Z = [1, 0, -1].
Btw, if you don't want to iterate over the list yourself, then you can use maplist/3 which is provided by SWI-Prolog. First define your desired calculation:
my_calculation(X, Y, Z) :-
Z is X - Y.
and then call maplist/3:
?- maplist(my_calculation(2), [1, 2, 3], Z).
Z = [1, 0, -1].

Resources