Prolog, X element before element Y on list [duplicate] - prolog

This question already has answers here:
Prolog, X before Y in a List
(4 answers)
Closed 6 years ago.
I am going to write predicate which is true iff only and only when element X occurs before Y on list L
before(L, X, Y) :-
nth1(PX, L, X),
nth1(PY, L, Y),
PX < PY.
Above, you can see my solution. What do you think about it ?
When it comes to my specific question:
My predicate returns true when there is exists at least one pair that Y followed X. How to define predicate such that it is true for each pair ?

The solution you show works for the "if one exists" case, but is somewhat imperative in nature. That is, it's a little bit like a C program translated to Prolog. Imperative means you are telling the computer, using the programming language, what steps to execute in order to achieve your results.
To be more declarative or relational, your "exists" solution could be expressed nicely as a DCG:
... --> [].
... --> [_], ... .
before(X, Y) --> ... , [X], ... , [Y], ... .
(NOTE: You can in Prolog have a predicate named ..., which is shown here.) This describes the relationship of X and Y in the list. It does not describe steps to execute, but instead describes the relationship of X and Y in a sequence. This solution has been shown before on SO.
Following this approach (where we describe the relationship of X and Y), one way (not necessarily the only way) to express that all the X precede all the Y would be:
before_all(X, Y) -->
{ dif(X,Y) },
any_sequence_but(Y), [X], any_sequence_but(Y), [Y], any_sequence_but(X).
any_sequence_but(_) --> [].
any_sequence_but(Y) --> [X], { dif(X,Y) }, any_sequence_but(Y).
Which yields a solution like this:
?- phrase(before_all(X,Y), [b,a,b,c,a,b,d]).
X = b,
Y = d ;
X = a,
Y = d ;
X = b,
Y = d ;
X = c,
Y = d ;
X = a,
Y = d ;
X = b,
Y = d ;
false.
?-

If the condition should hold for all pairs, the condition should hold for at least one pair, while its converse shouldn't be true for any pair.
I took the liberty of renaming your before/3 to beforeSome/3.
beforeSome(L, X, Y) :-
nth1(PX, L, X),
nth1(PY, L, Y),
PX < PY.
beforeAll(L, X, Y) :-
beforeSome(X,Y),
not(beforeSome(L, Y, X)).
Which yields the desired results:
?- beforeAll([1,2,3,1,4,5], 1, 4).
true.
?- beforeAll([1,2,3,1,4,5], 1, 2).
false.
Please note that your use of nth1/3 precludes it being used with uninstantiated variables. In other words, beforeAll([1,2,3,1,4,5], X, Y). is false.
A better implementation of beforeSome/3 would be something like
beforeSome([X|T], X, Y) :-
member(Y, T).
beforeSome([_|T], X, Y) :-
beforeSome(T, X, Y).
% no change needed, but repeated here for completeness' sake
beforeAll(L, X, Y) :-
beforeSome(X,Y),
not(beforeSome(L, Y, X)).

Related

Can I use integers as parameters?

