Combinations in all orders - prolog

I want to generate all pairs of all the numbers of a range 1..N in all orders i.e. [X,Y] and [Y,X]
I found these here : http://kti.ms.mff.cuni.cz/~bartak/prolog/combinatorics.html
comb(0,_,[]).
comb(N,[X|T],[X|Comb]):-N>0,N1 is N-1,comb(N1,T,Comb).
comb(N,[_|T],Comb):-N>0,comb(N,T,Comb).
comb_rep(0,_,[]).
comb_rep(N,[X|T],[X|RComb]):-N>0,N1 is N-1,comb_rep(N1,[X|T],RComb).
comb_rep(N,[_|T],RComb):-N>0,comb_rep(N,T,RComb).
?- findall(E1,comb_rep(2,[1,2,3],E1),C1),findall(E2,comb(2,[3,2,1],E2),C2),append(C1,C2,C),write(C).
[[1,1],[1,2],[1,3],[2,2],[2,3],[3,3],[3,2],[3,1],[2,1]]
There have to be an easier way ?
Also i would prefer to do it as GENERATOR, rather than a FULLY rendered list (like the ex above)

I suspect I am missing something because this does so much less than the code you posted, but this seems to create the pairs how you ask:
limit_pairs(N, [X, Y]) :-
between(1, N, X),
between(1, N, Y).
e.g.
?- limit_pairs(3, P).
P = [1, 1]
P = [1, 2]
P = [1, 3]
P = [2, 1]
P = [2, 2]
P = [2, 3]
P = [3, 1]
P = [3, 2]
P = [3, 3]

Related

List of subset sums Prolog

Given a list L of natural numbers I need to create a list containing the sums of the elements of all the subsets of L. For example if L=[1,3,6] I want to obtain the list [0,1,3,4,6,7,9,10].
I tried to use this code
subsetSums(List,Sums) :- findall(Sum,(subset(Sub,List),sum_list(Sub,Sum)),Sums).
but with the following query I get [0] as the only result instead of [0,1,2,3]
?- subsetSums([1,2],Sums).
Where am I wrong?
EDIT: I'm working on SWI Prolog and subset/2 should be a native predicate.
As suggested in the comment, you have to write your own subset/2 predicate and then use findall/3 on this predicate, like this:
subset([], []).
subset([E|T], [E|T1]):-
subset(T, T1).
subset([_|T], L):-
subset(T, L).
subsetSums(List,Sums) :-
findall(S,(subset(List,Sub),sumlist(Sub,S)),Sums).
?- subsetSums([1,2],L).
L = [3, 1, 2, 0]
?- subsetSums([1,2,3],L).
L = [6, 3, 4, 1, 5, 2, 3, 0]
where the output of subset/2 is:
subset([1,2,3],L).
L = [1, 2, 3]
L = [1, 2]
L = [1, 3]
L = [1]
L = [2, 3]
L = [2]
L = [3]
L = []

All possible knight positions in n moves - infinite loop in prolog

