Skip to content

Subset sum (CLP(FD))

Pick a subset of numbers to reach a target sum using 0/1 decision variables.

subset_sum(Weights, Target, Picks) :-
    same_length(Weights, Picks),
    booleans(Picks),
    scalar_product(Weights, Picks, Target),
    label(Picks).

% Picks are 0/1 variables
booleans([]).
booleans([X|Xs]) :- X in 0..1, booleans(Xs).

% Sum W_i * P_i equals Target
scalar_product([], [], 0).
scalar_product([W|Ws], [P|Ps], Target) :-
    scalar_product(Ws, Ps, Sub),
    Target #= Sub + W*P.

same_length([], []).
same_length([_|Xs], [_|Ys]) :- same_length(Xs, Ys).
?- subset_sum([3,4,5,6], 9, Picks).
Picks = [1,0,1,0] ;
Picks = [0,1,0,1] ; ...

Note: This simple encoding uses in/2 and linear constraints; for performance on larger instances, specialized propagators are preferable.