package Sequenic.T2.Engines; import java.math.BigInteger; /** * The CombinationGenerator by Michael Gilleland. See * http://www.merriampark.com/comb.htm . * *

This implements a generator producing all combinations of n elements, * taken r at a time. The algorithm is described by Kenneth H. Rosen, in * Discrete Mathematics and Its Applications, 2nd edition, McGraw-Hill, 1991, * pp. 284-286. * *

A "combination" of r elements from a set V of n (distinct) items is a * subset of V with r number of elements. Note that a combination is therefore * unordered. * * @author Michael Gilleland, adapted by Wishnu Prasetya */ public class CombinationGenerator extends AbstractCombinationGenerator { private int[] a; private int n; private int r; private BigInteger numLeft; private BigInteger total; /** * Create a generator that would generate all combinations of r elements * out of a set V of n distinct elements. The set V will be represented by * indices 0..n-1. */ public CombinationGenerator (int n, int r) { if (r > n) { throw new IllegalArgumentException (); } if (n < 1) { throw new IllegalArgumentException (); } this.n = n; this.r = r; a = new int[r]; BigInteger nFact = getFactorial (n); BigInteger rFact = getFactorial (r); BigInteger nminusrFact = getFactorial (n - r); total = nFact.divide (rFact.multiply (nminusrFact)); reset (); } public void reset () { for (int i = 0; i < a.length; i++) { a[i] = i; } numLeft = new BigInteger (total.toString ()); } /** * Return number of combinations not yet generated. */ public BigInteger getNumLeft () { return numLeft; } /** * Are there more combinations? */ public boolean hasMore () { return numLeft.compareTo (BigInteger.ZERO) == 1; } /** * Return total number of combinations. */ public BigInteger getTotal () { return total; } //------------------ // Compute factorial //------------------ private static BigInteger getFactorial (int n) { BigInteger fact = BigInteger.ONE; for (int i = n; i > 1; i--) { fact = fact.multiply (new BigInteger (Integer.toString (i))); } return fact; } /** * Give the next combination (algorithm from Rosen p. 286). * @return */ public int[] getNext () { if (numLeft.equals (total)) { numLeft = numLeft.subtract (BigInteger.ONE); return a; } int i = r - 1; while (a[i] == n - r + i) { i--; } a[i] = a[i] + 1; for (int j = i + 1; j < r; j++) { a[j] = a[i] + j - i; } numLeft = numLeft.subtract (BigInteger.ONE); return a; } }