Introduction

Combination is the way of picking a different unique smaller set from a bigger set, without regard to the ordering (positions) of the elements (in the smaller set). This article teaches you how to find combinations. First, I will show you the technique to find combinations. Next, I will go on to explain how to use my source code. The source includes a recursive template version and a non-recursive template version. At the end of the article, I will show you how to find permutations of a smaller set from a bigger set, using both next_combination() and next_permutation().

Before all these, let me first introduce to you the technique of finding combinations.

The Technique

The notations used in this article

n: n is the larger sequence from which the r sequence is picked.

r: r is the smaller sequence picked from the n sequence.

c: c is the formula for the total number of possible combinations of r, picked from n distinct objects: n! / (r! (n-r)!).

The ! postfix means factorial.

Explanation

Let me explain using a very simple example: finding all combinations of 2 from a set of 6 letters {A, B, C, D, E, F}. The first combination is AB and the last is EF.

The total number of possible combinations is: n!/(r!(n-r)!)=6!/(2!(6-2)!)=15 combinations.

I'm thinking if you would have noticed by now, the number of times a letter appears. The formula for the number of times a letter appears in all possible combinations is n!/(r!(n-r)!) * r / n == c * r / n. Using the above example, it would be 15 * 4 / 6 = 10 times. All the letters {A, B, C, D, E, F} appear 10 times as shown. You can count them yourself to prove it.

Source Code Section

Please note that all the combination functions are now enclosed in the stdcomb namespace.

The Recursive Way

I have made a recursive function, char_combination() which, as its name implies, takes in character arrays and processes them. The source code and examples of using char_combination() are in char_comb_ex.cpp. I'll stop to mention that function. For now, our focus is on recursive_combination(), a template function, which I wrote using char_combination() as a guideline.

The parameters prefixed with 'n' are associated with the n sequence, while the r-prefixed one are r sequence related. As an end user, you need not bother about those parameters. What you need to know is func. func is a function defined by you. If the combination function finds combinations recursively, there must exist a way the user can process each combination. The solution is a function pointer which takes in two parameters of type RanIt (stands for Random Iterator). You are the one who defines this function. In this way, encapsulation is achieved. You need not know how recursive_combination() internally works, you just need to know that it calls func whenever there is a different combination, and you just need to define the func() function to process the combination. It must be noted that func() should not write to the two iterators passed to it.

The typical way of filling out the parameters is n_column and r_column is always 0, loop is the number of elements in the r sequence minus that of the n sequence, and func is the function pointer to your function (nbegin and nend, and rbegin and rend are self-explanatory; they are the first iterators and the one past the last iterators of the respective sequences).

Just for your information, the maximum depth of the recursion done is r+1. In the last recursion (r+1 recursion), each new combination is formed.

An example of using recursive_combination() with raw character arrays is shown below:

Certain conditions must be satisfied in order for next_combination() to work

All the objects in the n sequence must be distinct.

For next_combination(), the r sequence must be initialized to the first r-th elements of the n sequence in the first call. For example, to find combinations of r=4 out of n=6 {1,2,3,4,5,6}, the r sequence must be initialsed to {1,2,3,4} before the first call.

As for prev_combination(), the r sequence must be initialised to the last r-th elements of the n sequence in the first call. For example, to find combinations of r=4 out of n=6 {1,2,3,4,5,6}, the r sequence must be initialsed to {3,4,5,6} before the first call.

The n sequence must not change throughout the process of finding all the combinations, else results are wrong (makes sense, right?).

next_combination() and prev_combination() operate on data types with the == operator defined. That is to mean if you want to use next_combination() on sequences of objects instead of sequences of POD (Plain Old Data), the class from which these objects are instantiated must have an overloaded == operator defined, or you can use the predicate versions.

When the above conditions are not satisfied, results are undetermined even if next_combination() and prev_combination() may return true.

Return Value

When next_combination() returns false, no more next combinations can be found, and the r sequence remains unaltered. Same for prev_combination().

Some information about next_combination() and prev_combination()

The n and r sequences need not be sorted to use next_combination() or prev_combination().

next_combination() and prev_combination() do not use any static variables, so it is alright to find combinations of another sequence of a different data type, even when the current finding of combinations of the current sequence have not reached the last combination. In other words, no reset is needed for next_combination() and prev_combination().

Examples of how to use these two functions are in next_comb_ex.cpp and prev_comb_ex.cpp.

