How to write earlier statement in prolog? - prolog

I was looking at prolog progrm and was unable to understand the following
earlier(X, _, [X|_]).
earlier(_, Y, [Y|_]) :- !, fail.
earlier(X, Y, [_|T]) :- earlier(X, Y, T).
Can anyone explain what does it mean??

As the name suggests, earlier(X, Y, Zs) is apparently supposed to check whether the element X appears earlier than the first occurrence of Y in the list Zs. It kind of does this:
?- earlier(a, b, [a, b, c, d]).
true ;
false.
?- earlier(b, d, [a, b, c, d]).
true ;
false.
With peculiar handling if the second argument is not in the given list:
?- earlier(a, not_in_list, [a, b, c, d]).
true ;
false.
How does this work? The first clause says that if X is the head of the list, then X appears earlier in the list than anything, represented by the anonymous variable _. The second clause says that if Y is the head of the list, then nothing (_ in first argument position) is before Y. In this case, the predicate fails and uses a cut to avoid finding spurious solutions. The third clause just recurses on the list of neither the first nor second clauses applied.
Due to the cut, this definition is not very declarative, and some interesting uses don't work as one might expect:
?- earlier(X, Y, Zs).
Zs = [X|_G947] ;
false.
?- earlier(a, b, Zs).
Zs = [a|_G923] ;
false.
?- earlier(X, Y, [a, b, c, d]).
X = a ;
false.
The last case, in particular, might be interesting for some use cases. Here is a more declarative version:
earlier_than(X, Y, Zs) :-
append(InitialPart, [X | _Rest], Zs),
notmember_of(Y, InitialPart).
notmember_of(_X, []).
notmember_of(X, [Y|Xs]) :-
dif(X, Y),
notmember_of(X, Xs).
You can use this to enumerate solutions more nicely:
?- earlier_than(X, Y, Zs).
Zs = [X|_G947] ;
Zs = [_G1162, X|_G1166],
dif(Y, _G1162) ;
Zs = [_G1254, _G1257, X|_G1261],
dif(Y, _G1257),
dif(Y, _G1254) ;
Zs = [_G1346, _G1349, _G1352, X|_G1356],
dif(Y, _G1352),
dif(Y, _G1349),
dif(Y, _G1346) .
?- earlier_than(a, b, Zs).
Zs = [a|_G923] ;
Zs = [_G1086, a|_G1090],
dif(_G1086, b) ;
Zs = [_G1169, _G1172, a|_G1176],
dif(_G1169, b),
dif(_G1172, b) ;
Zs = [_G1252, _G1255, _G1258, a|_G1262],
dif(_G1252, b),
dif(_G1255, b),
dif(_G1258, b) .
?- earlier_than(X, Y, [a, b, c, d]).
X = a ;
X = b,
dif(Y, a) ;
X = c,
dif(Y, b),
dif(Y, a) ;
X = d,
dif(Y, c),
dif(Y, b),
dif(Y, a) ;
false.
Personally, if the specification permits, I would also add a member(Y, Rest) to the definition of earlier_than/3. This makes things even nicer:
?- earlier_than(X, Y, Zs).
Zs = [X, Y|_G950] ;
Zs = [X, _G949, Y|_G953] ;
Zs = [X, _G949, _G952, Y|_G956] .
?- earlier_than(a, b, Zs).
Zs = [a, b|_G926] ;
Zs = [a, _G925, b|_G929] ;
Zs = [a, _G925, _G928, b|_G932] .
?- earlier_than(X, Y, [a, b, c, d]).
X = a,
Y = b ;
X = a,
Y = c ;
X = a,
Y = d ;
X = b,
Y = c ;
X = b,
Y = d ;
X = c,
Y = d ;
false.

Related

How to code a program in prolog, that does comparison on graphs