I have a problem with backtracking in Prolog when calculation solution for all possible knight positions in n moves with knowing the exact path.
My solution print some of the first results and then never terminate while looking for impossible results.
This is my code:
move([X, Y], [A, B]) :- X + 1 < 8, Y + 2 < 8, A is X + 1, B is Y + 2.
move([X, Y], [A, B]) :- X + 2 < 8, Y + 1 < 8, A is X + 2, B is Y + 1.
move([X, Y], [A, B]) :- X + 2 < 8, Y - 1 >= 0, A is X + 2, B is Y - 1.
move([X, Y], [A, B]) :- X + 1 < 8, Y - 2 >= 0, A is X + 1, B is Y - 2.
move([X, Y], [A, B]) :- X - 1 >= 0, Y - 2 >= 0, A is X - 1, B is Y - 2.
move([X, Y], [A, B]) :- X - 2 >= 0, Y - 1 >= 0, A is X - 2, B is Y - 1.
move([X, Y], [A, B]) :- X - 2 >= 0, Y + 1 < 8, A is X - 2, B is Y + 1.
move([X, Y], [A, B]) :- X - 1 >= 0, Y + 2 < 8, A is X - 1, B is Y + 2.
knight_move(X,Y,[X,Y],1) :- move(X,Y).
knight_move(X,Y,[X|P],C) :- move(X,Z), knight_move(Z,Y,P,Cn), C is Cn+1.
predict_moves(X,C,P) :- knight_move(X,_,P,C).
Sample call:
predict_moves([1,1],3,P).
In result I expect all possible paths in n 3 moves. Can sb help me with adding condition to my code to stop my code from backtracking to move and looping to infinity?
Before actually removing the problem, let's narrow down the source of non-termination. In your case, it is particularly tricky, for you get answers that are nice and correct. Only then there is a problem. The easiest way to narrow down the problem is by adding false goals into your program. If the resulting program still loops, we can continue adding further such goals. Here is what I came up with:
move([X, Y], [A, B]) :- X+1 < 8, Y+2 < 8, A is X+1, B is Y+2.
move([X, Y], [A, B]) :- false, X+2 < 8, Y+1 < 8, A is X+2, B is Y+1.
move([X, Y], [A, B]) :- false, X+2 < 8, Y-1 >= 0, A is X+2, B is Y-1.
move([X, Y], [A, B]) :- false, X+1 < 8, Y-2 >= 0, A is X+1, B is Y-2.
move([X, Y], [A, B]) :- X-1 >= 0, Y-2 >= 0, A is X-1, B is Y-2.
move([X, Y], [A, B]) :- false, X-2 >= 0, Y-1 >= 0, A is X-2, B is Y-1.
move([X, Y], [A, B]) :- false, X-2 >= 0, Y+1 < 8, A is X-2, B is Y+1.
move([X, Y], [A, B]) :- false, X-1 >= 0, Y+2 < 8, A is X-1, B is Y+2.
knight_move(X,Y,[X,Y],1) :- false, move(X,Y).
knight_move(X,Y,[X|P],C) :- move(X,Z), knight_move(Z,Y,P,Cn), false, C is Cn+1.
predict_moves(X,C,P) :- knight_move(X,_,P,C), false.
?- predict_moves([1,1],3,P), false.
All parts that are now striked through have no influence at all to termination. That might be a little irritating at first, for that code is actually executed, but still: no influence on termination. Note that in particular the variable C in knight_move/4 is now a singleton!
You need to modify the remaining visible part to remove the error.
If you use CLP(FD) for reasoning over integers, and change the order of your constraints so that you constrain the counter before you recurse, that will eliminate your looping issue:
move([X, Y], [A, B]) :- X + 1 #< 8, Y + 2 #< 8, A #= X + 1, B #= Y + 2.
move([X, Y], [A, B]) :- X + 2 #< 8, Y + 1 #< 8, A #= X + 2, B #= Y + 1.
move([X, Y], [A, B]) :- X + 2 #< 8, Y - 1 #>= 0, A #= X + 2, B #= Y - 1.
move([X, Y], [A, B]) :- X + 1 #< 8, Y - 2 #>= 0, A #= X + 1, B #= Y - 2.
move([X, Y], [A, B]) :- X - 1 #>= 0, Y - 2 #>= 0, A #= X - 1, B #= Y - 2.
move([X, Y], [A, B]) :- X - 2 #>= 0, Y - 1 #>= 0, A #= X - 2, B #= Y - 1.
move([X, Y], [A, B]) :- X - 2 #>= 0, Y + 1 #< 8, A #= X - 2, B #= Y + 1.
move([X, Y], [A, B]) :- X - 1 #>= 0, Y + 2 #< 8, A #= X - 1, B #= Y + 2.
knight_move(X,Y,[X,Y], 1) :- move(X,Y).
# NOTE the constraint of C #= Cn + 1 before the recursive call
knight_move(X,Y,[X|P], C) :- C #> 1, move(X,Z), C #= Cn + 1, knight_move(Z,Y,P,Cn).
predict_moves(X,C,P) :- knight_move(X,_,P,C).
Which results in:
| ?- predict_moves([1,1], 3, P).
P = [[1,1],[2,3],[3,5],[4,7]] ? a
P = [[1,1],[2,3],[3,5],[5,6]]
P = [[1,1],[2,3],[3,5],[5,4]]
P = [[1,1],[2,3],[3,5],[4,3]]
P = [[1,1],[2,3],[3,5],[2,3]]
P = [[1,1],[2,3],[3,5],[1,4]]
P = [[1,1],[2,3],[3,5],[1,6]]
P = [[1,1],[2,3],[3,5],[2,7]]
P = [[1,1],[2,3],[4,4],[5,6]]
P = [[1,1],[2,3],[4,4],[6,5]]
P = [[1,1],[2,3],[4,4],[6,3]]
P = [[1,1],[2,3],[4,4],[5,2]]
P = [[1,1],[2,3],[4,4],[3,2]]
P = [[1,1],[2,3],[4,4],[2,3]]
P = [[1,1],[2,3],[4,4],[2,5]]
P = [[1,1],[2,3],[4,4],[3,6]]
P = [[1,1],[2,3],[4,2],[5,4]]
P = [[1,1],[2,3],[4,2],[6,3]]
P = [[1,1],[2,3],[4,2],[6,1]]
P = [[1,1],[2,3],[4,2],[5,0]]
P = [[1,1],[2,3],[4,2],[3,0]]
P = [[1,1],[2,3],[4,2],[2,1]]
P = [[1,1],[2,3],[4,2],[2,3]]
P = [[1,1],[2,3],[4,2],[3,4]]
P = [[1,1],[2,3],[3,1],[4,3]]
P = [[1,1],[2,3],[3,1],[5,2]]
P = [[1,1],[2,3],[3,1],[5,0]]
P = [[1,1],[2,3],[3,1],[1,0]]
P = [[1,1],[2,3],[3,1],[1,2]]
P = [[1,1],[2,3],[3,1],[2,3]]
P = [[1,1],[2,3],[1,1],[2,3]]
P = [[1,1],[2,3],[1,1],[3,2]]
P = [[1,1],[2,3],[1,1],[3,0]]
P = [[1,1],[2,3],[1,1],[0,3]]
P = [[1,1],[2,3],[0,2],[1,4]]
P = [[1,1],[2,3],[0,2],[2,3]]
P = [[1,1],[2,3],[0,2],[2,1]]
P = [[1,1],[2,3],[0,2],[1,0]]
P = [[1,1],[2,3],[0,4],[1,6]]
P = [[1,1],[2,3],[0,4],[2,5]]
P = [[1,1],[2,3],[0,4],[2,3]]
P = [[1,1],[2,3],[0,4],[1,2]]
P = [[1,1],[2,3],[1,5],[2,7]]
P = [[1,1],[2,3],[1,5],[3,6]]
P = [[1,1],[2,3],[1,5],[3,4]]
P = [[1,1],[2,3],[1,5],[2,3]]
P = [[1,1],[2,3],[1,5],[0,3]]
P = [[1,1],[2,3],[1,5],[0,7]]
P = [[1,1],[3,2],[4,4],[5,6]]
P = [[1,1],[3,2],[4,4],[6,5]]
P = [[1,1],[3,2],[4,4],[6,3]]
P = [[1,1],[3,2],[4,4],[5,2]]
P = [[1,1],[3,2],[4,4],[3,2]]
P = [[1,1],[3,2],[4,4],[2,3]]
P = [[1,1],[3,2],[4,4],[2,5]]
P = [[1,1],[3,2],[4,4],[3,6]]
P = [[1,1],[3,2],[5,3],[6,5]]
P = [[1,1],[3,2],[5,3],[7,4]]
P = [[1,1],[3,2],[5,3],[7,2]]
P = [[1,1],[3,2],[5,3],[6,1]]
P = [[1,1],[3,2],[5,3],[4,1]]
P = [[1,1],[3,2],[5,3],[3,2]]
P = [[1,1],[3,2],[5,3],[3,4]]
P = [[1,1],[3,2],[5,3],[4,5]]
P = [[1,1],[3,2],[5,1],[6,3]]
P = [[1,1],[3,2],[5,1],[7,2]]
P = [[1,1],[3,2],[5,1],[7,0]]
P = [[1,1],[3,2],[5,1],[3,0]]
P = [[1,1],[3,2],[5,1],[3,2]]
P = [[1,1],[3,2],[5,1],[4,3]]
P = [[1,1],[3,2],[4,0],[5,2]]
P = [[1,1],[3,2],[4,0],[6,1]]
P = [[1,1],[3,2],[4,0],[2,1]]
P = [[1,1],[3,2],[4,0],[3,2]]
P = [[1,1],[3,2],[2,0],[3,2]]
P = [[1,1],[3,2],[2,0],[4,1]]
P = [[1,1],[3,2],[2,0],[0,1]]
P = [[1,1],[3,2],[2,0],[1,2]]
P = [[1,1],[3,2],[1,1],[2,3]]
P = [[1,1],[3,2],[1,1],[3,2]]
P = [[1,1],[3,2],[1,1],[3,0]]
P = [[1,1],[3,2],[1,1],[0,3]]
P = [[1,1],[3,2],[1,3],[2,5]]
P = [[1,1],[3,2],[1,3],[3,4]]
P = [[1,1],[3,2],[1,3],[3,2]]
P = [[1,1],[3,2],[1,3],[2,1]]
P = [[1,1],[3,2],[1,3],[0,1]]
P = [[1,1],[3,2],[1,3],[0,5]]
P = [[1,1],[3,2],[2,4],[3,6]]
P = [[1,1],[3,2],[2,4],[4,5]]
P = [[1,1],[3,2],[2,4],[4,3]]
P = [[1,1],[3,2],[2,4],[3,2]]
P = [[1,1],[3,2],[2,4],[1,2]]
P = [[1,1],[3,2],[2,4],[0,3]]
P = [[1,1],[3,2],[2,4],[0,5]]
P = [[1,1],[3,2],[2,4],[1,6]]
P = [[1,1],[3,0],[4,2],[5,4]]
P = [[1,1],[3,0],[4,2],[6,3]]
P = [[1,1],[3,0],[4,2],[6,1]]
P = [[1,1],[3,0],[4,2],[5,0]]
P = [[1,1],[3,0],[4,2],[3,0]]
P = [[1,1],[3,0],[4,2],[2,1]]
P = [[1,1],[3,0],[4,2],[2,3]]
P = [[1,1],[3,0],[4,2],[3,4]]
P = [[1,1],[3,0],[5,1],[6,3]]
P = [[1,1],[3,0],[5,1],[7,2]]
P = [[1,1],[3,0],[5,1],[7,0]]
P = [[1,1],[3,0],[5,1],[3,0]]
P = [[1,1],[3,0],[5,1],[3,2]]
P = [[1,1],[3,0],[5,1],[4,3]]
P = [[1,1],[3,0],[1,1],[2,3]]
P = [[1,1],[3,0],[1,1],[3,2]]
P = [[1,1],[3,0],[1,1],[3,0]]
P = [[1,1],[3,0],[1,1],[0,3]]
P = [[1,1],[3,0],[2,2],[3,4]]
P = [[1,1],[3,0],[2,2],[4,3]]
P = [[1,1],[3,0],[2,2],[4,1]]
P = [[1,1],[3,0],[2,2],[3,0]]
P = [[1,1],[3,0],[2,2],[1,0]]
P = [[1,1],[3,0],[2,2],[0,1]]
P = [[1,1],[3,0],[2,2],[0,3]]
P = [[1,1],[3,0],[2,2],[1,4]]
P = [[1,1],[0,3],[1,5],[2,7]]
P = [[1,1],[0,3],[1,5],[3,6]]
P = [[1,1],[0,3],[1,5],[3,4]]
P = [[1,1],[0,3],[1,5],[2,3]]
P = [[1,1],[0,3],[1,5],[0,3]]
P = [[1,1],[0,3],[1,5],[0,7]]
P = [[1,1],[0,3],[2,4],[3,6]]
P = [[1,1],[0,3],[2,4],[4,5]]
P = [[1,1],[0,3],[2,4],[4,3]]
P = [[1,1],[0,3],[2,4],[3,2]]
P = [[1,1],[0,3],[2,4],[1,2]]
P = [[1,1],[0,3],[2,4],[0,3]]
P = [[1,1],[0,3],[2,4],[0,5]]
P = [[1,1],[0,3],[2,4],[1,6]]
P = [[1,1],[0,3],[2,2],[3,4]]
P = [[1,1],[0,3],[2,2],[4,3]]
P = [[1,1],[0,3],[2,2],[4,1]]
P = [[1,1],[0,3],[2,2],[3,0]]
P = [[1,1],[0,3],[2,2],[1,0]]
P = [[1,1],[0,3],[2,2],[0,1]]
P = [[1,1],[0,3],[2,2],[0,3]]
P = [[1,1],[0,3],[2,2],[1,4]]
P = [[1,1],[0,3],[1,1],[2,3]]
P = [[1,1],[0,3],[1,1],[3,2]]
P = [[1,1],[0,3],[1,1],[3,0]]
P = [[1,1],[0,3],[1,1],[0,3]]
(3 ms) no
| ?-
The problem: you write:
knight_move(X,Y,[X|P],C) :- move(X,Z), knight_move(Z,Y,P,Cn), C is Cn+1.
there is no cut nor any other mechanism that prevents you from taking this branch, so Prolog can keep taking this branch. Furthermore you should decrement the counter Cn is C-1 and do this before the recursive call.
First of all, I think it is better to construct some sort of validation predicate instead of writing all these bounds checks:
valid_position(X,Y) :-
X >= 0,
Y >= 0,
X < 8,
Y < 8.
We can also construct a predicate plusneg/3 such that for posneg(X,DX,Y), Y is both X+DX and X-DX:
posneg(X,DX,Y) :-
Y is X+DX.
posneg(X,DX,Y) :-
Y is X-DX.
then we can describe the "possible moves" of the knight:
possible(X, Y, A, B) :-
posneg(X,2,A),
posneg(Y,1,B).
possible(X, Y, A, B) :-
posneg(X,1,A),
posneg(Y,2,B).
but these are not per se "valid moves", since we need to check if the new coordinate is valid. So we can write:
move([X,Y], [A,B]) :-
possible(X,Y,A,B),
valid_position(A,B).
although this introduces some additiona predicates, and is perhaps a litte less efficient, it is now clear that all the moves are valid ones.
Now for the knigt_move/4 with the counter, we can write a clause that says that if the counter has dropped below zero, no more moves are done:
knight_move(P1,P1,[P1],C) :-
C < 1.
In case the count is one or more, the knight can still do a move, so we can write it as:
knight_move(P1,PZ,[P1|PT],C) :-
C >= 1,
C1 is C-1,
move(P1,P2),
knight_move(P2,PZ,PT,C1).
Or putting this all together:
valid_position(X,Y) :-
X >= 0,
Y >= 0,
X < 8,
Y < 8.
posneg(X,DX,Y) :-
Y is X+DX.
posneg(X,DX,Y) :-
Y is X-DX.
possible(X, Y, A, B) :-
posneg(X,2,A),
posneg(Y,1,B).
possible(X, Y, A, B) :-
posneg(X,1,A),
posneg(Y,2,B).
move([X,Y], [A,B]) :-
possible(X,Y,A,B),
valid_position(A,B).
knight_move(P1,P1,[P1],C) :-
C < 1.
knight_move(P1,PZ,[P1|PT],C) :-
C >= 1,
C1 is C-1,
move(P1,P2),
knight_move(P2,PZ,PT,C1).
If we ask what fields we reach with exactly two moves (and how), we got:
?- knight_move([1,1],End,Path,2).
End = [5, 3],
Path = [[1, 1], [3, 2], [5, 3]] ;
End = [5, 1],
Path = [[1, 1], [3, 2], [5, 1]] ;
End = [1, 3],
Path = [[1, 1], [3, 2], [1, 3]] ;
End = [1, 1],
Path = [[1, 1], [3, 2], [1, 1]] ;
End = [4, 4],
Path = [[1, 1], [3, 2], [4, 4]] ;
End = [4, 0],
Path = [[1, 1], [3, 2], [4, 0]] ;
End = [2, 4],
Path = [[1, 1], [3, 2], [2, 4]] ;
End = [2, 0],
Path = [[1, 1], [3, 2], [2, 0]] ;
End = [5, 1],
Path = [[1, 1], [3, 0], [5, 1]] ;
End = [1, 1],
Path = [[1, 1], [3, 0], [1, 1]] ;
End = [4, 2],
Path = [[1, 1], [3, 0], [4, 2]] ;
End = [2, 2],
Path = [[1, 1], [3, 0], [2, 2]] ;
End = [4, 4],
Path = [[1, 1], [2, 3], [4, 4]] ;
End = [4, 2],
Path = [[1, 1], [2, 3], [4, 2]] ;
End = [0, 4],
Path = [[1, 1], [2, 3], [0, 4]] ;
End = [0, 2],
Path = [[1, 1], [2, 3], [0, 2]] ;
End = [3, 5],
Path = [[1, 1], [2, 3], [3, 5]] ;
End = [3, 1],
Path = [[1, 1], [2, 3], [3, 1]] ;
End = [1, 5],
Path = [[1, 1], [2, 3], [1, 5]] ;
End = [1, 1],
Path = [[1, 1], [2, 3], [1, 1]] ;
End = [2, 4],
Path = [[1, 1], [0, 3], [2, 4]] ;
End = [2, 2],
Path = [[1, 1], [0, 3], [2, 2]] ;
End = [1, 5],
Path = [[1, 1], [0, 3], [1, 5]] ;
End = [1, 1],
Path = [[1, 1], [0, 3], [1, 1]] ;
false.
So we can make 24 paths with exactly two moves. Note that there are duplicates, if we use setof/3 we can determine that we can reach 15 squares with two moves. For three moves there are 148 paths to reach 30 squares:
?- findall(End,knight_move([1,1],End,_,2),Ends), length(Ends,N).
Ends = [[5, 3], [5, 1], [1, 3], [1, 1], [4, 4], [4, 0], [2, 4], [2|...], [...|...]|...],
N = 24.
?- setof(End,Pa^knight_move([1,1],End,Pa,2),Ends), length(Ends,N).
Ends = [[0, 2], [0, 4], [1, 1], [1, 3], [1, 5], [2, 0], [2, 2], [2|...], [...|...]|...],
N = 15.
?- findall(End,knight_move([1,1],End,_,3),Ends), length(Ends,N).
Ends = [[7, 4], [7, 2], [3, 4], [3, 2], [6, 5], [6, 1], [4, 5], [4|...], [...|...]|...],
N = 148.
?- setof(End,Pa^knight_move([1,1],End,Pa,3),Ends), length(Ends,N).
Ends = [[0, 1], [0, 3], [0, 5], [0, 7], [1, 0], [1, 2], [1, 4], [1|...], [...|...]|...],
N = 30.