So what can we do with next_combination()?

With next_combination() and next_permutation() from STL algorithms, we can find permutations!!

The formula for the total number of permutations of the r sequence, picked from the n sequence, is: n!/(n-r)!

We can call next_combination() first, then next_permutation() iteratively; that way, we will find all the permutations. A typical way of using them is as follows:

However, I must mention that there exists a limitation for the above code. The n and r sequences must be sorted in ascending order in order for it to work. This is because next_permutation() will return false when it encounters a sequence in descending order. The solution to this problem for unsorted sequences is as follows:

However, this method requires you to calculate the number of permutations beforehand.

So how do I prove they are distinct permutations?

There is a set container class in STL we can use. All the objects in the set container are always in sorted order, and there are no duplicate objects. For our purpose, we will use this insert() member function:

pair <iterator, bool> insert(const value_type& _Val);

The insert() member function returns a pair, whose bool component returns true if an insertion is made, and false if the set already contains an element whose key had an equivalent value in the ordering, and whose iterator component returns the address where a new element is inserted or where the element is already located.

proof.cpp is written for this purpose, using the STL set container to prove that the permutations generated are unique. You can play around with this, but you should first calculate the number of permutations which would be generated. Too many permutations may take ages to complete (partly due to the working of the set container), or worse, you may run out of memory!

Thanks for your help and mail,sir. First I tried to run your example of char string i.e. n=123456 and r=1234 it runs fine, then I did what you said i.e. I did char [] as float [10] for n and r and then run in output it shows memory address for all pair (same value). Sir can you help me to solve this problem and second thing which I miss to mention in first mail is that I want to convert these code in ANSI C.
Thanking you.

Sir, Thanks for your help. Sir I just saw your part 2 upload, which is what I am looking for.I have implemented my algorithm in matlab which is serial now I want to convert it in c and parallel, and then test on cuda. so now I am understanding your "The Technique of Finding Combination, Given its Index" which you have explained very good, thanks. sir, I have not so far downloaded software and tested it, I will be very grateful to you if you help me to convert it in c language else I need to write my code in c++ which I don't know as I just started learning c language.

Sir, as you said in "A Benchmark Program for your PC" that "The program does not store the combination anywhere and discards them after every computation". If we want to see the combinations after computations, what and where we need to do the change in "TimeCombinations". Thanking you.
Sir, I also not find the source folder for "The Technique for Finding Combinations Without Repetitions" for example "Find Combinations of 3 from a Sequence of 5" with "Optimised Version: Index Combination". sir I will be very grateful if you can send/give idea where can I get it. Thanking you.

Thank you sir,in said folder I found the example by replacing the animal names by integers, it also works for floating numbers. sir I now started working on C++, as I found that more peoples are using it than C.

sir I repeat my first question again here,
Sir, as you said in "A Benchmark Program for your PC" that "The program does not store the combination anywhere and discards them after every computation". If we want to see the combinations after computations, what and where we need to do the change in "TimeCombinations". Thanking you.

sir, can you give more idea on how your code in "TimeCombinations" finds number of processors in cpu (as in my case 4) and split to find for combination for "91". Sir can it be possible if we use one thread in GPU for each combination. Thanking you.

Sir, there is correction in my previous reply, the correction is that in "TimeCombination" we don't find combination for 91, so my question is,on how your code in "TimeCombinations" finds number of processors in cpu (as in my case 4) and split to find on each processor. Sir can it be possible if we use one thread in GPU for each combination. Thanking you.

Sir, thanks for your help and reply, sir sorry I do not understand the meaning of "GPU does not compute arbitrary-sized integers." Sir, can you pls. help me to get the meaning by giving idea of this or tell me where can I get more info of this on net. Sir, does do you have any of your code of combinations for GPU or idea where can we find it. Thanking you.

Arbitrary-sized integers means it can grow larger than 32bit or 64bit to hold a very large integer value. There is no library to compute combination on GPUs as far as I know. I have a way to compute combination on GPU but I have not written the code or the article.

Without going too much into details. Since GPU cannot use arbitrary sized integer, we have to resort to using the biggest integer that the combination need to use by calculating the largest factorial needed. Example, since 10! falls within range of the 32bit integer, there is no need to use a larger integer. If we need a integer larger than 64 bit, we have to define the type ourselves using CUDA PTX assembly to help us detect the carry bit.

