Prolog. Difficult beginnings - prolog

At the beginning: I am beginner in Prolog but I have to admit, the language is curious because of the fact other paradigm.
find_kth_e(X, [X|_], 1).
find_kth_e(X, [_|T], K) :- K > 1, K1 is K-1, find_kth_e(X, T, K1).
?- find_kth_e(X, [1,2,3,4,5], 3).
X = 3 ;
false.
What is find_kth_e? Function? Relation? ( Yeah, I know that a function is a relation).
The result is 3. And it is ok. But why the second result is false?
Let's consider a modified version:
find_kth_e(X, [X|_], 1).
find_kth_e(X, [_|T], K) :- K > 1, K1 is K-1, find_kth_e(_, T, K1).
?- find_kth_e(X, [1,2,3,4,5], 3).
X = 3 ;
false.
The only difference is in line: find_kth_e(X, [_|T], K) :- K > 1, K1 is K-1, find_kth_e(_, T, K1).. I replaced X with _. And now:
?- find_kth_e(X, [1,2,3,4,5], 3).
true ;
false.
The answer is true and false. Why there is no 3? After all, the result should be returned by first version of function- I mean find_kth_e(X, [X|_], 1). So, the fact that I replaced X with _ should doesn't matter.
Please explain .

As #EugeneSh. says, Prolog has predicates. A predicate may have one or more predicate clauses (yours has two). A predicate defines a relation between its arguments.
?- find_kth_e(X, [1,2,3,4,5], 3).
X = 3 ;
false.
In this example, you queried whether X is the 3rd argument of list [1,2,3,4,5]. Prolog succeeded with X = 3. But there was a choice point in your predicate, meaning Prolog encountered a place in the code before it succeeded where an alternative decision could be explored. When you pressed ;, you told Prolog to explore that alternative (Prolog backtracks). Prolog found there were no more solutions after X = 3, so Prolog says "false".
When you replaced X with _ you indicated that you didn't care what the first argument is:
?- find_kth_e(_, [1,2,3,4,5], 3).
true ;
false.
As in the first query, Prolog succeeded in finding a 3rd element, but you indicated that you didn't care what that element is. So Prolog succeeds and says only "true". And, as before, the choice point is there. Your ; tells Prolog to backtrack to the choice point and it found no more solutions, so ultimately shows "false".
Here's another little test you can do to show success versus failure:
?- find_kth_e(X, [a,b,c,d,e], 3), write('Success!'), nl.
Success!
X = c ;
false.
Since the find_kth_e/3 succeeded, Prolog continued to the write/1 statement which wrote "Success!" and then showed X = c (Prolog shows all the variables that result in success after the entire clause finishes executing).
Here's a failure case:
?- find_kth_e(X, [a,b,c,d,e], 6), write('Success!'), nl.
false.
?-
find_kth_e/3 could not find a 6th element, so it failed. Prolog did not continue and do the write/1 due to the failure of the prior statement, and you can see "Success!" was not displayed.

Related

Is it possible to write an inconsistent Prolog program using only pure Prolog, cut and `false`?

