A composition of an integer v
is a set of K integers such that their sum is v
(and order matters). For instance the 3-sized compositions of 2 are:
2 0 0
1 1 0
1 0 1
0 2 0
0 1 1
0 0 2
A simple C++ algorithm to obtains these compositions can be found here:
void print(std::vector<int>& a) {
std::ostream_iterator<int> i(std::cout, " ");
std::copy(a.begin(), a.end(), i);
std::cout << "\n";
}
void recurse(std::vector<int>& a, int pos, int remaining) {
if (remaining == 0) { print(a); return; }
if (pos == a.size()) { return; }
for (int i = remaining; i >= 0; --i) {
a[pos] = i;
recurse(a, pos + 1, remaining - i);
}
}
int main() {
int v = 2, k = 3;
std::vector<int> a(k);
recurse(a, 0, v);
return 0;
}
But I need something a bit more complex:
I need to find the compositions of a integer vector. That is, given a vector v=(v1, v2, v3) I need to find all their individual compositions and then create all possible combinations. If C is a matrix where I put a partition of v1 in the first row, a partition of v2 in the second row, and a partition of v3 in the third row, then the sum of row f
in C gives v[f]
For instance, the vector (1,2) of size F=2, if we set K=2, can be decomposed in:
# all sets of K vectors such that their sum is (1,2)
C_1 = 1,0 C_2 = 1,0 C_3 = 1,0 C_4 = 0,1 C_5 = 0,1 C_6 = 0,1
2,0 1,1 0,2 2,0 1,1 0,2
The goal is to apply some function to each possible C. How can I do it it C++? I don't mind using generators, recursive or iterative algorithms as long as it does de job (as fast as possible).
Python
The implementation in Python is quite nice using recursions, yield
, and the itertools
library
import numpy as np
import itertools
# Generator to yield all K-size compositions of integer n
def findCombiR(n,K):
if K==1:
yield [n]
return
for i in range(0,n+1):
for result in findCombiR(n-i,K-1):
yield [i] + result
# Generator to yield all K-size compositions of a F-length vector
def findCombiR_v(v,K):
out = []
for f in range(0, len(v)):
out.append(findCombiR(v[f],K))
return out
# Main
####################
v = [1,2]
F = len(v)
K = 2
# C stores F composition generators, one for each element in v.
C = findCombiR_v(v,K)
#"product" combines all possible outputs of the F generators
for c in itertools.product(*C):
c = np.reshape(c, (F,K))
print(c, '\n')