How can I know if a person X is descendant of a person Y given the descendancy degree?
I've tried this:
descendant(X, Y, 1) :- son(X, Y).
descendant(X, Y, Degree) :- son(X, Z) , descendant(Z, Y, Degree-1).
Where son(X, Y) returns yes if X is son of Y. If Degree == 1 it returns the correct answer but for descendant(X, Y, 2), for instance, should return yes if X is grandson of Y but returns no.
1) Naming: Does son(X,Y) mean "X is the son of Y"—or vice-versa?
son_of(X,Y) is better.
2) Exploit successor-arithmetics: We don't need to do general arithmetics here... we only need to count.
So let's start in the beginning...
child_of(abel, adam). % from source
child_of(abel, eve).
child_of(cain, adam).
child_of(cain, eve).
child_of(enoch, cain).
child_of(irad, enoch).
child_of(mehujael, irad).
child_of(methushael, mehujael).
child_of(lamech, methushael).
child_of(jabal, lamech).
child_of(jabal, adah).
child_of(jubal, lamech).
child_of(jubal, adah).
child_of(tubal_cain, lamech).
child_of(tubal_cain, zillah).
child_of(naamah, lamech).
child_of(naamah, zillah).
child_of(seth, adam).
child_of(seth, eve).
child_of(enos, seth).
child_of(kenan, enos).
child_of(mahalalel, kenan).
child_of(jared, mahalalel).
child_of(enoch, jared).
child_of(methuselah, enoch).
child_of(lamech, methuselah).
child_of(noah, lamech).
child_of(shem, noah).
child_of(ham, noah).
child_of(japheth, noah).
Based on child_of/2 we first define ancestor_of/2—this should be nothing new to you!
ancestor_of(Y, Z) :-
child_of(Z, Y). % If Z is a child of Y ...
% then Y is an ancestor of Z.
ancestor_of(X, Z) :-
child_of(Z, Y), % If Z is a child of Y ...
ancestor_of(X, Y). % and X is an ancestor of Y ...
% then X is an ancestor of Z.
Next, we add an additional parameter indicating the distance.
We use s/1 terms to represent natural numbers and add a new argument to ancestor_of/2:
ancestor_of_dist(Y, Z, s(0)) :-
child_of(Z, Y). % If Z is a child of Y ...
% then Y is an ancestor of Z with distance = 1."
ancestor_of_dist(X, Z, s(N)) :-
child_of(Z, Y), % If Z is a child of Y ...
ancestor_of_dist(X, Y, N). % and X is an ancestor of Y with distance N ...
% then X is an ancestor of Z with distance N+1.
So ... who is grandparent of whom?
?- ancestor_of_dist(X, Z, s(s(0))).
X = adam, Z = enoch
; X = eve, Z = enoch
; X = cain, Z = irad
; X = jared, Z = irad
; X = enoch, Z = mehujael
; ...
; X = lamech, Z = japheth
; false.
Prolog is not a functional language. Thus, the Degree-1 term is not interpreted and evaluated as an expression. For Prolog, Degree-1 is just a compound term with two arguments. That can be made clear using the standard write_canonical/1 predicate, which writes a term without using operator notation:
?- write_canonical(Degree-1).
-(_,1)
true.
Write instead:
descendant(X, Y, 1) :-
son(X, Y).
descendant(X, Y, Degree) :-
son(X, Z) ,
descendant(Z, Y, Degree0),
Degree is Degree0 + 1.
The is/2 standard built-in predicate unifies the left argument with the value of the arithmetic expression in the right argument.
P.S. Note that the alternative descendant/3 predicate definition I suggest will solve the problem you described but it is not an efficient definition as it is not a tail-recursive definition. I.e. the recursive call in the second clause is not the last call in the clause body. This issue can be easily solved, however, by using an accumulator.

Rule to test whether two lists contain same two elements fails due to uniqueness constraint

