knedlsepp
knedlsepp

Reputation: 6084

Generating all combinations with repetition using MATLAB

How do I create all k-combinations with repetitions of a given set (also called k-multicombinations or multisubsets) using MATLAB?

This is similar to the cartesian product, but two rows that only differ by their sorting should be considered the same (e.g. the vectors [1,1,2]=~=[1,2,1] are considered to be the same), so generating the cartesian product and then applying unique(sort(cartesianProduct,2),'rows') should yield the same results.

Example: The call nmultichoosek(1:n,k) should generate the following matrix:

nmultichoosek(1:3,3)
ans =
     1     1     1
     1     1     2
     1     1     3
     1     2     2
     1     2     3
     1     3     3
     2     2     2
     2     2     3
     2     3     3
     3     3     3

Upvotes: 11

Views: 15729

Answers (3)

Luis Mendo
Luis Mendo

Reputation: 112669

Thanks to Hans Hirse for a correction.

Brute-force approach: generate all tuples and then keep only those that are sorted. Not suitable for large values of n or k.

values = 1:3;                               %//  data
k = 3;                                      %//  data
n = numel(values);                          %//  number of values
combs = values(dec2base(0:n^k-1,n)-'0'+1);  %//  generate all tuples
combs = combs(all(diff(combs.')>=0, 1),:);  %'// keep only those that are sorted

Upvotes: 2

Buck Thorn
Buck Thorn

Reputation: 5073

This is probably an even more brutal (memory intensive) method than previous posts, but a tidy readable one-liner:

 combs = unique(sort(nchoosek(repmat(values,1,k),k),2),'rows');

Upvotes: 1

knedlsepp
knedlsepp

Reputation: 6084

We can use the bijection mentioned in the wikipedia article, which maps combinations without repetition of type n+k-1 choose k to k-multicombinations of size n. We generate the combinations without repetition and map them using bsxfun(@minus, nchoosek(1:n+k-1,k), 0:k-1);. This results in the following function:

function combs = nmultichoosek(values, k)
%// Return number of multisubsets or actual multisubsets.
if numel(values)==1 
    n = values;
    combs = nchoosek(n+k-1,k);
else
    n = numel(values);
    combs = bsxfun(@minus, nchoosek(1:n+k-1,k), 0:k-1);
    combs = reshape(values(combs),[],k);
end

Upvotes: 19

Related Questions