Search code examples
prologclpfd

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?


Solution

  • 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.