I'm trying to count the numer of inversions in a list. A predicate inversion(+L,-N) unifies N to the number of inversions in that list. A inversion is defined as X > Y and X appears before Y in the list (unless X or Y is 0). For example:
?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.
For what I'm using this for, the list will always have exacly 9 elements, and always containing the numbers 0-8 uniquely.
I'm quite new to Prolog and I'm trying to do this as concise and as elegant as possible; It seems like DCG will probably help a lot. I read into the official definition and some tutorial sites, but still don't quit understand what it is. Any help would be greatly appreciated.
Here is another solution that doesn't leave choice points using if_/3:
inversions([],0).
inversions([H|T], N):-
if_( H = 0,
inversions(T,N),
( find_inv(T,H,N1),inversions(T, N2), N #= N1+N2 )
).
find_inv([],_,0).
find_inv([H1|T],H,N1):-
if_( H1=0,
find_inv(T,H,N1),
if_( H#>H1,
(find_inv(T,H,N2),N1 #= N2+1),
find_inv(T,H,N1)
)
).
#>(X, Y, T) :-
( integer(X),
integer(Y)
-> ( X > Y
-> T = true
; T = false
)
; X #> Y,
T = true
; X #=< Y,
T = false
).
I'm not so sure a DCG would be helpful here. Although we're processing a sequence, there's a lot of examination of the entire list at each point when looking at each element.
Here's a CLPFD approach which implements the "naive" algorithm for inversions, so it's transparent and simple, but not as efficient as it could be (it's O(n^2)). There's a more efficient algorithm (O(n log n)) involving a divide and conquer approach, which I show further below.
:- use_module(library(clpfd)).
inversions(L, C) :-
L ins 0..9,
all_distinct(L),
count_inv(L, C).
% Count inversions
count_inv([], 0).
count_inv([X|T], C) :-
count_inv(X, T, C1), % Count inversions for current element
C #= C1 + C2, % Add inversion count for the rest of the list
count_inv(T, C2). % Count inversions for the rest of the list
count_inv(_, [], 0).
count_inv(X, [Y|T], C) :-
( X #> Y, X #> 0, Y #> 0
-> C #= C1 + 1, % Valid inversion, count it
count_inv(X, T, C1)
; count_inv(X, T, C)
).
?- inversions([1,2,3,4,0,5,6,7,8],N).
N = 0 ;
false.
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3 ;
false.
?- inversions([0,2,X],1).
X = 1 ;
false.
It does leave a choice point, as you can see, which I haven't sorted out yet.
Here's the O(n log n) solution, which is using the sort/merge algorithm.
inversion([], [], 0).
inversion([X], [X], 0).
inversion([HU1, HU2|U], [HS1, HS2|S], C) :- % Ensure list args have at least 2 elements
split([HU1, HU2|U], L, R),
inversion(L, SL, C1),
inversion(R, SR, C2),
merge(SL, SR, [HS1, HS2|S], C3),
C #= C1 + C2 + C3.
% Split list into left and right halves
split(List, Left, Right) :-
split(List, List, Left, Right).
split(Es, [], [], Es).
split(Es, [_], [], Es).
split([E|Es], [_,_|T], [E|Ls], Right) :-
split(Es, T, Ls, Right).
% merge( LS, RS, M )
merge([], RS, RS, 0).
merge(LS, [], LS, 0).
merge([L|LS], [R|RS], [L|T], C) :-
L #=< R,
merge(LS, [R|RS], T, C).
merge([L|LS], [R|RS], [R|T], C) :-
L #> R, R #> 0 #<==> D, C #= C1+D,
merge([L|LS], RS, T, C1).
You can ignore the second argument, which is the sorted list (just a side effect if all you want is the count of inversions).
Here is another possibility to define the relation. First, #</3 and #\=/3 can be defined like so:
:- use_module(library(clpfd)).
bool_t(1,true).
bool_t(0,false).
#<(X,Y,Truth) :- X #< Y #<==> B, bool_t(B,Truth).
#\=(X,Y,Truth) :- X #\= Y #<==> B, bool_t(B,Truth).
Based on that, if_/3 and (',')/3 a predicate inv_t/3 can be defined, that yields true in the case of an inversion and false otherwise, according to the definition given by the OP:
inv_t(X,Y,T) :-
if_(((Y#<X,Y#\=0),X#\=0),T=true,T=false).
And subsequently the actual relation can be described like so:
list_inversions(L,I) :-
list_inversions_(L,I,0).
list_inversions_([],I,I).
list_inversions_([X|Xs],I,Acc0) :-
list_x_invs_(Xs,X,I0,0),
Acc1 #= Acc0+I0,
list_inversions_(Xs,I,Acc1).
list_x_invs_([],_X,I,I).
list_x_invs_([Y|Ys],X,I,Acc0) :-
if_(inv_t(X,Y),Acc1#=Acc0+1,Acc1#=Acc0),
list_x_invs_(Ys,X,I,Acc1).
Thus the example queries given by the OP succeed deterministically:
?- list_inversions([1,2,3,4,0,5,6,7,8],N).
N = 0.
?- list_inversions([1,2,3,0,4,6,8,5,7],N).
N = 3.
Such application-specific constraints can often be built using reified constraints (constraints whose truth value is reflected into a 0/1 variable). This leads to a relatively natural formulation, where B is 1 iff the condition you want to count is satisfied:
:- lib(ic).
inversions(Xs, N) :-
( fromto(Xs, [X|Ys], Ys, [_]), foreach(NX,NXs) do
( foreach(Y,Ys), param(X), foreach(B,Bs) do
B #= (X#\=0 and Y#\=0 and X#>Y)
),
NX #= sum(Bs) % number of Ys that are smaller than X
),
N #= sum(NXs).
This code is for ECLiPSe.
Using clpfd et automaton/8 we can write
:- use_module(library(clpfd)).
inversions(Vs, N) :-
Vs ins 0..sup,
variables_signature(Vs, Sigs),
automaton(Sigs, _, Sigs,
[source(s),sink(i),sink(s)],
[arc(s,0,s), arc(s,1,s,[C+1]), arc(s,1,i,[C+1]),
arc(i,0,i)],
[C], [0], [N]),
labeling([ff],Vs).
variables_signature([], []).
variables_signature([V|Vs], Sigs) :-
variables_signature_(Vs, V, Sigs1),
variables_signature(Vs, Sigs2),
append(Sigs1, Sigs2, Sigs).
variables_signature_([], _, []).
variables_signature_([0|Vs], Prev, Sigs) :-
variables_signature_(Vs,Prev,Sigs).
variables_signature_([V|Vs], Prev, [S|Sigs]) :-
V #\= 0,
% Prev #=< V #<==> S #= 0,
% modified after **false** remark
Prev #> V #<==> S,
variables_signature_(Vs,Prev,Sigs).
examples :
?- inversions([1,2,3,0,4,6,8,5,7],N).
N = 3 ;
false.
?- inversions([1,2,3,0,4,5,6,7,8],N).
N = 0 ;
false.
?- inversions([0,2,X],1).
X = 1.
in SWI-Prolog, with libraries aggregate and lists:
inversions(L,N) :-
aggregate_all(count, (nth1(P,L,X),nth1(Q,L,Y),X\=0,Y\=0,X>Y,P<Q), N).
both libraries are autoloaded, no need to explicitly include them.
If you want something more general, you can see the example in library(clpfd), under the automaton section, for some useful ideas. But I would try to rewrite your specification in simpler terms, using element/3 instead of nth1/3.
edit
after #false comment, I tried some variation on disequality operators, but none I've tried have been able to solve the problematic query. Then I tried again with the original idea, to put to good use element/3. Here is the result:
:- use_module(library(clpfd)).
inversions(L) :-
L ins 0..8,
element(P,L,X),
element(Q,L,Y),
X #\= 0, Y #\= 0, X #> Y, P #< Q,
label([P,Q]).
inversions(L,N) :-
aggregate(count, inversions(L), N) ; N = 0.
The last line label([P,Q]) it's key to proper reification: now we can determine the X value.
?- inversions([0,2,X],1).
X = 1.
Related
I would like to get the middle element of a list in Prolog.
The predicates middle([1,2,3],M) and middle([1,2,3,4],M) should both return 2 as a result.
And I am allowed to use the predicate deleteLast.
I know that there are similar posts that solve that question but I have not found one that just uses deleteLast.
Even the syntax is not correct - however this is my solution so far:
middle([], _).
middle([X|XTail|Y], E) :-
1 is mod(list_length([X|XTail|Y], 2)),
middle([XTail], E).
middle([X|XTail|Y], E) :-
0 is mod(list_length([X|XTail|Y], 2)),
middle([X|XTail], E).
middle([X], X).
Question: Is that partly correct or am I completely on the wrong path ?
Sorry, the attempted solution you have is completely on the wrong path.
It doesn't use deleteLast/2 as you stated you require
You are using list_length/2 as if it were an arithmetic function, which it is not. It's a predicate.
You have a term with invalid syntax and unknown semantics, [X|XTail|Y]
In Prolog, you just need to think about it in terms of the rules. Here's an approach using deleteLast/2:
middle([X], X). % `X` is the middle of the single element list `[X]`
middle([X,_], X). % `X` is the middle of the two-element list `[X,_]`
% X is the middle of the list `[H|T]` if X is the middle of the list TWithoutLast
% where TWithoutLast is T with its last element removed
%
middle([H|T], X) :-
deleteLast(T, TWithoutLast),
middle(TWithoutLast, X).
I assume deleteLast/2 is well-behaved and just fails if T is empty.
You can also do this with same_length/2 and append/3, but, alas, doesn't use deleteLast/2:
middle(L, M) :-
same_length(L1, L2),
append(L1, [M|L2], L).
middle(L, M) :-
same_length(L1, L2),
append(L1, [M,_|L2], L).
So much unnecessary work, and unnecessary code. length/2 is very efficient, and a true relation. Its second argument is guaranteed to be a non-negative integer. So:
middle(List, Middle) :-
List = [_|_], % at least one element
length(List, Len),
divmod(Len, 2, Q, R), % if not available do in two separate steps
N is Q + R,
nth1(N, List, Middle).
And you are about ready:
?- middle(L, M), numbervars(L).
L = [A],
M = A ;
L = [A, B],
M = A ;
L = [A, B, C],
M = B ;
L = [A, B, C, D],
M = B ;
L = [A, B, C, D, E],
M = C ;
L = [A, B, C, D, E, F],
M = C .
I understand that this doesn't solve your problem (the answer by #lurker does) but it answers your question. :-(
Here is my attempt:
middle(L,M):- append(L1,L2,L),length(L1,N),length(L2,N), reverse(L1,[M|_]).
middle(L,M):- append(L1,L2,L),length(L1,N),length(L2,N1), N is N1+1 ,
reverse(L1,[M|_]).
Example:
?- middle([1,2,3],M).
M = 2 ;
false.
?- middle([1,2,3,4],M).
M = 2 ;
false.
In your implementation the problem is that by writing for example:
list_length([X|XTail|Y], 2)
The above does not give you as X the first element and as Y the last so I think it has some major problems...
As well pointed out by lurker you could write the above solution in one clause without using reverse/2:
middle(L, M) :- append(L1, [M|T], L), length(L1, N), length([M|T], N1),
(N1 is N + 1 ; N1 is N + 2).
Also to make the solution more relational (also see mat's comment below) you could use CLPFD library and replace is/2 with #= like:
middle(L, M) :- append(L1, [M|T], L), length(L1, N), length([M|T], N1),
(N1 #= N + 1 ; N1 #= N + 2).
Another interesting solution is to consider this predicate for splitting a list in half:
half(List, Left, Right) :-
half(List, List, Left, Right).
half(L, [], [], L).
half(L, [_], [], L).
half([H|T], [_,_|T2], [H|Left], Right) :-
half(T, T2, Left, Right).
This predicate divides an even list into two equal halves, or an odd list into two pieces where the right half has one more element than the left. It does so by reducing the original list, via the second argument, by two elements, each recursive call, while at the same time reducing the original list by one element each recursive call via the first argument. When it recurses down to the second argument being zero or one elements in length, then the first argument represents the half that's left, which is the right-hand list.
Example results for half/3 are:
| ?- half([a,b,c], L, R).
L = [a]
R = [b,c] ? a
(1 ms) no
| ?- half([a,b,c,d], L, R).
L = [a,b]
R = [c,d] ? a
no
| ?-
We can't quite use this to easily find the middle element because, in the even case, we want the last element of the left hand list. If we could bias the right-hand list by an extra element, we could then pick off the head of the right-hand half as the "middle" element. We can accomplish this using the deleteLast/2 here:
middle([X], X).
middle(List, Middle) :-
deleteLast(List, ListWithoutLast),
half(ListWithoutLast, _, [Middle|_]).
The head of the right half list of the original list, with the last element deleted, is the "middle" element. We can also simply half/3 and combine it with middle/2 since we don't really need everything half/3 does (e.g., we don't need the left-hand list, or the tail of the right hand list):
middle([X], X).
middle(List, Middle) :-
deleteLast(List, ListWithoutLast),
middle(ListWithoutLast, ListWithoutLast, Middle).
middle([M|_], [], M).
middle([M|_], [_], M).
middle([_|T], [_,_|T2], Right) :-
middle(T, T2, Right).
Another approach would be to modify half/3 to bias the splitting of the original list in half toward the right-hand half, which eliminates the need for using deleteLast/2.
modified_half(List, Left, Right) :-
modified_half(List, List, Left, Right).
modified_half(L, [_], [], L).
modified_half(L, [_,_], [], L).
modified_half([H|T], [_,_,X|T2], [H|Left], Right) :-
modified_half(T, [X|T2], Left, Right).
This will bias the right hand list to have an extra element at the "expense" of the left:
| ?- modified_half([a,b,c,d,e], L, R).
L = [a,b]
R = [c,d,e] ? a
no
| ?- modified_half([a,b,c,d,e,f], L, R).
L = [a,b]
R = [c,d,e,f] ? a
no
| ?-
Now we can see that the middle element, per the original definition, is just the head of the right hand list. We can create a new definition for middle/2 using the above. As we did before with half/3, we can ignore everything but the head in the right half, and we can eliminate the left half since we don't need it, and create a consolidated middle/2 predicate:
middle(List, Middle) :-
middle(List, List, Middle).
middle([M|_], [_,_], M).
middle([M|_], [_], M).
middle([_|T], [_,_,X|T2], Middle) :-
middle(T, [X|T2], Middle).
This reduces the original list down one element at a time (first argument) and two elements at a time (second argument) until the second argument is reduced to one or two elements. It then considers the head first argument to be the middle element:
This gives:
| ?- middle([a,b,c], M).
M = b ? ;
no
| ?- middle([a,b,c,d], M).
M = b ? ;
no
| ?- middle(L, M).
L = [M,_] ? ;
L = [M] ? ;
L = [_,M,_,_] ? ;
L = [_,M,_] ? ;
L = [_,_,M,_,_,_] ? ;
L = [_,_,M,_,_] ? ;
L = [_,_,_,M,_,_,_,_] ?
...
Given two sorted lists Xs and Ys, how do I ensure the absolute difference between any X in Xs and any Y in Ys is at least two?
Sample queries with expected answers:
?- different([1,2,4],[5,6]). % 5-4 < 2
false
?- different([1,4],[2,6]). % 2-1 < 2
false
?- different([1,2,6],[4,8]). % 4-2 >= 2 and 6-4 >= 2 and 8-6 >= 2
true
?- different([],[4]).
true
How can I get to this result? Any ideas? Thank you!
Edit: Here is the code I have now:
difference([], []).
difference([_|_], []).
difference([], [_|_]).
difference(L1, L2) :-
L1 = [X1|X2],
L2 = [Y1|_],
Dif is X1-Y1,
(-1>Dif|Dif>1),
difference(X2, L2).
In this answer we use clpfd to attain both
versatility and optimum (linear) arithmetic complexity.
diff_to_mdist([], _, _).
diff_to_mdist([_|_], [], _).
diff_to_mdist([X|Xs], [Y|Ys], D) :-
( X #=< Y-D, diff_to_mdist(Xs, [Y|Ys], D)
; X #> Y-D, X #>= Y+D, diff_to_mdist([X|Xs], Ys, D)
).
diff_to_mdist([X0,X1|Xs], [Y0,Y1|Ys], D) :-
X0 #> Y0-D, X0 #< Y0+D,
( X0 #< Y0, X0 #=< Y0-D, X1 #>= Y0+D, diff_to_mdist([X0,X1|Xs], [Y1|Ys], D)
; X0 #> Y0, Y0 #=< X0-D, Y1 #>= X0+D, diff_to_mdist([X1|Xs], [Y0,Y1|Ys], D)
).
Let's use gnu-prolog version 1.4.4 and run queries like the ones suggested by the OP!
| ?- diff_to_mdist([1,2,4], [5,6], 2).
no
| ?- diff_to_mdist([1,4], [2,6], 2).
no
| ?- diff_to_mdist([1,2,6], [4,8], 2).
true ? ;
no
| ?- diff_to_mdist([], [4], 2).
yes
First, you can make your current code a lot neater and easier to read as follows:
different([], []).
different([_|_], []).
different([], [_|_]).
different([X|Xs], [Y|Ys]) :-
abs(X-Y) >= 2, % Prolog evaluates arithmetic expressions for compares
different(Xs, [Y|Ys]).
In this case, you've done one level of the recursion I mentioned in my comment, as it only checks each element of the first list against only the first element of the second. It ignores all the other elements of the second list. So you need to break it down further. You could make a helper predicate which compares each element of a list against a single value. Then have your main predicate call this helper predicate with each element of the other list. The main predicate would then look like:
different([], []).
different([], [_|_]).
different([X|Xs], L) :-
different_element(X, L),
different(Xs, L).
Then the helper predicate would be:
% This predicate succeeds if the first argument has the desired difference
% to each of the elements of the second argument (a list)
%
different_element(_, []).
different_element(X, [Y|Ys]) :-
abs(X-Y) >= 2,
different_element(X, Ys).
xMenores(_,[],[]).
xMenores(X,[H|T],[R|Z]) :-
xMenores(X,T,Z),
X > H,
R is H.
xMenores takes three parameters:
The first one is a number.
The second is a list of numbers.
The third is a list and is the variable that will contain the result.
The objective of the rule xMenores is obtain a list with the numbers of the list (Second parameter) that are smaller than the value on the first parameter. For example:
?- xMenores(3,[1,2,3],X).
X = [1,2]. % expected result
The problem is that xMenores returns false when X > H is false and my programming skills are almost null at prolog. So:
?- xMenores(4,[1,2,3],X).
X = [1,2,3]. % Perfect.
?- xMenores(2,[1,2,3],X).
false. % Wrong! "X = [1]" would be perfect.
I consider X > H, R is H. because I need that whenever X is bigger than H, R takes the value of H. But I don't know a control structure like an if or something in Prolog to handle this.
Please, any solution? Thanks.
Using ( if -> then ; else )
The control structure you might be looking for is ( if -> then ; else ).
Warning: you should probably swap the order of the first two arguments:
lessthan_if([], _, []).
lessthan_if([X|Xs], Y, Zs) :-
( X < Y
-> Zs = [X|Zs1]
; Zs = Zs1
),
lessthan_if(Xs, Y, Zs1).
However, if you are writing real code, you should almost certainly go with one of the predicates in library(apply), for example include/3, as suggested by #CapelliC:
?- include(>(3), [1,2,3], R).
R = [1, 2].
?- include(>(4), [1,2,3], R).
R = [1, 2, 3].
?- include(<(2), [1,2,3], R).
R = [3].
See the implementation of include/3 if you want to know how this kind of problems are solved. You will notice that lessthan/3 above is nothing but a specialization of the more general include/3 in library(apply): include/3 will reorder the arguments and use the ( if -> then ; else ).
"Declarative" solution
Alternatively, a less "procedural" and more "declarative" predicate:
lessthan_decl([], _, []).
lessthan_decl([X|Xs], Y, [X|Zs]) :- X < Y,
lessthan_decl(Xs, Y, Zs).
lessthan_decl([X|Xs], Y, Zs) :- X >= Y,
lessthan_decl(Xs, Y, Zs).
(lessthan_if/3 and lessthan_decl/3 are nearly identical to the solutions by Nicholas Carey, except for the order of arguments.)
On the downside, lessthan_decl/3 leaves behind choice points. However, it is a good starting point for a general, readable solution. We need two code transformations:
Replace the arithmetic comparisons < and >= with CLP(FD) constraints: #< and #>=;
Use a DCG rule to get rid of arguments in the definition.
You will arrive at the solution by lurker.
A different approach
The most general comparison predicate in Prolog is compare/3. A common pattern using it is to explicitly enumerate the three possible values for Order:
lessthan_compare([], _, []).
lessthan_compare([H|T], X, R) :-
compare(Order, H, X),
lessthan_compare_1(Order, H, T, X, R).
lessthan_compare_1(<, H, T, X, [H|R]) :-
lessthan_compare(T, X, R).
lessthan_compare_1(=, _, T, X, R) :-
lessthan_compare(T, X, R).
lessthan_compare_1(>, _, T, X, R) :-
lessthan_compare(T, X, R).
(Compared to any of the other solutions, this one would work with any terms, not just integers or arithmetic expressions.)
Replacing compare/3 with zcompare/3:
:- use_module(library(clpfd)).
lessthan_clpfd([], _, []).
lessthan_clpfd([H|T], X, R) :-
zcompare(ZOrder, H, X),
lessthan_clpfd_1(ZOrder, H, T, X, R).
lessthan_clpfd_1(<, H, T, X, [H|R]) :-
lessthan_clpfd(T, X, R).
lessthan_clpfd_1(=, _, T, X, R) :-
lessthan_clpfd(T, X, R).
lessthan_clpfd_1(>, _, T, X, R) :-
lessthan_clpfd(T, X, R).
This is definitely more code than any of the other solutions, but it does not leave behind unnecessary choice points:
?- lessthan_clpfd(3, [1,3,2], Xs).
Xs = [1, 2]. % no dangling choice points!
In the other cases, it behaves just as the DCG solution by lurker:
?- lessthan_clpfd(X, [1,3,2], Xs).
Xs = [1, 3, 2],
X in 4..sup ;
X = 3,
Xs = [1, 2] ;
X = 2,
Xs = [1] ;
X = 1,
Xs = [] .
?- lessthan_clpfd(X, [1,3,2], Xs), X = 3. %
X = 3,
Xs = [1, 2] ; % no error!
false.
?- lessthan_clpfd([1,3,2], X, R), R = [1, 2].
X = 3,
R = [1, 2] ;
false.
Unless you need such a general approach, include(>(X), List, Result) is good enough.
This can also be done using a DCG:
less_than([], _) --> [].
less_than([H|T], N) --> [H], { H #< N }, less_than(T, N).
less_than(L, N) --> [H], { H #>= N }, less_than(L, N).
| ?- phrase(less_than(R, 4), [1,2,3,4,5,6]).
R = [1,2,3] ? ;
You can write your predicate as:
xMenores(N, NumberList, Result) :- phrase(less_than(Result, N), NumberList).
You could write it as a one-liner using findall\3:
filter( N , Xs , Zs ) :- findall( X, ( member(X,Xs), X < N ) , Zs ) .
However, I suspect that the point of the exercise is to learn about recursion, so something like this would work:
filter( _ , [] , [] ) .
filter( N , [X|Xs] , [X|Zs] ) :- X < N , filter(N,Xs,Zs) .
filter( N , [X|Xs] , Zs ) :- X >= N , filter(N,Xs,Zs) .
It does, however, unpack the list twice on backtracking. An optimization here would be to combine the 2nd and 3rd clauses by introducing a soft cut like so:
filter( _ , [] , [] ) .
filter( N , [X|Xs] , [X|Zs] ) :-
( X < N -> Zs = [X|Z1] ; Zs = Z1 ) ,
filter(N,Xs,Zs)
.
(This is more like a comment than an answer, but too long for a comment.)
Some previous answers and comments have suggested using "if-then-else" (->)/2 or using library(apply) meta-predicate include/3. Both methods work alright, as long as only plain-old Prolog arithmetics—is/2, (>)/2, and the like—are used ...
?- X = 3, include(>(X),[1,3,2,5,4],Xs).
X = 3, Xs = [1,2].
?- include(>(X),[1,3,2,5,4],Xs), X = 3.
ERROR: >/2: Arguments are not sufficiently instantiated
% This is OK. When instantiation is insufficient, an exception is raised.
..., but when doing the seemingly benign switch from (>)/2 to (#>)/2, we lose soundness!
?- X = 3, include(#>(X),[1,3,2,5,4],Xs).
X = 3, Xs = [1,2].
?- include(#>(X),[1,3,2,5,4],Xs), X = 3.
false.
% This is BAD! Expected success with answer substitutions `X = 3, Xs = [1,2]`.
No new code is presented in this answer.
In the following we take a detailed look at different revisions of this answer by #lurker.
Revision #1, renamed to less_than_ver1//2. By using dcg and clpfd, the code is both very readable and versatile:
less_than_ver1(_, []) --> [].
less_than_ver1(N, [H|T]) --> [H], { H #< N }, less_than_ver1(N, T).
less_than_ver1(N, L) --> [H], { H #>= N }, less_than_ver1(N, L).
Let's query!
?- phrase(less_than_ver1(N,Zs),[1,2,3,4,5]).
N in 6..sup, Zs = [1,2,3,4,5]
; N = 5 , Zs = [1,2,3,4]
; N = 4 , Zs = [1,2,3]
; N = 3 , Zs = [1,2]
; N = 2 , Zs = [1]
; N in inf..1, Zs = []
; false.
?- N = 3, phrase(less_than_ver1(N,Zs),[1,2,3,4,5]).
N = 3, Zs = [1,2] % succeeds, but leaves useless choicepoint
; false.
?- phrase(less_than_ver1(N,Zs),[1,2,3,4,5]), N = 3.
N = 3, Zs = [1,2]
; false.
As a small imperfection, less_than_ver1//2 leaves some useless choicepoints.
Let's see how things went with the newer revision...
Revision #3, renamed to less_than_ver3//2:
less_than_ver3([],_) --> [].
less_than_ver3(L,N) --> [X], { X #< N -> L=[X|T] ; L=T }, less_than_ver3(L,N).
This code uses the if-then-else ((->)/2 + (;)/2) in order to improve determinism.
Let's simply re-run the above queries!
?- phrase(less_than_ver3(Zs,N),[1,2,3,4,5]).
N in 6..sup, Zs = [1,2,3,4,5]
; false. % all other solutions are missing!
?- N = 3, phrase(less_than_ver3(Zs,N),[1,2,3,4,5]).
N = 3, Zs = [1,2] % works as before, but no better.
; false. % we still got the useless choicepoint
?- phrase(less_than_ver3(Zs,N),[1,2,3,4,5]), N = 3.
false. % no solution!
% we got one with revision #1!
Surprise! Two cases that worked before are now (somewhat) broken, and the determinism in the ground case is no better... Why?
The vanilla if-then-else often cuts too much too soon, which is particularly problematic with code which uses coroutining and/or constraints.
Note that (*->)/2 (a.k.a. "soft-cut" or if/3), fares only a bit better, not a lot!
As if_/3 never ever cuts more (often than) the vanilla if-then-else (->)/2, it cannot be used in above code to improve determinism.
If you want to use if_/3 in combination with constraints, take a step back and write code that is non-dcg as the first shot.
If you're lazy like me, consider using a meta-predicate like tfilter/3 and (#>)/3.
This answer by #Boris presented a logically pure solution which utilizes clpfd:zcompare/3 to help improve determinism in certain (ground) cases.
In this answer we will explore different ways of coding logically pure Prolog while trying to avoid the creation of useless choicepoints.
Let's get started with zcompare/3 and (#<)/3!
zcompare/3 implements three-way comparison of finite domain variables and reifies the trichotomy into one of <, =, or >.
As the inclusion criterion used by the OP was a arithmetic less-than test, we propose using
(#<)/3 for reifying the dichotomy into one of true or false.
Consider the answers of the following queries:
?- zcompare(Ord,1,5), #<(1,5,B).
Ord = (<), B = true.
?- zcompare(Ord,5,5), #<(5,5,B).
Ord = (=), B = false.
?- zcompare(Ord,9,5), #<(9,5,B).
Ord = (>), B = false.
Note that for all items to be selected both Ord = (<) and B = true holds.
Here's a side-by-side comparison of three non-dcg solutions based on clpfd:
The left one uses zcompare/3 and first-argument indexing on the three cases <, =, and >.
The middle one uses (#<)/3 and first-argument indexing on the two cases true and false.
The right one uses (#<)/3 in combination with if_/3.
Note that we do not need to define auxiliary predicates in the right column!
less_than([],[],_). % less_than([],[],_). % less_than([],[],_).
less_than([Z|Zs],Ls,X) :- % less_than([Z|Zs],Ls,X) :- % less_than([Z|Zs],Ls,X) :-
zcompare(Ord,Z,X), % #<(Z,X,B), % if_(Z #< X,
ord_lt_(Ord,Z,Ls,Rs), % incl_lt_(B,Z,Ls,Rs), % Ls = [Z|Rs],
less_than(Zs,Rs,X). % less_than(Zs,Rs,X). % Ls = Rs),
% % less_than(Zs,Rs,X).
ord_lt_(<,Z,[Z|Ls],Ls). % incl_lt_(true ,Z,[Z|Ls],Ls). %
ord_lt_(=,_, Ls ,Ls). % incl_lt_(false,_, Ls ,Ls). %
ord_lt_(>,_, Ls ,Ls). % %
Next, let's use dcg!
In the right column we use if_//3 instead of if_/3.
Note the different argument orders of dcg and non-dcg solutions: less_than([1,2,3],Zs,3) vs phrase(less_than([1,2,3],3),Zs).
The following dcg implementations correspond to above non-dcg codes:
less_than([],_) --> []. % less_than([],_) --> []. % less_than([],_) --> [].
less_than([Z|Zs],X) --> % less_than([Z|Zs],X) --> % less_than([Z|Zs],X) -->
{ zcompare(Ord,Z,X) }, % { #<(Z,X,B) }, % if_(Z #< X,[Z],[]),
ord_lt_(Ord,Z), % incl_lt_(B,Z), % less_than(Zs,X).
less_than(Zs,X). % less_than(Zs,X). %
% %
ord_lt_(<,Z) --> [Z]. % incl_lt_(true ,Z) --> [Z]. %
ord_lt_(=,_) --> []. % incl_lt_(false,_) --> []. %
ord_lt_(>,_) --> []. % %
OK! Saving the best for last... Simply use meta-predicate tfilter/3 together with (#>)/3!
less_than(Xs,Zs,P) :-
tfilter(#>(P),Xs,Zs).
The dcg variant in this previous answer is our starting point.
Consider the auxiliary non-terminal ord_lt_//2:
ord_lt_(<,Z) --> [Z].
ord_lt_(=,_) --> [].
ord_lt_(>,_) --> [].
These three clauses can be covered using two conditions:
Ord = (<): the item should be included.
dif(Ord, (<)): it should not be included.
We can express this "either-or choice" using if_//3:
less_than([],_) --> [].
less_than([Z|Zs],X) -->
{ zcompare(Ord,Z,X) },
if_(Ord = (<), [Z], []),
less_than(Zs,X).
Thus ord_lt_//2 becomes redundant.
Net gain? 3 lines-of-code !-)
I have been brushing up on some Prolog recently. I kind of enjoy just coming up with random problems to try and solve and then working them out. This one is quite tough though, and I'm not one to give up on a problem that I have set out to solve.
The problem: I want to make a predicate that will have 2 predetermined lists, 2 numbers to swap, and then output the lists after the swapping is done.
Further Explanation: I made it a little harder on myself by wanting to find a specific unique number from list 1, and swapping this with a specific unique number from list 2 so that if I have 2 lists...
[7,2,7,8,5], and [1,2,3,8,7,9,8], and then give the predicate 2 numbers(Lets just say 8 and 7), then the number 8 and the number 7 will be swapped between the lists IF AND ONLY IF the number 8 is in the first list and the number 7 is in the second list. (It would disregard an 8 in the second list and a 7 in the first list).
Sample query with expected answer:
?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8],8,7,X,Y).
X = [7,2,7,7,5], Y = [1,2,3,8,8,9,8].
I kind of got stuck at this point:
bothSwap([],L2,N1,N2,[],L2).
bothSwap(L1,[],N1,N2,L1,[]).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 == N2, bothSwap(T1,T2,N1,N2,D1,D2), append(D1,[H2],X), append(D2,[H1],Y).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 =\= N2, bothSwap([H1|T1],T2,N1,N2,D1,D2).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 =\= N1, H2 == N2, bothSwap(T1,[H2|T2],N1,N2,D1,D2).
Any bright minds out there willing to tackle this problem with me? :)
Imagine how easy this problem would be if we could just "wish" for a list to be split up at the occurrence of the desired element, like this:
?- splitsies([1,2,3,4,5,6,7,8], 4, Prefix, Suffix).
Prefix = [1, 2, 3],
Suffix = [5, 6, 7, 8] ;
Guess what? :) append/3 can do that:
% splitsies is true if X splits list into a prefix/suffix pair.
splitsies(List, X, Start, Finish) :-
append(Start, [X|Finish], List).
Now the problem seems pretty simple!
bothSwap(Left, Right, A, B, AfterLeft, AfterRight) :-
% break up the inputs
splitsies(Left, A, LPre, LPost),
splitsies(Right, B, RPre, RPost),
% glue together the outputs (note that A and B are switched)
splitsies(AfterLeft, B, LPre, LPost),
splitsies(AfterRight, A, RPre, RPost).
I wouldn't pretend that this solution is efficient… but it's so hot you better wear oven mitts when you type it in. Oh, and check this out:
?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8], X, Y, [7,2,7,7,5], [1,2,3,8,8,9,8]).
X = 8,
Y = 7 ;
false.
Let's start, what you mean by swapping.
swap(X0,X, S0,S) :-
if_(X0 = S0, S = X, S = S0).
bothSwap0(Xs0, Ys0, X0,X, Xs,Ys) :-
maplist(swap(X0,X), Xs0,Xs),
maplist(swap(X,X0), Ys0,Ys).
if_( C_1, Then_0, Else_0) :-
call(C_1, Truth),
functor(Truth,_,0), % safety check
( Truth == true -> Then_0 ; Truth == false, Else_0 ).
=(X, Y, R) :- X == Y, !, R = true.
=(X, Y, R) :- ?=(X, Y), !, R = false. % syntactically different
=(X, Y, R) :- X \= Y, !, R = false. % semantically different
=(X, Y, R) :- R == true, !, X = Y.
=(X, X, true).
=(X, Y, false) :-
dif(X, Y).
Now you wanted a particular condition - it is not clear how to apply it. I see two interpretations:
bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
memberd(X0, Xs0),
memberd(X, Ys0),
maplist(swap(X0,X), Xs0,Xs),
maplist(swap(X,X0), Ys0,Ys).
Which means that bothSwap/6 will fail should the two elements not occur in their respective list.
Another interpretation might be that you want that otherwise the lists remain the same. To express this (in a pure monotonic fashion):
bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
if_( ( memberd_t(X0, Xs0), memberd_t(X, Ys0) ),
( maplist(swap(X0,X), Xs0,Xs), maplist(swap(X,X0), Ys0,Ys) ),
( Xs0 = Xs, Ys0 = Ys) ).
memberd_t(E, Xs, T) :-
list_memberd(Xs, E, T).
list_memberd([], _, false).
list_memberd([X|Xs], E, T) :-
if_(E = X, T = true, list_memberd(Xs, E, T) ).
','( A_1, B_1, T) :-
if_( A_1, call(B_1, T), T = false ).
Since Prolog is a descriptive language (that is, we describe what constitutes a solution and let Prolog work it out), If I understand your problem statement correctly, something like this ought to suffice:
both_swap(L1, L2, A, B, S1, S2 ) :- % to do the swap,
memberchk(A,L1) , % - L1 must contain an A
memberchk(B,L2) , % - L2 must contain a B
replace(L1,A,B,S1) , % - replace all As in L1 with a B
replace(L2,B,A,S2) % - replace all Bs in L2 with an A
. % Easy!
replace([],_,_,[]) . % if the list is empty, we're done.
replace([H|T],A,B,[S|Ss]) :- % otherwise...
( H = A -> S=B ; S=H ) , % - do the swap (if necessary),
replace(T,A,B,Ss) % - and recurse down
. % Also easy!
This replicates the implementation that uses splitsies/4
swap_two(A,B,C,D,E,F) :-
nth0(I1,A,C,L1),
dif(A,L1),
nth0(I2,B,D,L2),
dif(B,L2),
nth0(I1,E,D,L1),
nth0(I2,F,C,L2).
I am trying to write a Prolog code finding the n-th element of a list.
I wrote the below code but it doesn't return the element right.
match([Elem|Tail],Num,Num,Elem).
match([Elem|Tail],Num,C,MatchedNumber):-
match(Tail,Num,N,Elem),
C is N+1.
In the first line I say, if the requested element number is equal to counter, then give the first element of the current list to the variable called MatchedNumber. This code returns the Num and Counter right but I don't know why when I want to set the MatchedNumber as Elem, it always returns the first element of the list.
1: what is wrong with this code?
2: How can I say instead of showing the matched number, remove it from list?
First of all, there is a builtin nth0/3 for that:
?- nth0(0,[a,b,c],X).
X = a.
?- nth0(1,[a,b,c],X).
X = b.
?- nth0(2,[a,b,c],X).
X = c.
?- nth0(3,[a,b,c],X).
false.
Get the i-th element
The problem is in the inductive case:
match([Elem|Tail],Num,Counter,MatchedNumber):-
match(Tail,Num,N,Elem),
C is N+1.
Prolog doesn't know anything about C so the last statement doens't force Prolog to return the i-th element. It can simply return any element because N will match with Num in the recursive call and then set C to Num+1 but that's not a problem because C is not bound by anything.
A better way to solve this, is using a decrement counter:
match([H|_],0,H) :-
!.
match([_|T],N,H) :-
N > 0, %add for loop prevention
N1 is N-1,
match(T,N1,H).
Example:
?- match([a,b,c,d,e],0,X).
X = a.
?- match([a,b,c,d,e],1,X).
X = b.
?- match([a,b,c,d,e],2,X).
X = c.
?- match([a,b,c,d,e],3,X).
X = d.
?- match([a,b,c,d,e],4,X).
X = e.
?- match([a,b,c,d,e],5,X).
false.
The base case is thus that the index is 0 in which case you return the head, otherwise you query for the i-1-th element of the tail. This is also a more declarative approach.
This approach also makes use of tail recursion which in general will boost performance significantly.
Modifying the original predicate
It is rather un-Prolog to use an iterator and a bound, one in general uses a reverse iterator.
You can however modify the predicate as follows:
match([Elem|_],Num,Num,Elem) :-
!.
match([_|Tail],Num,Count,MatchedNumber) :-
Count < Num,
Count1 is Count+1,
match(Tail,Num,Count1,MatchedNumber).
So a few errors:
Use a "cut" ! in the first clause: since if it matches, we know Prolog should not try the second one;
Use MatchedNumber in the recursive call instead of Elem;
Perform a bound check Count < Num,
Do the increment of the counter Count1 is Count+1 before doing the recursive call; and
Substitute all variables you do not use by underscores _.
An example is then:
?- match([a,b,c,d,e],0,0,X).
X = a.
?- match([a,b,c,d,e],1,0,X).
X = b.
?- match([a,b,c,d,e],2,0,X).
X = c.
?- match([a,b,c,d,e],3,0,X).
X = d.
?- match([a,b,c,d,e],4,0,X).
X = e.
?- match([a,b,c,d,e],5,0,X).
false.
But as said before, it is inefficient to pass an additional argument, etc.
Remove the i-th element from the list
An almost equivalent approach can be used to remove the i-th element from the list:
removei([],_,[]).
removei([_|T],0,T) :-
!.
removei([H|T],N,[H|TR]) :-
N1 is N-1,
removei(T,N1,TR).
Here the base case is again that the index is 0 in which case the tail of the list is removed (thus dropping the head). The inductive case will place the head of the list in the head of the resulting list and will count on the recursive call to remove the correct item from the tail. Another base case removei([],_,[]). is added because it is possible that i is greater than the length of the list in which case this predicate won't remove any item.
Example
?- removei([a,b,c,d,e],0,X).
X = [b, c, d, e].
?- removei([a,b,c,d,e],1,X).
X = [a, c, d, e].
?- removei([a,b,c,d,e],2,X).
X = [a, b, d, e].
?- removei([a,b,c,d,e],3,X).
X = [a, b, c, e].
?- removei([a,b,c,d,e],4,X).
X = [a, b, c, d].
?- removei([a,b,c,d,e],5,X).
X = [a, b, c, d, e].
?- removei([a,b,c,d,e],6,X).
X = [a, b, c, d, e].
To find the nth element of a list (where n is relative to zero), something like this ought to suffice:
find_nth_element_of_list( 0 , X , [X|_] ) .
find_nth_element_of_list( N , X , [_|Xs] ) :-
N > 0 ,
N1 is N-1 ,
find_nth_element_of_list( N1 , X , Xs )
.
Similarly, to remove the nth element of a list, something like this ought to suffice:
remove_nth_element_of_list( 0 , [_|Xs] , Xs ) . % at n=0, toss the head and unify the tail with the result set
remove_nth_element_of_list( N , [X|Xs] , [X|Ys] ) :- % at n>0, prepend the head to the result and recurse down.
N > 0 ,
N1 is N-1 ,
remove_nth_element_of_list( N1 , Xs , Ys )
.
If for some reason you need to achieve this using no built-in predicates besides append here is my implementation:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(N, List, H) :-
append(L1, [H|_], List),
my_length(L1, N),
!.
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
and without append:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(0, [H|_], H) :- !.
my_nth(N, [_|T], Result) :-
N1 is N - 1,
my_nth(N1, T, Result),
!.
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
And without !:
my_length([], 0).
my_length([_|T], N1) :- my_length(T, N), N1 is N + 1.
% Nth
my_nth(N, [_|T], Result) :-
N > 0,
N1 is N - 1,
my_nth(N1, T, Result).
my_nth(0, [H|_], H).
test_my_nth(X, Y, Z) :-
my_nth(0, [123, 456, 789], X),
my_nth(1, [123, 456, 789], Y),
my_nth(2, [123, 456, 789], Z).
% X = 123
% Y = 456
% Z = 789
Why would anyone need it? There is a specific professor at Poznan University of Technology that requires students to write predicates like this.