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}