I'm trying to create a rule called redundancy that examines lists to see if two elements appear together in more than one list.
Here is my code:
columns([a,b,c]).
columns([b,c,d]).
in(X, [H|_]) :-
X = H.
in(X, [_|T]) :-
in(X, T).
redundancy(X, Y) :-
columns(A),
columns(B),
A \= B,
X \= Y,
in(X, A),
in(X, B),
in(Y, A),
in(Y, B).
The problem is the constraint X \= Y. I want it in there to exclude instances where X and Y are identical elements, which would be true for all single elements that appear in more than one list. But it only returns false for the given columns even though it should return permutations of b and c.
?- redundancy(U, T).
false.
If I comment out the constraint I get the expected elements along with the unwanted ones mentioned above.
?- redundancy(X, Y).
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = b ;
X = Y, Y = c ;
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = b ;
X = Y, Y = c ;
false.
Is there a way to enforce this constraint? I'm also interested in ideas to restrict results to a given combination of elements rather than permutations.
Simply move X \= Y to the last line of your predicate. also, see prolog-dif and instantiation-error.
The thing to avoid is using non-pure predicates with not-yet-instantiated logical variables (unless this is exactly what you intended, and you know what you're doing).
Another thing to notice is that X \= Y is not a constraint (that's dif), but a check.

How to print all the facts in prolog

I am a beginner and I am using SWI Prolog to write a rule to print all the facts about addition of two numbers.The following is the code:
addition(X,Y,Z) :- Z is X+Y.
add(X,Y):-
between(X,Y,A),
addition(X,A,Z),
writeln(addition(X,A,Z)),
X1 is X+1,
add(X1,Y).
And the following is the output:
1 ?- add(1,2).
addition(1,1,2)
addition(2,2,4)
addition(1,2,3)
addition(2,2,4)
false.
As you can see the output addition(2,2,4) is repeating and addition(2,1,3) is missing. What am I doing wrong here??
addition/3 is a "rule", or a "predicate", not a fact. Anyway, you have defined it as:
% addition(X, Y, Z)
% Z is the sum of the integers X and Y
Now you want to apply this predicate to (and I am guessing here) each pair X and Y such that X is between A and B and Y is between A and B:
% add(A, B, Addition)
% Add all numbers X and Y that are between A and B
add(A, B, addition(X, Y, Z)) :-
between(A, B, X),
between(A, B, Y),
addition(X, Y, Z).
You will notice that you don't need recursion (or iteration): you can use the fact that between/3 is non-deterministic and will create choice points that will be evaluated on backtracking.
You can now call it like this:
?- add(1, 2, A).
A = addition(1, 1, 2) ;
A = addition(1, 2, 3) ;
A = addition(2, 1, 3) ;
A = addition(2, 2, 4).
You can press the ; or space to backtrack and evaluate the next solution.
The third argument to add/3 is unified with the term addition/3 in the head of add/3. It happens to have the same name as the predicate addition/3, but it could have been called anything.
If you insist on printing it out from a single call, you could use forall/2:
?- forall(add(1, 2, A), format('~q', [A])).

Difference between X\=Y and dif(X,Y)

What is the difference between this:
X \= Y
and this piece of code:
dif(X, Y)
I thought that they should behave the same, but they do not. Here's the example:
n_puta(L, N, X) :- nputa(L, N, 0, X).
nputa([], N, C, _) :- N = C.
nputa([G|R], N, C, X) :- G = X, nputa(R, N, Y, X), C is Y - 1.
nputa([G|R], N, C, X) :- dif(G,X), nputa(R, N, C, X).
And here are some calls:
?- n_puta([a,a,b,b,b], 2, X).
X = a ;
false.
?- n_puta([a,a,b,a,b,b], 3, X).
X = a ;
X = b ;
false.
X should be the atom that occurs exactly N times in the list L. If I replace dif(G, X) with G \= X, I don't get the expected result. Can someone tell me what is the difference between these two operators? Can I use anything else except dif(G, X)?
This example works prefectly in SWI-Prolog, but doesn't work in Amzi! Prolog.
dif/2 and (\=)/2 are the same as long as their arguments are ground. But only dif/2 is a pure relation that works correctly also with variables and can be used in all directions. Your example clearly shows that you should use dif/2 in this case, because you use your predicate not only to test, but also to generate solutions. The most widely used Prolog systems all provide dif/2.

Don't repeat solutions in Prolog

Suppose you have a database with the following content:
son(a, d).
son(b, d).
son(a, c).
son(b, c).
So a and b are sons of d and c. Now you want to know, given a bigger database, who is brother to who. A solution would be:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y.
The problem with this is that if you ask "brother(X, Y)." and start pressing ";" you'll get redundant results like:
X = a, Y = b;
X = b, Y = a;
X = a, Y = b;
X = b, Y = a;
I can understand why I get these results but I am looking for a way to fix this. What can I do?
Prolog will always try to find every possible solution available for your statements considering your set of truths. The expansion works as depth-first search:
son(a, d).
son(b, d).
son(a, c).
son(b, c).
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y.
brother(X, Y)
_______________________|____________________________ [son(X, P)]
| | | |
X = a, P = d X = b, P = d X = a, P = c X = a, P = b
| | | |
| ... ... ...
|
| (X and P are already defined for this branch;
| the algorithm now looks for Y's)
|__________________________________________ [son(Y, d)]
| |
son(a, d) -> Y = a son(b, d) -> Y = b
| |
| | [X \= Y]
X = a, Y = a -> false X = a, Y = b -> true
|
|
solution(X = a, Y = b, P = d)
But, as you can see, the expansion will be performed in all the branches, so you'll end up with more of the same solution as the final answer. As pointed by #Daniel Lyons, you may use the setof built-in.
You may also use the ! -- cut operator -- that stops the "horizontal" expansion, once a branch has been found to be valid, or add some statement that avoids the multiple solutions.
For further information, take a look at the Unification algorithm.
First, I would advise against updating the Prolog database dynamically. For some reasons, consider the article
"How to deal with the Prolog dynamic database?".
You could use a combination of the builtin setof/3 and member/2, as #DanielLyons has suggested in his answer.
As yet another alternative, consider the following query which uses setof/3 in a rather unusual way, like this:
?- setof(t,brother(X,Y),_).
X = a, Y = b ;
X = b, Y = a.
You can eliminate one set with a comparison:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y, X #< Y.
?- brother(X, Y).
X = a,
Y = b ;
X = a,
Y = b ;
false.
Since X and Y will be instantiated both ways, requiring X be less than Y is a good way to cut the solutions in half.
Your second problem is that X and Y are brothers by more than one parent. The easiest solution here would be to make your rules more explicit:
mother(a, d).
mother(b, d).
father(a, c).
father(b, c).
brother(X, Y) :-
mother(X, M), mother(Y, M),
father(X, F), father(Y, F),
X \= Y, X #< Y.
?- brother(X, Y).
X = a,
Y = b ;
false.
This method is very specific to this particular problem, but the underlying reasoning is not: you had two copies because a and b are "brothers" by c and also by d—Prolog was right to produce that solution twice because there was a hidden variable being instantiated to two different values.
A more elegant solution would probably be to use setof/3 to get the solutions. This can work even with your original code:
?- setof(X-Y, (brother(X, Y), X #< Y), Brothers).
Brothers = [a-b].
The downside to this approach is that you wind up with a list rather than Prolog generating different solutions, though you can recover that behavior with member/2.
This should work. But I think it can be improved (I am not a Prolog specialist):
brother(X, Y) :-
son(X, P1),
son(Y, P1),
X #< Y,
(son(X, P2), son(Y, P2), P1 #< P2 -> false; true).
If you're using Strawberry Prolog compiler,you won't get all the answers by typing this:
?- brother(X, Y),
write(X), nl,
write(Y), nl.
In order to get all the answers write this:
?- brother(X, Y),
write(X), nl,
write(Y), nl,
fail.
I hope it helps you.:)
I got to an answer.
% Include the dictionary
:- [p1]. % The dictionary with sons
:- dynamic(found/2).
brother(X, Y) :-
% Get two persons from the database to test
son(X, P),
son(Y, P),
% Test if the two persons are different and were not already used
testBrother(X, Y).
% If it got here it's because there is no one else to test above, so just fail and retract all
brother(_, _) :-
retract(found(_, _)),
fail.
testBrother(X, Y) :-
X \= Y,
\+found(X, Y),
\+found(Y, X),
% If they were not used succed and assert what was found
assert(found(X, Y)).
It always returns fails in the end but it succeeds with the following.
brother(X, Y). % Every brother without repetition
brother('Urraca', X). % Every brother of Urraca without repetition
brother('Urraca', 'Sancho I'). % True, because Urraca and Sancho I have the same father and mother. In fact, even if they only had the same mother or the same father it would return true. A little off context but still valid, if they have three or more common parents it would still work
It fails with the following:
brother(X, X). % False because it's the same person
brother('Nope', X). % False because not is not even in the database
brother('Nope', 'Sancho I'). % False, same reason
So like this I can, for example, ask: brother(X, Y), and start pressing ";" to see every brother and sister without any repetition.
I can also do brother(a, b) and brother(b, a), assuming a and b are persons in the database. This is important because some solutions would use #< to test things and like so brother(b, a) would fail.
So there it is.

Resources