Search code examples
prologclpfdgnu-prolog

How to use an fd solver to determine which elements of a list can sum to a given number?


Given a list of possible summands I want to determine which, if any, can form a given sum. For example, with [1,2,3,4,5] I can make the sum of 9 with [4,5], [5,3,1], and [4,3,2]. I am using GNU Prolog and have something like the following which does not work

numbers([1,2,3,4,5]).

all_unique(_, []).
all_unique(L, [V|T]) :-
    fd_exactly(1, L, V),
    all_unique(L, T).

fd_sum([], Sum).
fd_sum([H|T], Sum):-
    S = Sum + H,
    fd_sum(T, S).
    
sum_clp(N, Summands):-
    numbers(Numbers),
    length(Numbers, F),
    between(1, F, X),
    length(S, X),
    fd_domain(S, Numbers),
    fd_domain(Y, [N]),
    all_unique(S, Numbers),
    fd_sum(S, Sum),
    Sum #= Y,
    fd_labeling(S).

I think the main problem is that I am not representing the constraint on the sum properly? Or maybe it is something else?


Solution

  • Just in case you're really interested in CLP(FD), here is your corrected program.

    numbers([1,2,3,4,5]).
    
    % note: use builtins where available, both for efficiency and correctness
    %all_unique(_, []).
    %all_unique(L, [V|T]) :-
    %    fd_exactly(1, L, V),
    %    all_unique(L, T).
    
    fd_sum([], 0). % sum_fd_SO.pl:8: warning: singleton variables [Sum] for fd_sum/2
    fd_sum([H|T], Sum):-
        % note: use CLP(FD) operators and the correct operands
        Sum #= S + H,
        fd_sum(T, S).
        
    sum_clp(N, S):- % sum_fd_SO.pl:13-23: warning: singleton variables [Summands] for sum_clp/2
        numbers(Numbers),
        length(Numbers, F),
        between(1, F, X),
        length(S, X),
        fd_domain(S, Numbers),
        %fd_domain(Y, [N]),
        %all_unique(S, Numbers),
        fd_all_different(S),
        fd_sum(S, N),
        %Sum #= Y,
        fd_labeling(S).
    

    test

     ?- sum_clp(3,L).
    
    L = [3] ? ;
    
    L = [1,2] ? ;
    
    L = [2,1] ? ;
    
    no