For a heuristic algorithm I need to evaluate, one after the other, the combinations of a certain set until I reach a stop criterion.
Since they are a lot, at the momen
For the sake of completeness and clarity I'll post my final code:
// Given a pool of elements returns all the
// combinations of the groups of lenght r in pool,
// such that the combinations are ordered (ascending) by the sum of
// the indexes of the elements.
// e.g. pool = {A,B,C,D,E} r = 3
// returns
// (A, B, C) indexes: (0, 1, 2) sum: 3
// (A, B, D) indexes: (0, 1, 3) sum: 4
// (A, B, E) indexes: (0, 1, 4) sum: 5
// (A, C, D) indexes: (0, 2, 3) sum: 5
// (A, C, E) indexes: (0, 2, 4) sum: 6
// (B, C, D) indexes: (1, 2, 3) sum: 6
// (A, D, E) indexes: (0, 3, 4) sum: 7
// (B, C, E) indexes: (1, 2, 4) sum: 7
// (B, D, E) indexes: (1, 3, 4) sum: 8
// (C, D, E) indexes: (2, 3, 4) sum: 9
public static IEnumerable
GetCombinationsSortedByIndexSum(this IList pool, int r)
{
int n = pool.Count;
if (r > n)
throw new ArgumentException("r cannot be greater than pool size");
int minSum = F(r - 1);
int maxSum = F(n) - F(n - r - 1);
for (int sum = minSum; sum <= maxSum; sum++)
{
foreach (var indexes in AllSubSequencesWithGivenSum(0, n - 1, r, sum))
yield return indexes.Select(x => pool[x]).ToArray();
}
}
// Given a start element and a last element of a sequence of consecutive integers
// returns all the monotonically increasing subsequences of length "m" having sum "sum"
// e.g. seqFirstElement = 1, seqLastElement = 5, m = 3, sum = 8
// returns {1,2,5} and {1,3,4}
static IEnumerable>
AllSubSequencesWithGivenSum(int seqFirstElement, int seqLastElement, int m, int sum)
{
int lb = sum - F(seqLastElement) + F(seqLastElement - m + 1);
int ub = sum - F(seqFirstElement + m - 1) + F(seqFirstElement);
lb = Math.Max(seqFirstElement, lb);
ub = Math.Min(seqLastElement - m + 1, ub);
for (int i = lb; i <= ub; i++)
{
if (m == 1)
{
if (i == sum) // this check shouldn't be necessary anymore since LB/UB should automatically exclude wrong solutions
yield return new int[] { i };
}
else
{
foreach (var el in AllSubSequencesWithGivenSum(i + 1, seqLastElement, m - 1, sum - i))
yield return new int[] { i }.Concat(el);
}
}
}
// Formula to compute the sum of the numbers from 0 to n
// e.g. F(4) = 0 + 1 + 2 + 3 + 4 = 10
static int F(int n)
{
return (n * (n + 1)) / 2;
}