Related
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.
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).
Define a predicate subsetsum(L, Sum, Subl) that takes a list L of numbers, a number Sum, and unifies SubL with a sub sequence of L such that the sum of the numbers in SubL is Sum.
For example
?- subsetsum([1,2,5,3,2], 5, SubSet);
SubSet = [1,2,2];
SubSet = [2,3];
SubSet = [5];
SubSet = [3,2];
No.
we have
sum([H1 | [H2 | Tail]], S):-
sum([[H1+H2]|Tail], S):-
sum([X], X).
and
subset([],[]).
subset([H1|T1], [H1|T2]) :- // heads are the same
subset(T1, T2).
subset([_|Rest], X):
subset(Rest, X).
If all numbers used are integers and your Prolog processor supports clpfd, proceed like this!
:- use_module(library(clpfd)).
z_z_product(A,B,AB) :-
AB #= A*B.
subsetsum_(Zs, Sum, Bs, [Sum|Vs]) :-
same_length(Zs, Bs),
append(Zs, Bs, Vs),
Bs ins 0..1,
maplist(z_z_product, Zs, Bs, Xs),
sum(Xs, #=, Sum).
Sample query:
?- subsetsum_([1,2,5,3,2], 5, Sel, Vs), labeling([], Vs).
Sel = [0,0,0,1,1], Vs = [5,1,2,5,3,2,0,0,0,1,1]
; Sel = [0,0,1,0,0], Vs = [5,1,2,5,3,2,0,0,1,0,0]
; Sel = [0,1,0,1,0], Vs = [5,1,2,5,3,2,0,1,0,1,0]
; Sel = [1,1,0,0,1], Vs = [5,1,2,5,3,2,1,1,0,0,1]
; false.
The following clauses should do what you need...
subsetsum(SET, SUM, ANSWER) :-
% Find a subset
subset(SET, ANSWER),
% Check elements of the subset add up to SUM
sum(ANSWER, SUM).
% sum(LIST, SUM) - sums all numbers in the list
sum([], 0).
sum([X | T], SUM) :-
sum(T, TAILSUM),
SUM is TAILSUM + X.
% subset - finds subsets
subset([], []).
subset([E|Tail], [E|NTail]) :-
subset(Tail, NTail).
subset([_|Tail], NTail) :-
subset(Tail, NTail).
With swi-prolog we can use the library predicate sum_list/2 together with that subset/2 you already got! Note that I gave subset/2 the better fitting name list_subsequence/2:
list_subsequence([], []).
list_subsequence([X|Xs], [X|Ys]) :-
list_subsequence(Xs, Ys).
list_subsequence([_|Xs], Ys) :-
list_subsequence(Xs, Ys).
subsetsum(List, Sum, Sub) :-
list_subsequence(List, Sub),
sum_list(Sub, Sum).
Here is the sample query that you gave:
?- subsetsum([1,2,5,3,2], 5, Xs).
Xs = [1,2,2]
; Xs = [2,3]
; Xs = [5]
; Xs = [3,2]
; false.
OK! Let's run another query with both integers and floats... does that work, too?
?- subsetsum([1,2.1,5,3,2], 5.1, Xs).
Xs = [1,2.1,2]
; Xs = [2.1,3]
; false.
Looks alright to me!
I would like to perform something like:
merge([[[],[],[],[t1]],[[],[],[],[t2,t3]]], X).
where X would return as: [[],[],[],[t1,t2,t3]].
But I have tried everything to my prolog knowledge and came up with nothing.
Any hints?
Imagine it as:
Computer(
Tasklist1(
core1[sometasks],core2[sometasks],...,coreX(sometasks)),
...
TasklistX(
core1[sometasks],core2[sometasks],...,coreX(sometasks))
)
so the tasklist after tasklist1 needs to be scheduled on the same cores, after the tasks of tasklist1.
It's not totally clear what the limits of the problem may be. But here is a solution which assumes you may have more than two inner list-of-lists, and the count of the innermost lists might vary.
merge2(L, [], L) :- L \= [].
merge2([], L, L).
merge2([LH1|LT1], [LH2|LT2], [LH3|LT3]) :-
append(LH1, LH2, LH3),
merge2(LT1, LT2, LT3).
merge([L], L).
merge([H1,H2|T], R) :-
merge2(H1, H2, H),
merge([H|T], R).
So,
| ?- merge([[[],[],[],[t1]],[[],[],[],[t2,t3]]], L).
L = [[],[],[],[t1,t2,t3]] ? ;
no
| ?- merge([[[1],[2],[3]], [[4],[5],[6]],[[a],[b],[c,d]]], L).
L = [[1,4,a],[2,5,b],[3,6,c,d]] ? a
no
| ?- merge([[[1],[2],[3]], [[5],[6]],[[a],[b],[c,d]]], L).
L = [[1,5,a],[2,6,b],[3,c,d]] ? ;
(1 ms) no
| ?-
If you want to restrict the innermost list counts to be the same, you can replace merge2 with maplist, and the merge predicate simply becomes:
merge([L], L).
merge([H1,H2|T], R) :-
maplist(append, H1, H2, H),
merge([H|T], R).
I thought it could be easier...
merge(L, R) :-
maplist(length_list(N), L),
findall(S, (
between(1,N,I),
findall(Zs, (
member(Z,L),
nth1(I,Z,Zs)), T),
append(T, S)), R).
length_list(Len, L) :- length(L, Len).
I need a function in Prolog: swapcouple(L, L1).
swapcouple([a,b,c,d,e], M) --> output M=[b,a,d,c,e]
swapcouple([a,b,c,d], M) --> output M=[b,a,d,c]
(what have you tried?) This is a valid definition:
swapcouple([a,b,c,d,e], M) :- M=[b,a,d,c,e].
swapcouple([a,b,c,d], M) :- M=[b,a,d,c].
Proceed by abstraction. For example,
swapcouple([A,B,C,D,E], M) :- M=[B,A,D,C,E].
swapcouple([A,B,C,D], M) :- M=[B,A,D,C].
Do you see where I'm going? [A,B,C,D,E] = [A,B | R] where R = [C,D,E]. Can we use that?
swapcouple([A,B|R], M) :- R=[C,D,E], M=[B,A|S], S=[D,C,E].
Right? Here's the crucial bit. R=[C,D,E], S=[D,C,E] is the same as swapcouple(R,S), isn't it?
swapcouple([A,B|R], M) :- M=[B,A|S], swapcouple(R,S).
Assuming that swapcouple does what it is advertised to do, we can just use it when the need arises. Here you've got your very own recursive procedure (well, predicate). It is even tail recursive modulo cons, which is even more hip and fun.
Few more edge cases are missing there. I'm positive you can finish it up.
The implementation can hardly get more direct than this:
list_swappedcouples([],[]).
list_swappedcouples([A],[A]).
list_swappedcouples([A,B|Xs],[B,A|Ys]) :-
list_swappedcouples(Xs,Ys).
Here are your sample queries:
?- list_swappedcouples([a,b,c,d,e],Ls).
Ls = [b,a,d,c,e] ; % succeeds, but leaves behind choicepoint
false.
?- list_swappedcouples([a,b,c,d],Ls).
Ls = [b,a,d,c]. % succeeds deterministically
Edit 2015-06-03
We can utilize first argument indexing to improve determinism.
list_with_swapped_couples([],[]).
list_with_swapped_couples([X|Xs],Ys) :-
list_prev_w_swapped_couples(Xs,X,Ys).
list_prev_w_swapped_couples([],X,[X]).
list_prev_w_swapped_couples([X1|Xs],X0,[X1,X0|Ys]) :-
list_with_swapped_couples(Xs,Ys).
Note that all following sample queries succeed deterministically.
?- list_with_swapped_couples([],Xs).
Xs = [].
?- list_with_swapped_couples([1],Xs).
Xs = [1].
?- list_with_swapped_couples([1,2],Xs).
Xs = [2,1].
?- list_with_swapped_couples([1,2,3],Xs).
Xs = [2,1,3].
?- list_with_swapped_couples([1,2,3,4],Xs).
Xs = [2,1,4,3].
?- list_with_swapped_couples([1,2,3,4,5],Xs).
Xs = [2,1,4,3,5].