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.
Prolog predicate next(X, List,List1), that returns in List1 the next element(s) from List that follows X, e.g., next(a,[a,b,c,a,d],List1), will return List1=[b,d].
I have tried following:
next(X, [X,Y|List], [Y|List1]) :- % X is the head of the list
next(X, [Y|List], List1).
next(X, [Y|List], List1) :- % X is not the head of the list
X \== Y,
next(X, List, List1).
next(_,[], []).
First, whenever possible, use prolog-dif for expressing term inequality!
Second, the question you asked is vague about corner cases: In particular, it is not clear how next(E,Xs,Ys) should behave if there are multiple neighboring Es in Xs or if Xs ends with E.
That being said, here's my shot at your problem:
next(E,Xs,Ys) :-
list_item_nexts(Xs,E,Ys).
list_item_nexts([],_,[]).
list_item_nexts([E],E,[]).
list_item_nexts([I|Xs],E,Ys) :-
dif(E,I),
list_item_nexts(Xs,E,Ys).
list_item_nexts([E,X|Xs],E,[X|Ys]) :-
list_item_nexts(Xs,E,Ys).
Let's see some queries!
?- next(a,[a,b,c,a,d],List1).
List1 = [b,d] ;
false.
?- next(a,[a,a,b,c,a,d],List1).
List1 = [a,d] ;
false.
?- next(a,[a,a,b,c,a,d,a],List1).
List1 = [a,d] ;
false.
Note that above queries succeed, but leave behind useless choicepoints.
This inefficiency can be dealt with, but I suggest figuring out more complete specs first:)
This version is deterministic for the cases given by #repeat using if_/3 and (=)/3. It shows how purity and efficiency can coexist in one and the same Prolog program.
next(E, Xs, Ys) :-
xs_e_(Xs, E, Ys).
xs_e_([], _E, []).
xs_e_([X|Xs], E, Ys) :-
if_(X = E, xs_e_xys(Xs, E, Ys), xs_e_(Xs, E, Ys)).
xs_e_xys([], _E, []).
xs_e_xys([X|Xs], E, [X|Ys]) :-
xs_e_(Xs, E, Ys).
%xs_e_xys([X|Xs], E, [X|Ys]) :- % alternate interpretation
% xs_e_([X|Xs], E, Ys).
Is it possible to get a predicate with already built-in ones (in swi-prolog) such that:
Wanted_Pred(X, a) %false
Wanted_Pred(b, a) %false
Wanted_Pred(X, Y) %true
Wanted_Pred(X, X) %true
Wanted_Pred(X, [Y|Z]) %false
Wanted_Pred([A|B], [X,Y|Z]) %false
Wanted_Pred([A,C|B], [X,Y|Z]) %true
e.g. succeeds iff both arguments represent each others free variable renaming,
note that copy_term doesn't do it as it unifies arguments in the end:
copy_term(X, a) %true
copy_term(X, [Y|Z]) %true
copy_term([A|B], [X,Y|Z]) %true
subsumes_term/2 perfectly fits your requirements, just swap the arguments:
?- subsumes_term(a,X).
false.
?- subsumes_term(a,b).
false.
?- subsumes_term(Y,X).
true.
?- subsumes_term(X,X).
true.
?- subsumes_term([Y|Z],X).
false.
?- subsumes_term([X,Y|Z],[A|B]).
false.
?- subsumes_term([X,Y|Z],[A,C|B]).
true.
I've seen a fairly recent thread on SWI-Prolog mailing list on the efficient implementation of (=#=)/2, that I think it's related (actually, it also satisfies your requirements): putting it to good use should be the best option available.
edit correcting the link to mailing list. Recent switch of list' hosting to google groups made the archive unavailable...
You can find the thread for instance in archived discussions, searching for the author, Kuniaki Mukai
Here is the predicated I am searching implemented by me but
I WANT TO FIND OUT IF THIS KIND OF PREDICATE IS BUILT_IN OR SIMILAR ONE IN SWI-PROLOG.
true_copy(X, Y) :-
(X == Y, !);
(var(X), var(Y), !);
((var(X); var(Y)) -> !, fail);
(atom(X), atom(Y) -> !, fail).
true_copy([X | L1], [Y | L2]) :-
!,
true_copy(X, Y),
true_copy(L1, L2).
true_copy(Term1, Term2) :-
Term1 =.. L1,
Term2 =.. L2,
true_copy(L1, L2).
I have a problem with predicate which works in that way that it takes list of atoms:
nopolfont([to,jest,tekśćik,'!'],L).
and in result
L = [to,jest,tekscik,'!'].
I have problem with make_swap and swap predicates. So far I have:
k(ś,s).
k(ą,a).
% etc.
swap(X,W) :- name(X,P), k(P,Y), !, name(Y,W).
swap(X,X).
make_swap(A,W)
:- atom(A),!,
name(A,L),
swap(L,NL),
name(W,NL).
nopolfont([],[]).
nopolfont([H|T],[NH|S]) :- make_swap(H,NH), nopolfont(T,S).
Is there any elegant way to do this?
This is also quite elegant:
polish_char_replacer(X, Y) :-
k(X, Y),
!.
polish_char_replacer(X, X).
nopolfont(Atoms1, Atoms2) :-
maplist(replace(polish_char_replacer), Atoms1, Atoms2).
replace(Goal, Atom1, Atom2) :-
atom_chars(Atom1, Chars1),
maplist(Goal, Chars1, Chars2),
atom_chars(Atom2, Chars2).
Probably as elegant as it can get:
k(ś,s).
k(ą,a).
swap(X,W) :- name(P,[X]), k(P,Y), !, name(Y,[W]).
swap(X,X).
list_swap([], []).
list_swap([H|T], [W|S]) :-
swap(H, W),
list_swap(T, S).
atom_swap(A,W) :-
atom(A), !,
name(A, L),
list_swap(L,S),
name(W, S).
nopolfont([],[]).
nopolfont([H|T],[NH|S]) :-
atom_swap(H,NH),
nopolfont(T,S).
Also, obviously define this, to get the expected result, but I assume this is in the % etc
k(ć, c).