I'm trying to code a program in prolog that says true if all the paths from a to b are the same size. Example : we have a path from a to b and another from a to c to b, here it's false because there are two paths from a to b with different sizes, the first is 1 and the other is 2. They all must be the same size otherwise it's false.
I started doing this to get the length of each path, but I'm stuck here, I just need to compare if there are two same paths or not, if yes then we compare the two results if they are the same length then true otherwise false, but I don't know how to do it in Prolog :
chemin1(X, Y):-
arete(X,Y).
chemin1(X, Y):-
arete(X,Z),
chemin1(Z,Y).
chemin2(X, Y, N):-
arete(X, Y),
N is 1.
chemin2(X, Y, N):-
arete(X, Z),
N1 is 1,
chemin2(Z, Y, N2),
N is N1+N2.
I'm assuming you have an acyclic directed graph and that a path is represented by a vertex list.
% b
% / \
% a d
% \ / \
% c---e
arete(a, b).
arete(a, c).
arete(b, d).
arete(c, d).
arete(c, e).
arete(d, e).
chemin(X, X, [X]).
chemin(X, Z, [X|Xs]):- arete(X, Y), chemin(Y, Z, Xs).
Examples:
?- chemin(a, d, C).
C = [a, b, d] ;
C = [a, c, d] ;
false.
?- chemin(a, e, C).
C = [a, b, d, e] ;
C = [a, c, d, e] ;
C = [a, c, e] ;
false.
Then, all paths between two vertices X and Y are of the same size, if there are no two paths between vertices X and Y that are of different sizes.
% all_same_size(+X, +Y)
all_same_size(X, Y) :-
not( ( chemin(X, Y, Xs),
chemin(X, Y, Ys),
not( same_size(Xs, Ys) ) ) ).
same_size([], []).
same_size([_|Xs], [_|Ys]) :- same_size(Xs, Ys).
Examples:
?- all_same_size(a, d).
true.
?- all_same_size(a, e).
false.
chemin2(X0,X, N) :-
path(arete, Path, X0,X),
length(Path, N).
allequallength(X0, X) :-
setof(N, chemin2(X0,X, N), [_]).
Using path/4.
With this definition you can also ask a more general question using the facts you indicated:
arete(a, b).
arete(b, d).
arete(b, c).
arete(a, c).
?- allequallength(X0,X).
X0 = X
; X0 = a, X = b
; X0 = a, X = d
; X0 = b, X = c
; X0 = b, X = d.

Prolog membership predicate without dif or when

The following prolog logic
memberd(X, [X|_T]).
memberd(X, [Y| T]) :- dif(X,Y), memberd(X, T).
will produce
?- memberd(a, [a, b, a]).
true
?- memberd(X, [a, b, a]).
X = a ;
X = b ;
false.
?- memberd(X, [a, b, a, c, a, d, b]).
X = a ;
X = b ;
X = c ;
X = d ;
false.
is there prolog logic that can be used to produce the same result without using when() or dif() function or anything from a loaded prolog library. Just using pure logic?
To answer your question literally, just use:
?- setof(t, member(X, [a,b,a]), _).
X = a
; X = b.
However, some answers will be suboptimal:
?- setof(t,member(a,[a,X]),_).
true
; X = a. % redundant
... whereas memberd/2 answers in perfection:
?- memberd(a,[a,X]).
true
; false.
In fact, if you use library(reif) with
memberd(E, [X|Xs]) :-
if_(E = X, true, memberd(E, Xs) ).
you get the best answer possible:
?- memberd(a,[a,X]).
true.

Prolog: eliminate repetitions in query