This one tickled my interest in theory:
Is it possible to write an inconsistent Prolog program, i.e. a program that answers both false and true depending on how it is queried, using only pure Prolog, the cut, and false?
For example, one could query p(1) and the Prolog Processor would says false. But when one queries p(X) the Prolog Processor would give the set of answers 1, 2, 3.
This can be easily achieved with "computational state examination predicates" like var/1 (really better called fresh/1) + el cut:
p(X) :- nonvar(X),!,member(X,[2,3]).
p(X) :- member(X,[1,2,3]).
Then
?- p(1).
false.
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
"Ouch time" ensues if this is high-assurance software. Naturally, any imperative program has no problem going off the rails like this on every other line.
So. can be done without those "computational state examination predicates"?
P.S.
The above illustrates that all the predicates of Prolog are really carrying a threaded hidden argument of the "computational state":
p(X,StateIn,StateOut).
which can be used to explain the behavour of var/1 and friends. The Prolog program is then "pure" when it only calls predicates that neither consult not modify that State. Well, at least that seems to be a good way to look at what is going on. I think.
Here's a very simple one:
f(X,X) :- !, false.
f(0,1).
Then:
| ?- f(0,1).
yes
| ?- f(X,1).
no
| ?- f(0,Y).
no
So Prolog claims there are no solutions to the queries with variables, although f(0,1) is true and would be a solution to both.
Here is one attempt. The basic idea is that X is a variable iff it can be unified with both a and b. But of course we can't write this as X = a, X = b. So we need a "unifiable" test that succeeds without binding variables like =/2 does.
First, we need to define negation ourselves, since it's impure:
my_not(Goal) :-
call(Goal),
!,
false.
my_not(_Goal).
This is only acceptable if your notion of pure Prolog includes call/1. Let's say that it does :-)
Now we can check for unifiability by using =/2 and the "not not" pattern to preserve success while undoing bindings:
unifiable(X, Y) :-
my_not(my_not(X = Y)).
Now we have the tools to define var/nonvar checks:
my_var(X) :-
unifiable(X, a),
unifiable(X, b).
my_nonvar(X) :-
not(my_var(X)).
Let's check this:
?- my_var(X).
true.
?- my_var(1).
false.
?- my_var(a).
false.
?- my_var(f(X)).
false.
?- my_nonvar(X).
false.
?- my_nonvar(1).
true.
?- my_nonvar(a).
true.
?- my_nonvar(f(X)).
true.
The rest is just your definition:
p(X) :-
my_nonvar(X),
!,
member(X, [2, 3]).
p(X) :-
member(X, [1, 2, 3]).
Which gives:
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
?- p(1).
false.
Edit: The use of call/1 is not essential, and it's interesting to write out the solution without it:
not_unifiable(X, Y) :-
X = Y,
!,
false.
not_unifiable(_X, _Y).
unifiable(X, Y) :-
not_unifiable(X, Y),
!,
false.
unifiable(_X, _Y).
Look at those second clauses of each of these predicates. They are the same! Reading these clauses declaratively, any two terms are not unifiable, but also any two terms are unifiable! Of course you cannot read these clauses declaratively because of the cut. But I find this especially striking as an illustration of how catastrophically impure the cut is.

Why does returning false? [duplicate]