Generate a list of different values with CLPFD

I am trying to generate all possible combinations of lists of three elements where all are distinct. I am using the CLPFD library to define the domain of the variable.
I defined the following
listDif(F,X):-F ins 1..3,findall(F,all_distinct(F),X).
And the answers to the queries are
?- listDif([1,_,2],X).
X = [[1, 3, 2]].
?- listDif([1,_,_],X).
X = [[1, _7374, _7380]],
_7374 in 2..3,
all_distinct([1, _7374, _7380]),
_7380 in 2..3.
?-
How do I display the lists with the possible integer values?
If you want to generate lists with CLPFD then you need to use lists. :) Your code is just using individual integers.
list3(F) :-
length(F, 3), % F is a list of length 3
F ins 1..3, % Elements of F are in the range 1..3
all_distinct(F). % F has distinct elements
Now you have a predicate which succeeds for unique lists consisting of 1, 2, 3:
?- list3(F), label(F).
F = [1, 2, 3] ;
F = [1, 3, 2] ;
F = [2, 1, 3] ;
F = [2, 3, 1] ;
F = [3, 1, 2] ;
F = [3, 2, 1].
Then you can use findall/3 if you want to have a list of all of these lists:
?- findall(F, (list3(F), label(F)), AllList3).
AllList3 = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]].