I've been trying to write a simple code, that would behave in this manner:
| ?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? ;
X = [a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
And
| ?- hasCoppiesOf([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = ...
This desire resulted in next piece of code:
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B).
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
And it gives me what I want on the second query, however, the first results in:
?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
It seems to be working fine, but that repetition of the same answers bothers me. It's, probably, a simple mistake, but is there a way to make the output prettier?
And honestly, that a mystery, why Prolog treats two identical arrays as different answers.
Or maybe it's just something wrong with my system?
Edit:
The gentle guidance of the person in the comments helped me to solve this issue. However, if this question will be reading the person who wants to solve exactly the same problem - code not really working well, my apologies.
I think you just made your predicate more complex than it needs to be, probably just overthinking it. A given solution may succeed in multiple paths through the logic.
You can do this without append/3 by aligning the front end of the lists and keep the original list to "reset" on repeats:
% Empty list base cases
dups_list([], []).
dups_list([_|_], []).
% Main predicate, calling aux predicate
dups_list(L, Ls) :-
dups_list(L, L, Ls).
% Recursive auxiliary predicate
dups_list([], [_|_], []).
dups_list([], [X|Xs], [X|Ls]) :-
dups_list(Xs, [X|Xs], Ls).
dups_list([X|Xs], L, [X|Ls]) :-
dups_list(Xs, L, Ls).
Here are some results:
| ?- dups_list(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? a
X = [a,b,a,b]
X = [a,b,a,b,a,b,a,b]
no
| ?- dups_list([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ?
...
| ?- dups_list(A, B).
A = []
B = [] ? ;
A = [_|_]
B = [] ? ;
A = [C]
B = [C] ? ;
A = [C]
B = [C,C] ? ;
A = [C,D]
B = [C,D] ? ;
A = [C]
B = [C,C,C] ? ;
A = [C,D,E]
B = [C,D,E] ? ;
...
There may be a way to simplify the solution just a bit more, but I haven't played with it enough to determine if that's the case.
I think this is what you're trying for...
coppies(Z,Z,[]).
coppies(X,Z,[Y|Ys]):- \+member(Y,Z),coppies(X,[Y|Z],Ys).
coppies(X,Z,[Y|Ys]):- member(Y,Z),coppies(X,Z,Ys).
copies(M,[Y|Ys]):-coppies(M,[],[Y|Ys]).
Input:
copies(X,[1,2,1,2,1,2]).
Output:
X = [2, 1].
BTW I've used some different names instead..
Okay, I got your problem, you want to eliminate the repetitions.
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!. %Change here, place a cut after the termination.
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
This is the change that you need to make.
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!.
A Cut '!' terminates the unwanted backtracking and thereby repetitions.

Prolog append/3 realization with more determinism?

It is folk knowledge that append(X,[Y],Z) finds the last element
Y of the list Z and the remaining list X.
But there is some advantage of having a customized predicate last/3,
namely it can react without leaving a choice point:
?- last([1,2,3],X,Y).
X = 3,
Y = [1,2]
?- append(Y,[X],[1,2,3]).
Y = [1,2],
X = 3 ;
No
Is there a way to realize a different implementation of
append/3 which would also not leave a choice point in the
above example?
P.S.: I am comparing:
/**
* append(L1, L2, L3):
* The predicate succeeds whenever L3 unifies with the concatenation of L1 and L2.
*/
% append(+List, +List, -List)
:- public append/3.
append([], X, X).
append([X|Y], Z, [X|T]) :- append(Y, Z, T).
And (à la Gertjan van Noord):
/**
* last(L, E, R):
* The predicate succeeds with E being the last element of the list L
* and R being the remainder of the list.
*/
% last(+List, -Elem, -List)
:- public last/3.
last([X|Y], Z, T) :- last2(Y, X, Z, T).
% last2(+List, +Elem, -Elem, -List)
:- private last2/4.
last2([], X, X, []).
last2([X|Y], U, Z, [U|T]) :- last2(Y, X, Z, T).
One way to do it is to use foldl/4 with the appropriate help predicate:
swap(A, B, B, A).
list_front_last([X|Xs], F, L) :-
is_list(Xs),
foldl(swap, Xs, F, X, L).
This should be it:
?- list_front_last([a,b,c,d], F, L).
F = [a, b, c],
L = d.
?- list_front_last([], F, L).
false.
?- list_front_last([c], F, L).
F = [],
L = c.
?- Ys = [y|Ys], list_front_last(Ys, F, L).
false.
Try to see if you can leave out the is_list/1 from the definition.
As I posted:
append2(Start, End, Both) :-
% Preventing unwanted choicepoint with append(X, [1], [1]).
is_list(Both),
is_list(End),
!,
append(Start, End, Both),
!.
append2(Start, End, Both) :-
append(Start, End, Both),
% Preventing unwanted choicepoint with append(X, Y, [1]).
(End == [] -> ! ; true).
Result in swi-prolog:
?- append2(Y, [X], [1,2,3]).
Y = [1, 2],
X = 3.

Prolog compute the permutation

I'm writing a permutation function [a,b]-->[[[a], [b]], [[a, b]]
I have this so far, but it doesn't work.
perm([],[]).
perm(L,[H|T]) :- append(V,[H|U],L), append(V,U,W), perm(W,T).
Given your example, it looks like you might actually be wanting the powerset, not the permutation, of the given list.
For instance, the powerset of [a,b] is the set {[a,b], [a], [b], []}.
To compute the powerset of a list of items in Prolog, look at this answer by #gusbro. If this helps you, also please upvote that answer.
If you want all solutions of the powerset of a list L at once, you can wrap the call to powerset/2 in a findall/3 call like this:
?- findall(S, powerset(L, S), Ss).
If, on the other hand, you're after the partitions (as you've mentioned in one of your earlier edits), consider the following:
partition(L, PL) :-
partition(L, [], PL).
partition([], [], []).
partition([X|Xs], As, R) :-
% add X into the new partition...
append(As, [X], NewAs),
partition(Xs, NewAs, R).
partition(L, [A|As], [[A|As]|R]) :-
% ...or, collect the current non-empty partition
partition(L, [], R).
The predicate partition/2 takes a list and returns all partitions, as you've described. For example:
?- partition([a,b,c],L).
L = [[a, b, c]] ;
L = [[a, b], [c]] ;
L = [[a], [b, c]] ;
L = [[a], [b], [c]] ;
false.
Really? It seems to work in SWI-Prolog:
?- [user].
|: perm([],[]).
|: perm(L,[H|T]) :- append(V,[H|U],L), append(V,U,W), perm(W,T).
|: % user://1 compiled 0.00 sec, 3 clauses
true.
?- perm([a,b,c], X).
X = [a, b, c] ;
X = [a, c, b] ;
X = [b, a, c] ;
X = [b, c, a] ;
X = [c, a, b] ;
X = [c, b, a] ;
false.
?- perm([a,b,c,d], X).
X = [a, b, c, d] ;
/* trimming 22 solutions */
X = [d, c, b, a] ;
false.
This also yields the number of answers you'd expect: 3! = 6, 4! = 24. What's not working for you?
Quick note: Prolog doesn't offer functions, but relations.
In this case, perm/2 will hold true when the arguments are one the permutation of the other.
I find this definition more readable than your.
perm([], []).
perm([E|Es], P) :-
perm(Es, Q),
select(E, P, Q).
It's almost the same as that of permutation/2 SWI-Prolog, but hides a bug...

Resources