sir,Thanks for help and info.This info help me in thinking on how can we do combination on GPU. Sir in one of my early reply I asked one question which I am writing here again " Sir can it be possible if we use one thread in GPU for each combination in "Timecombination" i.e. instead of using only number of processor in CPU. Thanking you.

for(long ab=0;ab<maxx*maxy;++ab)// unwrap a nested for loop(can be 2 for loops)
{
long aa = ab / maxx;
long bb = ab % maxy;
//if(aa<=bb)// if you want same number combinations otherwise use:
if(aa<bb) // limit to the unique half,bb should be of the larger array
{
//printf("%d,%d\n",arrayx[aa],arrayy[bb]);
// don't use printf in openmp (limits to a one cpu)
}
}

The article is very interesting. Actually, couple years ago, I have written my own algorithms for calculating Combinations, Permutations and Factorial in C# using iterative approach rather than recursive for performance reason: iterative solutions in many cases provides several order of magnitude better performance than recursive ones. Corresponding online Combinatorics Calculator, powered by these algorithms, is available at: http://www.webinfocentral.com/MATH/Combinatorics.aspx[^]

I saw the old posts about this issue, but I haven't seen the solution.
I also need the combination of vector elements for unlimited number of vectors. I'm running out of time and you might have coded it already, so I don't have to brainstorm with it..
If you do, I'd really appreciate your help.
Also I'm not really into this topic, need some time to get familiar with.
Thanks.

It doesn't gives you the first combination because the first combination is what you feed into the function to get the next combination and subsequently the rest of the combinations. Therefore you already have the first combination.

You cannot use a vector because you cannot compare a vector with another vector, unless you write a vector comparison function or functor.

I have not tested with CString but it should work with CStrings because CStrings are comparable.

First of all, I really like your article.
There is a question. As we know, any permutation has signature, i. e. -
1,2,3 - signature is 1.
2,1,3 - signature is -1.
Have you ever tried to write next_permutation() like this:
int next_permutation(/*arguments*/) - returns 0 if sequence is sorted, e.g. - 1,2,3; otherwise returns the signature (1 or -1) of the current permutation?
This would be really usefull. For example, in matrix determinant calculation.

Hi Alex, under the section "Code Examples for Finding Index from Permutation" of this article: Permutations in C++, Part 2[^], it is written in response to your question. I hope it is what you are looking for!

I tried your solution and it worked except for one thing. I wanted not to use
"const int N_NUM and const int R_NUM". My idea to input these value at will, but because the compiler is expecting a constant expression, it doesn't compile. Below is something I tried that didn't work. I am showing to give an int of what I want to do.

I declared them as const because to declare the n[] array and r[] array on the stack requires a constant number to tell the compiler how big is the array. If N_NUM and R_NUM is not const, then you have to allocate your arrays dynamically using 'new' but you also must remember to delete them away after use. Allocate your arrays dynamically is good if you do not know how big is your array until the user runs your program.

This really doesn't work for me and I could tell just by looking at it. I ran it to confirm my thoughts and it doesn't work. My objecting is to input all the following without having to explicitly say what they are and what size the array is going to be:

I already told you that you can use std::vector and stdcomb::next_combination(): whenever the user enters a number, you just push back the number into the n vector and before you call next_combination() for the first time, initialise the r vector.

I modified the combinaton code to use numbers instead of letters. It compils and builds successfully. However, the output seems like just a vector address. Can you please tell me what I am doing wrong.
Thanks.

//char_comb_ex.cpp
//This program finds combinations using the recursive method

/*****Instructions*******
To see how it works for other combinations
Try setting N_NUM to other numbers (must not be greater than 10)
Try setting R_NUM to other numbers (must not be greater than N_NUM)
*************************/

I would like to generate all possible combinations using a sequence of vectors, where each vector contains all items that are allowed to stand at a certain place of the combination. For example, from the following input:

{ A } { A, B, C } { C } { D } { E, F }

I would like to get the following 5-item combinations:

AACDE
AACDF
ABCDE
ABCDF
ACCDE
ACCDF

I use std::vector<std::vector<ITEM>> to represent the input, where ITEM is a class representing A, B, C, D, E or F. The result should also come as std::vector<std::vector<ITEM>>.

It looks like I might achieve the above result using your algorithm, but does it support variable counts/sets of allowed items at individual positions?