001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.math3.util;
018
019import java.util.Iterator;
020import java.util.concurrent.atomic.AtomicReference;
021
022import org.apache.commons.math3.exception.MathArithmeticException;
023import org.apache.commons.math3.exception.NotPositiveException;
024import org.apache.commons.math3.exception.NumberIsTooLargeException;
025import org.apache.commons.math3.exception.util.LocalizedFormats;
026
027/**
028 * Combinatorial utilities.
029 *
030 * @since 3.3
031 */
032public final class CombinatoricsUtils {
033
034    /** All long-representable factorials */
035    static final long[] FACTORIALS = new long[] {
036                       1l,                  1l,                   2l,
037                       6l,                 24l,                 120l,
038                     720l,               5040l,               40320l,
039                  362880l,            3628800l,            39916800l,
040               479001600l,         6227020800l,         87178291200l,
041           1307674368000l,     20922789888000l,     355687428096000l,
042        6402373705728000l, 121645100408832000l, 2432902008176640000l };
043
044    /** Stirling numbers of the second kind. */
045    static final AtomicReference<long[][]> STIRLING_S2 = new AtomicReference<long[][]> (null);
046
047    /** Private constructor (class contains only static methods). */
048    private CombinatoricsUtils() {}
049
050
051    /**
052     * Returns an exact representation of the <a
053     * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
054     * Coefficient</a>, "{@code n choose k}", the number of
055     * {@code k}-element subsets that can be selected from an
056     * {@code n}-element set.
057     * <p>
058     * <Strong>Preconditions</strong>:
059     * <ul>
060     * <li> {@code 0 <= k <= n } (otherwise
061     * {@code MathIllegalArgumentException} is thrown)</li>
062     * <li> The result is small enough to fit into a {@code long}. The
063     * largest value of {@code n} for which all coefficients are
064     * {@code  < Long.MAX_VALUE} is 66. If the computed value exceeds
065     * {@code Long.MAX_VALUE} a {@code MathArithMeticException} is
066     * thrown.</li>
067     * </ul></p>
068     *
069     * @param n the size of the set
070     * @param k the size of the subsets to be counted
071     * @return {@code n choose k}
072     * @throws NotPositiveException if {@code n < 0}.
073     * @throws NumberIsTooLargeException if {@code k > n}.
074     * @throws MathArithmeticException if the result is too large to be
075     * represented by a long integer.
076     */
077    public static long binomialCoefficient(final int n, final int k)
078        throws NotPositiveException, NumberIsTooLargeException, MathArithmeticException {
079        CombinatoricsUtils.checkBinomial(n, k);
080        if ((n == k) || (k == 0)) {
081            return 1;
082        }
083        if ((k == 1) || (k == n - 1)) {
084            return n;
085        }
086        // Use symmetry for large k
087        if (k > n / 2) {
088            return binomialCoefficient(n, n - k);
089        }
090
091        // We use the formula
092        // (n choose k) = n! / (n-k)! / k!
093        // (n choose k) == ((n-k+1)*...*n) / (1*...*k)
094        // which could be written
095        // (n choose k) == (n-1 choose k-1) * n / k
096        long result = 1;
097        if (n <= 61) {
098            // For n <= 61, the naive implementation cannot overflow.
099            int i = n - k + 1;
100            for (int j = 1; j <= k; j++) {
101                result = result * i / j;
102                i++;
103            }
104        } else if (n <= 66) {
105            // For n > 61 but n <= 66, the result cannot overflow,
106            // but we must take care not to overflow intermediate values.
107            int i = n - k + 1;
108            for (int j = 1; j <= k; j++) {
109                // We know that (result * i) is divisible by j,
110                // but (result * i) may overflow, so we split j:
111                // Filter out the gcd, d, so j/d and i/d are integer.
112                // result is divisible by (j/d) because (j/d)
113                // is relative prime to (i/d) and is a divisor of
114                // result * (i/d).
115                final long d = ArithmeticUtils.gcd(i, j);
116                result = (result / (j / d)) * (i / d);
117                i++;
118            }
119        } else {
120            // For n > 66, a result overflow might occur, so we check
121            // the multiplication, taking care to not overflow
122            // unnecessary.
123            int i = n - k + 1;
124            for (int j = 1; j <= k; j++) {
125                final long d = ArithmeticUtils.gcd(i, j);
126                result = ArithmeticUtils.mulAndCheck(result / (j / d), i / d);
127                i++;
128            }
129        }
130        return result;
131    }
132
133    /**
134     * Returns a {@code double} representation of the <a
135     * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
136     * Coefficient</a>, "{@code n choose k}", the number of
137     * {@code k}-element subsets that can be selected from an
138     * {@code n}-element set.
139     * <p>
140     * <Strong>Preconditions</strong>:
141     * <ul>
142     * <li> {@code 0 <= k <= n } (otherwise
143     * {@code IllegalArgumentException} is thrown)</li>
144     * <li> The result is small enough to fit into a {@code double}. The
145     * largest value of {@code n} for which all coefficients are less than
146     * Double.MAX_VALUE is 1029. If the computed value exceeds Double.MAX_VALUE,
147     * Double.POSITIVE_INFINITY is returned</li>
148     * </ul></p>
149     *
150     * @param n the size of the set
151     * @param k the size of the subsets to be counted
152     * @return {@code n choose k}
153     * @throws NotPositiveException if {@code n < 0}.
154     * @throws NumberIsTooLargeException if {@code k > n}.
155     * @throws MathArithmeticException if the result is too large to be
156     * represented by a long integer.
157     */
158    public static double binomialCoefficientDouble(final int n, final int k)
159        throws NotPositiveException, NumberIsTooLargeException, MathArithmeticException {
160        CombinatoricsUtils.checkBinomial(n, k);
161        if ((n == k) || (k == 0)) {
162            return 1d;
163        }
164        if ((k == 1) || (k == n - 1)) {
165            return n;
166        }
167        if (k > n/2) {
168            return binomialCoefficientDouble(n, n - k);
169        }
170        if (n < 67) {
171            return binomialCoefficient(n,k);
172        }
173
174        double result = 1d;
175        for (int i = 1; i <= k; i++) {
176             result *= (double)(n - k + i) / (double)i;
177        }
178
179        return FastMath.floor(result + 0.5);
180    }
181
182    /**
183     * Returns the natural {@code log} of the <a
184     * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
185     * Coefficient</a>, "{@code n choose k}", the number of
186     * {@code k}-element subsets that can be selected from an
187     * {@code n}-element set.
188     * <p>
189     * <Strong>Preconditions</strong>:
190     * <ul>
191     * <li> {@code 0 <= k <= n } (otherwise
192     * {@code MathIllegalArgumentException} is thrown)</li>
193     * </ul></p>
194     *
195     * @param n the size of the set
196     * @param k the size of the subsets to be counted
197     * @return {@code n choose k}
198     * @throws NotPositiveException if {@code n < 0}.
199     * @throws NumberIsTooLargeException if {@code k > n}.
200     * @throws MathArithmeticException if the result is too large to be
201     * represented by a long integer.
202     */
203    public static double binomialCoefficientLog(final int n, final int k)
204        throws NotPositiveException, NumberIsTooLargeException, MathArithmeticException {
205        CombinatoricsUtils.checkBinomial(n, k);
206        if ((n == k) || (k == 0)) {
207            return 0;
208        }
209        if ((k == 1) || (k == n - 1)) {
210            return FastMath.log(n);
211        }
212
213        /*
214         * For values small enough to do exact integer computation,
215         * return the log of the exact value
216         */
217        if (n < 67) {
218            return FastMath.log(binomialCoefficient(n,k));
219        }
220
221        /*
222         * Return the log of binomialCoefficientDouble for values that will not
223         * overflow binomialCoefficientDouble
224         */
225        if (n < 1030) {
226            return FastMath.log(binomialCoefficientDouble(n, k));
227        }
228
229        if (k > n / 2) {
230            return binomialCoefficientLog(n, n - k);
231        }
232
233        /*
234         * Sum logs for values that could overflow
235         */
236        double logSum = 0;
237
238        // n!/(n-k)!
239        for (int i = n - k + 1; i <= n; i++) {
240            logSum += FastMath.log(i);
241        }
242
243        // divide by k!
244        for (int i = 2; i <= k; i++) {
245            logSum -= FastMath.log(i);
246        }
247
248        return logSum;
249    }
250
251    /**
252     * Returns n!. Shorthand for {@code n} <a
253     * href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the
254     * product of the numbers {@code 1,...,n}.
255     * <p>
256     * <Strong>Preconditions</strong>:
257     * <ul>
258     * <li> {@code n >= 0} (otherwise
259     * {@code MathIllegalArgumentException} is thrown)</li>
260     * <li> The result is small enough to fit into a {@code long}. The
261     * largest value of {@code n} for which {@code n!} does not exceed
262     * Long.MAX_VALUE} is 20. If the computed value exceeds {@code Long.MAX_VALUE}
263     * an {@code MathArithMeticException } is thrown.</li>
264     * </ul>
265     * </p>
266     *
267     * @param n argument
268     * @return {@code n!}
269     * @throws MathArithmeticException if the result is too large to be represented
270     * by a {@code long}.
271     * @throws NotPositiveException if {@code n < 0}.
272     * @throws MathArithmeticException if {@code n > 20}: The factorial value is too
273     * large to fit in a {@code long}.
274     */
275    public static long factorial(final int n) throws NotPositiveException, MathArithmeticException {
276        if (n < 0) {
277            throw new NotPositiveException(LocalizedFormats.FACTORIAL_NEGATIVE_PARAMETER,
278                                           n);
279        }
280        if (n > 20) {
281            throw new MathArithmeticException();
282        }
283        return FACTORIALS[n];
284    }
285
286    /**
287     * Compute n!, the<a href="http://mathworld.wolfram.com/Factorial.html">
288     * factorial</a> of {@code n} (the product of the numbers 1 to n), as a
289     * {@code double}.
290     * The result should be small enough to fit into a {@code double}: The
291     * largest {@code n} for which {@code n!} does not exceed
292     * {@code Double.MAX_VALUE} is 170. If the computed value exceeds
293     * {@code Double.MAX_VALUE}, {@code Double.POSITIVE_INFINITY} is returned.
294     *
295     * @param n Argument.
296     * @return {@code n!}
297     * @throws NotPositiveException if {@code n < 0}.
298     */
299    public static double factorialDouble(final int n) throws NotPositiveException {
300        if (n < 0) {
301            throw new NotPositiveException(LocalizedFormats.FACTORIAL_NEGATIVE_PARAMETER,
302                                           n);
303        }
304        if (n < 21) {
305            return FACTORIALS[n];
306        }
307        return FastMath.floor(FastMath.exp(CombinatoricsUtils.factorialLog(n)) + 0.5);
308    }
309
310    /**
311     * Compute the natural logarithm of the factorial of {@code n}.
312     *
313     * @param n Argument.
314     * @return {@code n!}
315     * @throws NotPositiveException if {@code n < 0}.
316     */
317    public static double factorialLog(final int n) throws NotPositiveException {
318        if (n < 0) {
319            throw new NotPositiveException(LocalizedFormats.FACTORIAL_NEGATIVE_PARAMETER,
320                                           n);
321        }
322        if (n < 21) {
323            return FastMath.log(FACTORIALS[n]);
324        }
325        double logSum = 0;
326        for (int i = 2; i <= n; i++) {
327            logSum += FastMath.log(i);
328        }
329        return logSum;
330    }
331
332    /**
333     * Returns the <a
334     * href="http://mathworld.wolfram.com/StirlingNumberoftheSecondKind.html">
335     * Stirling number of the second kind</a>, "{@code S(n,k)}", the number of
336     * ways of partitioning an {@code n}-element set into {@code k} non-empty
337     * subsets.
338     * <p>
339     * The preconditions are {@code 0 <= k <= n } (otherwise
340     * {@code NotPositiveException} is thrown)
341     * </p>
342     * @param n the size of the set
343     * @param k the number of non-empty subsets
344     * @return {@code S(n,k)}
345     * @throws NotPositiveException if {@code k < 0}.
346     * @throws NumberIsTooLargeException if {@code k > n}.
347     * @throws MathArithmeticException if some overflow happens, typically for n exceeding 25 and
348     * k between 20 and n-2 (S(n,n-1) is handled specifically and does not overflow)
349     * @since 3.1
350     */
351    public static long stirlingS2(final int n, final int k)
352        throws NotPositiveException, NumberIsTooLargeException, MathArithmeticException {
353        if (k < 0) {
354            throw new NotPositiveException(k);
355        }
356        if (k > n) {
357            throw new NumberIsTooLargeException(k, n, true);
358        }
359
360        long[][] stirlingS2 = STIRLING_S2.get();
361
362        if (stirlingS2 == null) {
363            // the cache has never been initialized, compute the first numbers
364            // by direct recurrence relation
365
366            // as S(26,9) = 11201516780955125625 is larger than Long.MAX_VALUE
367            // we must stop computation at row 26
368            final int maxIndex = 26;
369            stirlingS2 = new long[maxIndex][];
370            stirlingS2[0] = new long[] { 1l };
371            for (int i = 1; i < stirlingS2.length; ++i) {
372                stirlingS2[i] = new long[i + 1];
373                stirlingS2[i][0] = 0;
374                stirlingS2[i][1] = 1;
375                stirlingS2[i][i] = 1;
376                for (int j = 2; j < i; ++j) {
377                    stirlingS2[i][j] = j * stirlingS2[i - 1][j] + stirlingS2[i - 1][j - 1];
378                }
379            }
380
381            // atomically save the cache
382            STIRLING_S2.compareAndSet(null, stirlingS2);
383
384        }
385
386        if (n < stirlingS2.length) {
387            // the number is in the small cache
388            return stirlingS2[n][k];
389        } else {
390            // use explicit formula to compute the number without caching it
391            if (k == 0) {
392                return 0;
393            } else if (k == 1 || k == n) {
394                return 1;
395            } else if (k == 2) {
396                return (1l << (n - 1)) - 1l;
397            } else if (k == n - 1) {
398                return binomialCoefficient(n, 2);
399            } else {
400                // definition formula: note that this may trigger some overflow
401                long sum = 0;
402                long sign = ((k & 0x1) == 0) ? 1 : -1;
403                for (int j = 1; j <= k; ++j) {
404                    sign = -sign;
405                    sum += sign * binomialCoefficient(k, j) * ArithmeticUtils.pow(j, n);
406                    if (sum < 0) {
407                        // there was an overflow somewhere
408                        throw new MathArithmeticException(LocalizedFormats.ARGUMENT_OUTSIDE_DOMAIN,
409                                                          n, 0, stirlingS2.length - 1);
410                    }
411                }
412                return sum / factorial(k);
413            }
414        }
415
416    }
417
418    /**
419     * Returns an iterator whose range is the k-element subsets of {0, ..., n - 1}
420     * represented as {@code int[]} arrays.
421     * <p>
422     * The arrays returned by the iterator are sorted in descending order and
423     * they are visited in lexicographic order with significance from right to
424     * left. For example, combinationsIterator(4, 2) returns an Iterator that
425     * will generate the following sequence of arrays on successive calls to
426     * {@code next()}:</p><p>
427     * {@code [0, 1], [0, 2], [1, 2], [0, 3], [1, 3], [2, 3]}
428     * </p><p>
429     * If {@code k == 0} an Iterator containing an empty array is returned and
430     * if {@code k == n} an Iterator containing [0, ..., n -1] is returned.</p>
431     *
432     * @param n Size of the set from which subsets are selected.
433     * @param k Size of the subsets to be enumerated.
434     * @return an {@link Iterator iterator} over the k-sets in n.
435     * @throws NotPositiveException if {@code n < 0}.
436     * @throws NumberIsTooLargeException if {@code k > n}.
437     */
438    public static Iterator<int[]> combinationsIterator(int n, int k) {
439        return new Combinations(n, k).iterator();
440    }
441
442    /**
443     * Check binomial preconditions.
444     *
445     * @param n Size of the set.
446     * @param k Size of the subsets to be counted.
447     * @throws NotPositiveException if {@code n < 0}.
448     * @throws NumberIsTooLargeException if {@code k > n}.
449     */
450    public static void checkBinomial(final int n,
451                                     final int k)
452        throws NumberIsTooLargeException,
453               NotPositiveException {
454        if (n < k) {
455            throw new NumberIsTooLargeException(LocalizedFormats.BINOMIAL_INVALID_PARAMETERS_ORDER,
456                                                k, n, true);
457        }
458        if (n < 0) {
459            throw new NotPositiveException(LocalizedFormats.BINOMIAL_NEGATIVE_PARAMETER, n);
460        }
461    }
462}