Get list of sets where the sum of each set is X

I'm trying to figure out how to generate a list of sets, where each set has a length of N and the sum of each set is X.
I found this code:
num_split(0,[]).
num_split(N, [X | List]):-
between(1,N,X),
plus(X,Y,N),
num_split(Y,List).
And I can use that to get a list of sets with sum X:
num_split(6,List),length(List,5).
List = [1, 1, 1, 1, 2] ;
List = [1, 1, 1, 2, 1] ;
List = [1, 1, 2, 1, 1] ;
List = [1, 2, 1, 1, 1] ;
List = [2, 1, 1, 1, 1] ;
false.
The problem is that those are all permutations, and I'm looking for combinations. The output I'm looking for should be something like get_combos(Sum,Length,List):
get_combos(6,2,List).
List = [5,1];
List = [4,2];
List = [3,3];
false.
Any pointers?
If you have access to a CLP(FD) library, you can use this code:
:- [library(clpfd)].
get_combos(Sum, Length, List) :-
length(List, Length),
List ins 1 .. Sum,
% all_distinct(List), not really useful here
sum(List, #=, Sum),
chain(List, #<),
label(List).
test:
?- get_combos(10,3,L).
L = [1, 2, 7] ;
L = [1, 3, 6] ;
L = [1, 4, 5] ;
L = [2, 3, 5] ;
Maybe I misunderstood your question. Use this chain
...
chain(List, #=<),
....
to get possible duplicates values:
?- get_combos(10,3,L).
L = [1, 1, 8] ;
L = [1, 2, 7] ;
L = [1, 3, 6] ;
L = [1, 4, 5] ;
L = [2, 2, 6] ;
L = [2, 3, 5] ;
L = [2, 4, 4] ;
L = [3, 3, 4] ;
false.
Enforce an "equal or greater" restriction between successive values in the array.
You can add it on as another predicate:
is_combination([]).
is_combination([_]).
is_combination([A,B|List]) :- A =< B, is_combination([B|List]).
get_combos(Sum, Length, List) :-
num_split(Sum, Length, List),
is_combination(List).
Unfortunately, tacking it on the end of the num_split/3 does not necessarily increase its performance, so adding it directly into the algorithm would be marginally better:
get_combos(_, 0, []).
get_combos(Sum, 1, [Sum]).
get_combos(Sum, Length, [A, B|List]) :-
between(1, Sum, A),
plus(A, NextSum, Sum),
plus(1, NextLength, Length),
get_combos(NextSum, NextLength, [B|List]),
A =< B.
I'm not sure just how much more performance this gets, as the comparison has to be after the recursion, due to the less-than-or-equals operator (=<) requiring both operands to be fully instantiated for it to work.

Prolog - Difference between two lists BUT

Using SWI-Prolog's listing predicate (or SICStus' predicate in its list library), we have:
lists:subtract([], _, []) :- !.
lists:subtract([A|C], B, D) :-
memberchk(A, B), !,
subtract(C, B, D).
lists:subtract([A|B], C, [A|D]) :-
subtract(B, C, D).
which does this successfully:
?- subtract([2,3,4,5],[3,4],X).
X = [2, 5].
BUT, what if I want to do:
?- new_subtract([2,3,4,5],[3,X],Y).
X = [3, 2],
X = [3, 4],
X = [3, 5],
Y then has three solutions by taking the three X solutions from [2,3,4,5].
However, subtract/2 doesn't allow for this.
I've been trying to solve this for ages by taking the cuts (!)s out of the built in predicate's body to try and get it to backtrack and find all the solutions.
I assume you mean
?- new_subtract([2,3,4,5],[3,X],Y).
Y = [3, 2] ;
Y = [3, 4] ;
Y = [3, 5]
The following definition does that, but does not preserve all of subtract/3's behavior:
sub(List,[],List).
sub(List,[X|Sub],Rem) :- select(X,List,Rem0), sub(Rem0,Sub,Rem).
Usage:
?- sub([2,3,4,5],[3,X],Y).
X = 2,
Y = [4, 5] ;
X = 4,
Y = [2, 5] ;
X = 5,
Y = [2, 4] ;
false.

Resources