Fastest solution for all possible combinations, taking k elements out of n possible elements for k > 2 and n large


MathUser

I am using MATLAB to find all possible combinations of k elements from n possible elements . I stumbled upon this question , but unfortunately it doesn't solve my problem. Of course neither, since my n is around 100.nchoosek

The thing is, I don't need to use all possible combinations at the same time. I'll explain my needs as there may be easier ways to achieve the desired result. I have a matrix M with 100 rows and 25 columns .

A submatrix of M can be thought of as a matrix formed by a subset of all columns and rows of M. I have a function f that can be applied to any matrix that results in -1 or 1. For example, you can think of a function as where A is any matrix (the exact function is irrelevant to this part of the question).sign(det(A))

I would like to know what is the maximum number of rows of M , and the submatrix A formed by these rows is such that f(A) = 1 . Note that if f(M) = 1 , I'm done. However, if this is not the case, then I need to start combining rows, all combinations starting with row 99, then row 98, and so on.

Until now, I've achieved only a few lines when working with M. However, since I'm working with a relatively large dataset, things get bogged down. Have you guys thought of a way to do it without using the above function? Any help would be greatly appreciated.nchoosek

Here is my minimal working example, it works for smaller examples, obs_totbut fails when I try with larger numbers:

value = -1; obs_tot = 100; n_rows = 25;
mat = randi(obs_tot,n_rows);
while value == -1
    posibles = nchoosek(1:obs_tot,i);
    [num_tries,num_obs] = size(possibles);
    num_try = 1;
        while value == 0 && num_try <= num_tries
        check = mat(possibles(num_try,:),:);
        value = sign(det(check));
        num_try = num_try + 1;
        end
    i = i - 1;
end
obs_used = possibles(num_try-1,:)';
civic madness

foreword

As you yourself noticed in the question, it's better not to return all possible combinations at once, but to enumerate them one by one so as not to blow up memory when it gets bigger . So something like:nchoosekn

enumerator = CombinationEnumerator(k, n);
while(enumerator.MoveNext())
    currentCombination = enumerator.Current;
    ...
end

This is the implementation of the enumerator for the Matlab class. It's based on the classic interface in C#/.NET and mimics sub-functions in ( unfolded ) way :IEnumerator<T>combsnchoosek

%
% PURPOSE:
%
%   Enumerates all combinations of length 'k' in a set of length 'n'.
%
% USAGE:
%
%   enumerator = CombinaisonEnumerator(k, n);
%   while(enumerator.MoveNext())
%       currentCombination = enumerator.Current;
%       ...
%   end
%

%% ---
classdef CombinaisonEnumerator  < handle

    properties (Dependent) % NB: Matlab R2013b bug => Dependent must be declared before their get/set !
        Current; % Gets the current element.
    end

    methods
        function [enumerator] = CombinaisonEnumerator(k, n)
        % Creates a new combinations enumerator.

            if (~isscalar(n) || (n < 1) || (~isreal(n)) || (n ~= round(n))), error('`n` must be a scalar positive integer.'); end
            if (~isscalar(k) || (k < 0) || (~isreal(k)) || (k ~= round(k))), error('`k` must be a scalar positive or null integer.'); end
            if (k > n), error('`k` must be less or equal than `n`'); end

            enumerator.k = k;
            enumerator.n = n;
            enumerator.v = 1:n;            
            enumerator.Reset();

        end
        function [b] = MoveNext(enumerator)
        % Advances the enumerator to the next element of the collection.

            if (~enumerator.isOkNext), 
                b = false; return; 
            end

            if (enumerator.isInVoid)
                if (enumerator.k == enumerator.n),
                    enumerator.isInVoid = false;
                    enumerator.current = enumerator.v;
                elseif (enumerator.k == 1)
                    enumerator.isInVoid = false;
                    enumerator.index = 1;
                    enumerator.current = enumerator.v(enumerator.index);                    
                else
                    enumerator.isInVoid = false;
                    enumerator.index = 1;
                    enumerator.recursion = CombinaisonEnumerator(enumerator.k - 1, enumerator.n - enumerator.index);
                    enumerator.recursion.v = enumerator.v((enumerator.index + 1):end); % adapt v (todo: should use private constructor)
                    enumerator.recursion.MoveNext();
                    enumerator.current = [enumerator.v(enumerator.index) enumerator.recursion.Current]; 
                end
            else
                if (enumerator.k == enumerator.n),
                    enumerator.isInVoid = true;
                    enumerator.isOkNext = false;
                elseif (enumerator.k == 1)
                    enumerator.index = enumerator.index + 1;
                    if (enumerator.index <= enumerator.n)
                        enumerator.current = enumerator.v(enumerator.index);
                    else 
                        enumerator.isInVoid = true;
                        enumerator.isOkNext = false;
                    end                                       
                else
                    if (enumerator.recursion.MoveNext())
                        enumerator.current = [enumerator.v(enumerator.index) enumerator.recursion.Current];
                    else
                        enumerator.index = enumerator.index + 1;
                        if (enumerator.index <= (enumerator.n - enumerator.k + 1))
                            enumerator.recursion = CombinaisonEnumerator(enumerator.k - 1, enumerator.n - enumerator.index);
                            enumerator.recursion.v = enumerator.v((enumerator.index + 1):end); % adapt v (todo: should use private constructor)
                            enumerator.recursion.MoveNext();
                            enumerator.current = [enumerator.v(enumerator.index) enumerator.recursion.Current];
                        else 
                            enumerator.isInVoid = true;
                            enumerator.isOkNext = false;
                        end                                                               
                    end
                end
            end

            b = enumerator.isOkNext;

        end
        function [] = Reset(enumerator)
        % Sets the enumerator to its initial position, which is before the first element.

            enumerator.isInVoid = true;
            enumerator.isOkNext = (enumerator.k > 0);

        end
        function [c] = get.Current(enumerator)
            if (enumerator.isInVoid), error('Enumerator is positioned (before/after) the (first/last) element.'); end
            c = enumerator.current;
        end
    end

    properties (GetAccess=private, SetAccess=private)
        k = [];
        n = [];
        v = [];
        index = [];
        recursion = [];
        current = [];
        isOkNext = false;
        isInVoid = true;
    end

