Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Library function for Permutation and Combination in C++

What's the most widely used existing library in C++ to give all the combination and permutation of k elements out of n elements?

I am not asking the algorithm but the existing library or methods.

Thanks.

like image 388
skydoor Avatar asked Feb 06 '10 03:02

skydoor


People also ask

How do you do permutations and combinations in C?

In C programming language, nCr is referred as the combination. nCr is the selection of r objects from a set of n objects, where the order of objects does not matter. nPr is referred as the permutation. nPr is arrangement of 'r' objects from a set of 'n' objects, which should be in an order or sequence.

What is permutation combination?

permutations and combinations, the various ways in which objects from a set may be selected, generally without replacement, to form subsets. This selection of subsets is called a permutation when the order of selection is a factor, a combination when order is not a factor.

What's the difference between permutations and combinations?

What do you mean by permutations and combinations? A permutation is an act of arranging the objects or numbers in order. Combinations are the way of selecting the objects or numbers from a group of objects or collection, in such a way that the order of the objects does not matter.


1 Answers

I decided to test the solutions by dman and Charles Bailey here. I'll call them solutions A and B respectively. My test is visiting each combination of of a vector<int> size = 100, 5 at a time. Here's the test code:

Test Code

struct F {     unsigned long long count_;      F() : count_(0) {}      bool operator()(std::vector<int>::iterator, std::vector<int>::iterator)     {++count_; return false;} };  int main() {     typedef std::chrono::high_resolution_clock Clock;     typedef std::chrono::duration<double> sec;     typedef std::chrono::duration<double, std::nano> ns;     int n = 100;     std::vector<int> v(n);     std::iota(v.begin(), v.end(), 0);     std::vector<int>::iterator r = v.begin() + 5;     F f;     Clock::time_point t0 = Clock::now();     do     {         f(v.begin(), r);     } while (next_combination(v.begin(), r, v.end()));     Clock::time_point t1 = Clock::now();     sec s0 = t1 - t0;     ns pvt0 = s0 / f.count_;     std::cout << "N = " << v.size() << ", r = " << r-v.begin()               << ", visits = " << f.count_ << '\n'               << "\tnext_combination total = " << s0.count() << " seconds\n"               << "\tnext_combination per visit = " << pvt0.count() << " ns"; } 

All code was compiled using clang++ -O3 on a 2.8 GHz Intel Core i5.

Solution A

Solution A results in an infinite loop. Even when I make n very small, this program never completes. Subsequently downvoted for this reason.

Solution B

This is an edit. Solution B changed in the course of writing this answer. At first it gave incorrect answers and due to very prompt updating it now gives correct answers. It prints out:

N = 100, r = 5, visits = 75287520     next_combination total = 4519.84 seconds     next_combination per visit = 60034.3 ns 

Solution C

Next I tried the solution from N2639 which looks very similar to solution A, but works correctly. I'll call this solution C and it prints out:

N = 100, r = 5, visits = 75287520     next_combination total = 6.42602 seconds     next_combination per visit = 85.3531 ns 

Solution C is 703 times faster than solution B.

Solution D

Finally there is a solution D found here. This solution has a different signature / style and is called for_each_combination, and is used much like std::for_each. The driver code above changes between the timer calls like so:

Clock::time_point t0 = Clock::now(); f = for_each_combination(v.begin(), r, v.end(), f); Clock::time_point t1 = Clock::now(); 

Solution D prints out:

N = 100, r = 5, visits = 75287520     for_each_combination = 0.498979 seconds     for_each_combination per visit = 6.62765 ns 

Solution D is 12.9 times faster than solution C, and over 9000 times faster than solution B.

I consider this a relatively small problem: only 75 million visits. As the number of visits increases into the billions, the discrepancy in the performance between these algorithms continues to grow. Solution B is already unwieldy. Solution C eventually becomes unwieldy. Solution D is the highest performing algorithm to visit all combinations I'm aware of.

The link showing solution D also contains several other algorithms for enumerating and visiting permutations with various properties (circular, reversible, etc.). Each of these algorithms was designed with performance as one of the goals. And note that none of these algorithms requires the initial sequence to be in sorted order. The elements need not even be LessThanComparable.

like image 101
Howard Hinnant Avatar answered Sep 20 '22 22:09

Howard Hinnant