I implemented the following power program in Prolog:
puissance(_,0,1).
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
The code does what is supposed to do, but after the right answer it prints "false.". I don't understand why. I am using swi-prolog.
Can do like this instead:
puissance(X,N,P) :-
( N > 0 ->
A is N-1,
puissance(X,A,Z),
P is Z*X
; P = 1 ).
Then it will just print one answer.
(Your code leaves a `choice point' at every recursive call, because you have two disjuncts and no cut. Using if-then-else or a cut somewhere removes those. Then it depends on the interpreter what happens. Sicstus still asks if you want ((to try to find)) more answers.)
Semantic differences
Currently, there are 3 different versions of puissance/3, and I would like to show a significant semantic difference between some of them.
As a test case, I consider the query:
?- puissance(X, Y, Z), false.
What does this query mean? Declaratively, it is clearly equivalent to false. This query is very interesting nevertheless, because it terminates iff puissance/3 terminates universally.
Now, let us try the query on the different variants of the program:
Original definition (from the question):
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Accepted answer:
?- puissance(X, Y, Z), false.
false.
Other answer:
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Obviously, the solution shown in the accepted answer yields a different result, and is worth considering further.
Here is the program again:
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Let us ask something simple first: Which solutions are there at all? This is called the most general query, because its arguments are all fresh variables:
?- puissance(X, Y, Z).
Y = 0,
Z = 1.
The program answers: There is only a single solution: Y=0, Z=1.
That's incorrect (to see this, try the query ?- puissance(0, 1, _) which succeeds, contrary to the same program claiming that Y can only be 0), and a significant difference from the program shown in the question. For comparison, the original program yields:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
ERROR: puissance/3: Arguments are not sufficiently instantiated
That's OK: On backtracking, the program throws an instantiation error to indicate that no further reasoning is possible at this point. Critically though, it does not simply fail!
Improving determinism
So, let us stick to the original program, and consider the query:
?- puissance(1, 1, Z).
Z = 1 ;
false.
We would like to get rid of false, which occurs because the program is not deterministic.
One way to solve this is to use zcompare/3 from library(clpfd). This lets you reify the comparison, and makes the result available for indexing while retaining the predicate's generality.
Here is one possible solution:
puissance(X, N, P) :-
zcompare(C, 0, N),
puissance_(C, X, N, P).
puissance_(=, _, 0, 1).
puissance_(<, X, N, P) :-
A #= N-1,
puissance(X, A, Z),
P #= Z*X.
With this version, we get:
?- puissance(1, 1, Z).
Z = 1.
This is now deterministic, as intended.
Now, let us consider the test case from above with this version:
?- puissance(X, Y, Z), false.
nontermination
Aha! So this query neither throws an instantiation error nor terminates, and is therefore different from all the versions that have hitherto been posted.
Let us consider the most general query with this program:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
X = Z,
Y = 1,
Z in inf..sup ;
Y = 2,
X^2#=Z,
Z in 0..sup ;
Y = 3,
_G3136*X#=Z,
X^2#=_G3136,
_G3136 in 0..sup ;
etc.
Aha! So we get a symbolic representation of all integers that satisfy this relation.
That's pretty cool, and I therefore recommend you use CLP(FD) constraints when reasoning over integers in Prolog. This will make your programs more general and also lets you improve their efficiency more easily.
You can add a cut operator (i.e. !) to your solution, meaning prolog should not attempt to backtrack and find any more solutions after the first successful unification that has reached that point. (i.e. you're pruning the solution tree).
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Layman's Explanation:
The reason prolog attempts to see if there are any more solutions, is this:
At the last call to puissance in your recursion, the first puissance clause succeeds since P=1, and you travel all the way back to the top call to perform unification with P with the eventual value that results from that choice.
However, for that last call to puissance, Prolog didn't have a chance to check whether the second puissance clause would also be satisfiable and potentially lead to a different solution, therefore unless you tell it not to check for further solutions (by using a cut on the first clause after it has been successful), it is obligated to go back to that point, and check the second clause too.
Once it does, it sees that the second clause cannot be satisfied because N = 0, and therefore that particular attempt fails.
So the "false" effectively means that prolog checked for other choice points too and couldn't unify P in any other way that would satisfy them, i.e. there are no more valid unifications for P.
And the fact that you're given the choice to look for other solutions in the first place, exactly means that there are still other routes with potentially satisfiable clauses remaining that have not been explored yet.

Prolog - count occurrence of number

I want to write predicate which can count all encountered number:
count(1, [1,0,0,1,0], X).
X = 2.
I tried to write it like:
count(_, [], 0).
count(Num, [H|T], X) :- count(Num, T, X1), Num = H, X is X1 + 1.
Why doesn't work it?
Why doesn't work it?
Prolog is a programming language that often can answer such question directly. Look how I tried out your definition starting with your failing query:
?- count(1, [1,0,0,1,0], X).
false.
?- count(1, Xs, X).
Xs = [], X = 0
; Xs = [1], X = 1
; Xs = [1,1], X = 2
; Xs = [1,1,1], X = 3
; ... .
?- Xs = [_,_,_], count(1, Xs, X).
Xs = [1,1,1], X = 3.
So first I realized that the query does not work at all, then I generalized the query. I replaced the big list by a variable Xs and said: Prolog, fill in the blanks for me! And Prolog did this and reveals us precisely the cases when it will succeed.
In fact, it only succeeds with lists of 1s only. That is odd. Your definition is too restricted - it correctly counts the 1s in lists where there are only ones, but all other lists are rejected. #coder showed you how to extend your definition.
Here is another one using library(reif) for
SICStus|SWI. Alternatively, see tfilter/3.
count(X, Xs, N) :-
tfilter(=(X), Xs, Ys),
length(Ys, N).
A definition more in the style of the other definitions:
count(_, [], 0).
count(E, [X|Xs], N0) :-
if_(E = X, C = 1, C = 0),
count(E, Xs, N1),
N0 is N1+C.
And now for some more general uses:
How does a four element list look like that has 3 times a 1 in it?
?- length(L, 4), count(1, L, 3).
L = [1,1,1,_A], dif(1,_A)
; L = [1,1,_A,1], dif(1,_A)
; L = [1,_A,1,1], dif(1,_A)
; L = [_A,1,1,1], dif(1,_A)
; false.
So the remaining element must be something different from 1.
That's the fine generality Prolog offers us.
The problem is that as stated by #lurker if condition (or better unification) fails then the predicate will fail. You could make another clause for this purpose, using dif/2 which is pure and defined in the iso:
count(_, [], 0).
count(Num, [H|T], X) :- dif(Num,H), count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
The above is not the most efficient solution since it leaves many choice points but it is a quick and correct solution.
You simply let the predicate fail at the unification Num = X. Basically, it's like you don't accept terms which are different from the only one you are counting.
I propose to you this simple solution which uses tail recursion and scans the list in linear time. Despite the length, it's very efficient and elegant, it exploits declarative programming techniques and the backtracking of the Prolog engine.
count(C, L, R) :-
count(C, L, 0, R).
count(_, [], Acc, Acc).
count(C, [C|Xr], Acc, R) :-
IncAcc is Acc + 1,
count(C, Xr, IncAcc, R).
count(C, [X|Xr], Acc, R) :-
dif(X, C),
count(C, Xr, Acc, R).
count/3 is the launcher predicate. It takes the term to count, the list and gives to you the result value.
The first count/4 is the basic case of the recursion.
The second count/4 is executed when the head of the list is unified with the term you are looking for.
The third count/4 is reached upon backtracking: If the term doesn’t match, the unification fails, you won't need to increment the accumulator.
Acc allows you to scan the entire list propagating the partial result of the recursive processing. At the end you simply have to return it.
I solved it myself:
count(_, [], 0).
count(Num, [H|T], X) :- Num \= H, count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
I have decided to add my solution to the list here.
Other solutions here use either explicit unification/failure to unify, or libraries/other functions, but mine uses cuts and implicit unification instead. Note my solution is similar to Ilario's solution but simplifies this using cuts.
count(_, [], 0) :- !.
count(Value, [Value|Tail],Occurrences) :- !,
count(Value,Tail,TailOcc),
Occurrences is TailOcc+1.
count(Value, [_|Tail], Occurrences) :- count(Value,Tail,Occurrences).
How does this work? And how did you code it?
It is often useful to equate solving a problem like this to solving a proof by induction, with a base case, and then a inductive step which shows how to reduce the problem down.
Line 1 - base case
Line 1 (count(_, [], 0) :- !.) handles the "base case".
As we are working on a list, and have to look at each element, the simplest case is zero elements ([]). Therefore, we want a list with zero elements to have no instances of the Value we are looking for.
Note I have replaced Value in the final code with _ - this is because we do not care what value we are looking for if there are no values in the list anyway! Therefore, to avoid a singleton variable we negate it here.
I also added a ! (a cut) after this - as there is only one correct value for the number of occurrences we do not want Prolog to backtrack and fail - therefore we tell Prolog we found the correct value by adding this cut.
Lines 2/3 - inductive step
Lines 2 and 3 handle the "inductive step". This should handle if we have one or more elements in the list we are given. In Prolog we can only directly look at the head of the list, therefore let us look at one element at a time. Therefore, we have two cases - either the value at the head of the list is the Value we are looking for, or it is not.
Line 2
Line 2 (count(Value, [Value|Tail],Occurrences) :- !, count(Value,Tail,TailOcc), Occurrences is TailOcc+1.) handles if the head of our list and the value we are looking for match. Therefore, we simply use the same variable name so Prolog will unify them.
A cut is used as the first step in our solution (which makes each case mutually exclusive, and makes our solution last-call-optimised, by telling Prolog not to try any other rules).
Then, we find out how many instances of our term there are in the rest of the list (call it TailOcc). We don't know how many terms there are in the list we have at the moment, but we know it is one more than there are in the rest of the list (as we have a match).
Once we know how many instances there are in the rest of the list (call this Tail), we can take this value and add 1 to it, then return this as the last value in our count function (call this Occurences).
Line 3
Line 3 (count(Value, [_|Tail], Occurrences) :- count(Value,Tail,Occurrences).) handles if the head of our list and the value we are looking for do not match.
As we used a cut in line 2, this line will only be tried if line 2 fails (i.e. there is no match).
We simply take the number of instances in the rest of the list (the tail) and return this same value without editing it.

Prolog program returns false

I implemented the following power program in Prolog:
puissance(_,0,1).
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
The code does what is supposed to do, but after the right answer it prints "false.". I don't understand why. I am using swi-prolog.
Can do like this instead:
puissance(X,N,P) :-
( N > 0 ->
A is N-1,
puissance(X,A,Z),
P is Z*X
; P = 1 ).
Then it will just print one answer.
(Your code leaves a `choice point' at every recursive call, because you have two disjuncts and no cut. Using if-then-else or a cut somewhere removes those. Then it depends on the interpreter what happens. Sicstus still asks if you want ((to try to find)) more answers.)
Semantic differences
Currently, there are 3 different versions of puissance/3, and I would like to show a significant semantic difference between some of them.
As a test case, I consider the query:
?- puissance(X, Y, Z), false.
What does this query mean? Declaratively, it is clearly equivalent to false. This query is very interesting nevertheless, because it terminates iff puissance/3 terminates universally.
Now, let us try the query on the different variants of the program:
Original definition (from the question):
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Accepted answer:
?- puissance(X, Y, Z), false.
false.
Other answer:
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Obviously, the solution shown in the accepted answer yields a different result, and is worth considering further.
Here is the program again:
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Let us ask something simple first: Which solutions are there at all? This is called the most general query, because its arguments are all fresh variables:
?- puissance(X, Y, Z).
Y = 0,
Z = 1.
The program answers: There is only a single solution: Y=0, Z=1.
That's incorrect (to see this, try the query ?- puissance(0, 1, _) which succeeds, contrary to the same program claiming that Y can only be 0), and a significant difference from the program shown in the question. For comparison, the original program yields:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
ERROR: puissance/3: Arguments are not sufficiently instantiated
That's OK: On backtracking, the program throws an instantiation error to indicate that no further reasoning is possible at this point. Critically though, it does not simply fail!
Improving determinism
So, let us stick to the original program, and consider the query:
?- puissance(1, 1, Z).
Z = 1 ;
false.
We would like to get rid of false, which occurs because the program is not deterministic.
One way to solve this is to use zcompare/3 from library(clpfd). This lets you reify the comparison, and makes the result available for indexing while retaining the predicate's generality.
Here is one possible solution:
puissance(X, N, P) :-
zcompare(C, 0, N),
puissance_(C, X, N, P).
puissance_(=, _, 0, 1).
puissance_(<, X, N, P) :-
A #= N-1,
puissance(X, A, Z),
P #= Z*X.
With this version, we get:
?- puissance(1, 1, Z).
Z = 1.
This is now deterministic, as intended.
Now, let us consider the test case from above with this version:
?- puissance(X, Y, Z), false.
nontermination
Aha! So this query neither throws an instantiation error nor terminates, and is therefore different from all the versions that have hitherto been posted.
Let us consider the most general query with this program:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
X = Z,
Y = 1,
Z in inf..sup ;
Y = 2,
X^2#=Z,
Z in 0..sup ;
Y = 3,
_G3136*X#=Z,
X^2#=_G3136,
_G3136 in 0..sup ;
etc.
Aha! So we get a symbolic representation of all integers that satisfy this relation.
That's pretty cool, and I therefore recommend you use CLP(FD) constraints when reasoning over integers in Prolog. This will make your programs more general and also lets you improve their efficiency more easily.
You can add a cut operator (i.e. !) to your solution, meaning prolog should not attempt to backtrack and find any more solutions after the first successful unification that has reached that point. (i.e. you're pruning the solution tree).
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Layman's Explanation:
The reason prolog attempts to see if there are any more solutions, is this:
At the last call to puissance in your recursion, the first puissance clause succeeds since P=1, and you travel all the way back to the top call to perform unification with P with the eventual value that results from that choice.
However, for that last call to puissance, Prolog didn't have a chance to check whether the second puissance clause would also be satisfiable and potentially lead to a different solution, therefore unless you tell it not to check for further solutions (by using a cut on the first clause after it has been successful), it is obligated to go back to that point, and check the second clause too.
Once it does, it sees that the second clause cannot be satisfied because N = 0, and therefore that particular attempt fails.
So the "false" effectively means that prolog checked for other choice points too and couldn't unify P in any other way that would satisfy them, i.e. there are no more valid unifications for P.
And the fact that you're given the choice to look for other solutions in the first place, exactly means that there are still other routes with potentially satisfiable clauses remaining that have not been explored yet.

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.

Resources