end

We can test that the implementation is working from the command window as follows:

>> e = CombinaisonEnumerator(3, 6);
>> while(e.MoveNext()), fprintf(1, '%s\n', num2str(e.Current)); end

The following combinations are expected to be returned :n!/(k!*(n-k)!)

1  2  3
1  2  4
1  2  5
1  2  6
1  3  4
1  3  5
1  3  6
1  4  5
1  4  6
1  5  6
2  3  4
2  3  5
2  3  6
2  4  5
2  4  6
2  5  6
3  4  5
3  4  6
3  5  6
4  5  6

The implementation of this enumerator can be further optimized for speed, or by enumerating the combinations in an order that better suits your situation (eg, test some combinations first and not others)...well, at least it works! :)

Solve the problem

It's really easy to solve your problem now:

n = 100;
m = 25;
matrix = rand(n, m);

k = n;
cont = true;
while(cont && (k >= 1))

    e = CombinationEnumerator(k, n);
    while(cont && e.MoveNext());

       cont = f(matrix(e.Current(:), :)) ~= 1;

    end

    if (cont), k = k - 1; end 

end 

Related


all possible combinations of k with lists of size n

Theodore Narliyski: I want to get all possible combinations of size K from a list of size N. I have a list with "person" objects and I am trying to create a new ArrayList which will be filled with the list of objects. Each table will be a different combination

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Algorithm to return all combinations of k elements from n

Frederick I want to write a function that takes an array of letters as a parameter and selects multiple letters. Suppose you provide an array of 8 letters and want to select 3 letters from it. Then you will get: 8! / ((8 - 3)! * 3!) = 56 Returns an array (or

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

Get all possible combinations of elements

sa555 How would you get all possible combinations of 2 elements in an array? E.g: [ 1, 2, 3, 4 ] becomes [ [1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4

get all possible combinations of k elements from a list

Tobias Herman I need a function that does the same thing as itertools.combinations(iterable, r) in python So far I came up with this: {-| forward application -} x -: f = f x infixl 0 -: {-| combinations 2 "ABCD" = ["AB","AC","AD","BC","BD","CD"] -} combinatio

Get all possible combinations of k elements from a list

Tobias Herman I need a function that does the same thing as in pythonitertools.combinations(iterable, r) So far I have come up with this: {-| forward application -} x -: f = f x infixl 0 -: {-| combinations 2 "ABCD" = ["AB","AC","AD","BC","BD","CD"] -} combin

Fastest sorting method for k numbers and N elements, k <<< N

Puckz Problem: There are n balls, marked as 0, 1, 2, in random order, I want to sort from small to large. ball: 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, ... It must be solved in the fastest way. The sort() function cannot be used. I have thought of many ways, such as bu

All possible combinations of N objects in K buckets

Aliresa Norri Say I have 3 boxes labeled A, B, C and I have 2 balls, B1 and B2. I want to get all possible combinations of these balls in a box. Note that it is important to know the balls in each box, which means that B1 and B2 are not the same. A B

all possible combinations of k with lists of size n

Theodore Narliyski: I want to get all possible combinations of size K from a list of size N. I have a list with "person" objects and I am trying to create a new ArrayList which will be filled with the list of objects. Each table will be a different combination

Algorithm to return all combinations of k elements from n

Frederick I want to write a function that takes an array of letters as a parameter and selects multiple letters. Suppose you provide an array of 8 letters and want to select 3 letters from it. Then you will get: 8! / ((8 - 3)! * 3!) = 56 Returns an array (or