1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /*
19 * This is not the original file distributed by the Apache Software Foundation
20 * It has been modified by the Hipparchus project
21 */
22 package org.hipparchus.util;
23
24 import java.lang.reflect.Array;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Spliterator;
28 import java.util.Spliterators;
29 import java.util.concurrent.atomic.AtomicReference;
30 import java.util.stream.Stream;
31 import java.util.stream.StreamSupport;
32
33 import org.hipparchus.exception.LocalizedCoreFormats;
34 import org.hipparchus.exception.MathIllegalArgumentException;
35 import org.hipparchus.exception.MathRuntimeException;
36 import org.hipparchus.special.Gamma;
37
38 /**
39 * Combinatorial utilities.
40 */
41 public final class CombinatoricsUtils {
42
43 /** Maximum index of Bell number that fits into a long.
44 * @since 2.2
45 */
46 public static final int MAX_BELL = 25;
47
48 /** All long-representable factorials */
49 static final long[] FACTORIALS = {
50 1l, 1l, 2l,
51 6l, 24l, 120l,
52 720l, 5040l, 40320l,
53 362880l, 3628800l, 39916800l,
54 479001600l, 6227020800l, 87178291200l,
55 1307674368000l, 20922789888000l, 355687428096000l,
56 6402373705728000l, 121645100408832000l, 2432902008176640000l };
57
58 /** Stirling numbers of the second kind. */
59 static final AtomicReference<long[][]> STIRLING_S2 = new AtomicReference<> (null);
60
61 /**
62 * Default implementation of {@link #factorialLog(int)} method:
63 * <ul>
64 * <li>No pre-computation</li>
65 * <li>No cache allocation</li>
66 * </ul>
67 */
68 private static final FactorialLog FACTORIAL_LOG_NO_CACHE = FactorialLog.create();
69
70 /** Bell numbers.
71 * @since 2.2
72 */
73 private static final AtomicReference<long[]> BELL = new AtomicReference<> (null);
74
75 /** Private constructor (class contains only static methods). */
76 private CombinatoricsUtils() {}
77
78
79 /**
80 * Returns an exact representation of the <a
81 * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
82 * Coefficient</a>, "{@code n choose k}", the number of
83 * {@code k}-element subsets that can be selected from an
84 * {@code n}-element set.
85 * <p><Strong>Preconditions</strong>:</p>
86 * <ul>
87 * <li> {@code 0 <= k <= n } (otherwise
88 * {@code MathIllegalArgumentException} is thrown)</li>
89 * <li> The result is small enough to fit into a {@code long}. The
90 * largest value of {@code n} for which all coefficients are
91 * {@code < Long.MAX_VALUE} is 66. If the computed value exceeds
92 * {@code Long.MAX_VALUE} a {@code MathRuntimeException} is
93 * thrown.</li>
94 * </ul>
95 *
96 * @param n the size of the set
97 * @param k the size of the subsets to be counted
98 * @return {@code n choose k}
99 * @throws MathIllegalArgumentException if {@code n < 0}.
100 * @throws MathIllegalArgumentException if {@code k > n}.
101 * @throws MathRuntimeException if the result is too large to be
102 * represented by a long integer.
103 */
104 public static long binomialCoefficient(final int n, final int k)
105 throws MathIllegalArgumentException, MathRuntimeException {
106 CombinatoricsUtils.checkBinomial(n, k);
107 if ((n == k) || (k == 0)) {
108 return 1;
109 }
110 if ((k == 1) || (k == n - 1)) {
111 return n;
112 }
113 // Use symmetry for large k
114 if (k > n / 2) {
115 return binomialCoefficient(n, n - k);
116 }
117
118 // We use the formula
119 // (n choose k) = n! / (n-k)! / k!
120 // (n choose k) == ((n-k+1)*...*n) / (1*...*k)
121 // which could be written
122 // (n choose k) == (n-1 choose k-1) * n / k
123 long result = 1;
124 if (n <= 61) {
125 // For n <= 61, the naive implementation cannot overflow.
126 int i = n - k + 1;
127 for (int j = 1; j <= k; j++) {
128 result = result * i / j;
129 i++;
130 }
131 } else if (n <= 66) {
132 // For n > 61 but n <= 66, the result cannot overflow,
133 // but we must take care not to overflow intermediate values.
134 int i = n - k + 1;
135 for (int j = 1; j <= k; j++) {
136 // We know that (result * i) is divisible by j,
137 // but (result * i) may overflow, so we split j:
138 // Filter out the gcd, d, so j/d and i/d are integer.
139 // result is divisible by (j/d) because (j/d)
140 // is relative prime to (i/d) and is a divisor of
141 // result * (i/d).
142 final long d = ArithmeticUtils.gcd(i, j);
143 result = (result / (j / d)) * (i / d);
144 i++;
145 }
146 } else {
147 // For n > 66, a result overflow might occur, so we check
148 // the multiplication, taking care to not overflow
149 // unnecessary.
150 int i = n - k + 1;
151 for (int j = 1; j <= k; j++) {
152 final long d = ArithmeticUtils.gcd(i, j);
153 result = ArithmeticUtils.mulAndCheck(result / (j / d), i / d);
154 i++;
155 }
156 }
157 return result;
158 }
159
160 /**
161 * Returns a {@code double} representation of the <a
162 * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
163 * Coefficient</a>, "{@code n choose k}", the number of
164 * {@code k}-element subsets that can be selected from an
165 * {@code n}-element set.
166 * <p>* <Strong>Preconditions</strong>:</p>
167 * <ul>
168 * <li> {@code 0 <= k <= n } (otherwise
169 * {@code IllegalArgumentException} is thrown)</li>
170 * <li> The result is small enough to fit into a {@code double}. The
171 * largest value of {@code n} for which all coefficients are <
172 * Double.MAX_VALUE is 1029. If the computed value exceeds Double.MAX_VALUE,
173 * Double.POSITIVE_INFINITY is returned</li>
174 * </ul>
175 *
176 * @param n the size of the set
177 * @param k the size of the subsets to be counted
178 * @return {@code n choose k}
179 * @throws MathIllegalArgumentException if {@code n < 0}.
180 * @throws MathIllegalArgumentException if {@code k > n}.
181 * @throws MathRuntimeException if the result is too large to be
182 * represented by a long integer.
183 */
184 public static double binomialCoefficientDouble(final int n, final int k)
185 throws MathIllegalArgumentException, MathRuntimeException {
186 CombinatoricsUtils.checkBinomial(n, k);
187 if ((n == k) || (k == 0)) {
188 return 1d;
189 }
190 if ((k == 1) || (k == n - 1)) {
191 return n;
192 }
193 if (k > n/2) {
194 return binomialCoefficientDouble(n, n - k);
195 }
196 if (n < 67) {
197 return binomialCoefficient(n,k);
198 }
199
200 double result = 1d;
201 for (int i = 1; i <= k; i++) {
202 result *= (double)(n - k + i) / (double)i;
203 }
204
205 return FastMath.floor(result + 0.5);
206 }
207
208 /**
209 * Returns the natural {@code log} of the <a
210 * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
211 * Coefficient</a>, "{@code n choose k}", the number of
212 * {@code k}-element subsets that can be selected from an
213 * {@code n}-element set.
214 * <p>* <Strong>Preconditions</strong>:</p>
215 * <ul>
216 * <li> {@code 0 <= k <= n } (otherwise
217 * {@code MathIllegalArgumentException} is thrown)</li>
218 * </ul>
219 *
220 * @param n the size of the set
221 * @param k the size of the subsets to be counted
222 * @return {@code n choose k}
223 * @throws MathIllegalArgumentException if {@code n < 0}.
224 * @throws MathIllegalArgumentException if {@code k > n}.
225 * @throws MathRuntimeException if the result is too large to be
226 * represented by a long integer.
227 */
228 public static double binomialCoefficientLog(final int n, final int k)
229 throws MathIllegalArgumentException, MathRuntimeException {
230 CombinatoricsUtils.checkBinomial(n, k);
231 if ((n == k) || (k == 0)) {
232 return 0;
233 }
234 if ((k == 1) || (k == n - 1)) {
235 return FastMath.log(n);
236 }
237
238 /*
239 * For values small enough to do exact integer computation,
240 * return the log of the exact value
241 */
242 if (n < 67) {
243 return FastMath.log(binomialCoefficient(n,k));
244 }
245
246 /*
247 * Return the log of binomialCoefficientDouble for values that will not
248 * overflow binomialCoefficientDouble
249 */
250 if (n < 1030) {
251 return FastMath.log(binomialCoefficientDouble(n, k));
252 }
253
254 if (k > n / 2) {
255 return binomialCoefficientLog(n, n - k);
256 }
257
258 /*
259 * Sum logs for values that could overflow
260 */
261 double logSum = 0;
262
263 // n!/(n-k)!
264 for (int i = n - k + 1; i <= n; i++) {
265 logSum += FastMath.log(i);
266 }
267
268 // divide by k!
269 for (int i = 2; i <= k; i++) {
270 logSum -= FastMath.log(i);
271 }
272
273 return logSum;
274 }
275
276 /**
277 * Returns n!. Shorthand for {@code n} <a
278 * href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the
279 * product of the numbers {@code 1,...,n}.
280 * <p>* <Strong>Preconditions</strong>:</p>
281 * <ul>
282 * <li> {@code n >= 0} (otherwise
283 * {@code MathIllegalArgumentException} is thrown)</li>
284 * <li> The result is small enough to fit into a {@code long}. The
285 * largest value of {@code n} for which {@code n!} does not exceed
286 * Long.MAX_VALUE} is 20. If the computed value exceeds {@code Long.MAX_VALUE}
287 * an {@code MathRuntimeException } is thrown.</li>
288 * </ul>
289 *
290 * @param n argument
291 * @return {@code n!}
292 * @throws MathRuntimeException if the result is too large to be represented
293 * by a {@code long}.
294 * @throws MathIllegalArgumentException if {@code n < 0}.
295 * @throws MathIllegalArgumentException if {@code n > 20}: The factorial value is too
296 * large to fit in a {@code long}.
297 */
298 public static long factorial(final int n) throws MathIllegalArgumentException {
299 if (n < 0) {
300 throw new MathIllegalArgumentException(LocalizedCoreFormats.FACTORIAL_NEGATIVE_PARAMETER, n);
301 }
302 if (n > 20) {
303 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE, n, 20);
304 }
305 return FACTORIALS[n];
306 }
307
308 /**
309 * Compute n!, the<a href="http://mathworld.wolfram.com/Factorial.html">
310 * factorial</a> of {@code n} (the product of the numbers 1 to n), as a
311 * {@code double}.
312 * The result should be small enough to fit into a {@code double}: The
313 * largest {@code n} for which {@code n!} does not exceed
314 * {@code Double.MAX_VALUE} is 170. If the computed value exceeds
315 * {@code Double.MAX_VALUE}, {@code Double.POSITIVE_INFINITY} is returned.
316 *
317 * @param n Argument.
318 * @return {@code n!}
319 * @throws MathIllegalArgumentException if {@code n < 0}.
320 */
321 public static double factorialDouble(final int n) throws MathIllegalArgumentException {
322 if (n < 0) {
323 throw new MathIllegalArgumentException(LocalizedCoreFormats.FACTORIAL_NEGATIVE_PARAMETER,
324 n);
325 }
326 if (n < 21) {
327 return FACTORIALS[n];
328 }
329 return FastMath.floor(FastMath.exp(CombinatoricsUtils.factorialLog(n)) + 0.5);
330 }
331
332 /**
333 * Compute the natural logarithm of the factorial of {@code n}.
334 *
335 * @param n Argument.
336 * @return {@code log(n!)}
337 * @throws MathIllegalArgumentException if {@code n < 0}.
338 */
339 public static double factorialLog(final int n) throws MathIllegalArgumentException {
340 return FACTORIAL_LOG_NO_CACHE.value(n);
341 }
342
343 /**
344 * Returns the <a
345 * href="http://mathworld.wolfram.com/StirlingNumberoftheSecondKind.html">
346 * Stirling number of the second kind</a>, "{@code S(n,k)}", the number of
347 * ways of partitioning an {@code n}-element set into {@code k} non-empty
348 * subsets.
349 * <p>
350 * The preconditions are {@code 0 <= k <= n } (otherwise
351 * {@code MathIllegalArgumentException} is thrown)
352 * </p>
353 * @param n the size of the set
354 * @param k the number of non-empty subsets
355 * @return {@code S(n,k)}
356 * @throws MathIllegalArgumentException if {@code k < 0}.
357 * @throws MathIllegalArgumentException if {@code k > n}.
358 * @throws MathRuntimeException if some overflow happens, typically for n exceeding 25 and
359 * k between 20 and n-2 (S(n,n-1) is handled specifically and does not overflow)
360 */
361 public static long stirlingS2(final int n, final int k)
362 throws MathIllegalArgumentException, MathRuntimeException {
363 if (k < 0) {
364 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, k, 0);
365 }
366 if (k > n) {
367 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE,
368 k, n);
369 }
370
371 long[][] stirlingS2 = STIRLING_S2.get();
372
373 if (stirlingS2 == null) {
374 // the cache has never been initialized, compute the first numbers
375 // by direct recurrence relation
376
377 // as S(26,9) = 11201516780955125625 is larger than Long.MAX_VALUE
378 // we must stop computation at row 26
379 final int maxIndex = 26;
380 stirlingS2 = new long[maxIndex][];
381 stirlingS2[0] = new long[] { 1l };
382 for (int i = 1; i < stirlingS2.length; ++i) {
383 stirlingS2[i] = new long[i + 1];
384 stirlingS2[i][0] = 0;
385 stirlingS2[i][1] = 1;
386 stirlingS2[i][i] = 1;
387 for (int j = 2; j < i; ++j) {
388 stirlingS2[i][j] = j * stirlingS2[i - 1][j] + stirlingS2[i - 1][j - 1];
389 }
390 }
391
392 // atomically save the cache
393 STIRLING_S2.compareAndSet(null, stirlingS2);
394
395 }
396
397 if (n < stirlingS2.length) {
398 // the number is in the small cache
399 return stirlingS2[n][k];
400 } else {
401 // use explicit formula to compute the number without caching it
402 if (k == 0) {
403 return 0;
404 } else if (k == 1 || k == n) {
405 return 1;
406 } else if (k == 2) {
407 return (1l << (n - 1)) - 1l;
408 } else if (k == n - 1) {
409 return binomialCoefficient(n, 2);
410 } else {
411 // definition formula: note that this may trigger some overflow
412 long sum = 0;
413 long sign = ((k & 0x1) == 0) ? 1 : -1;
414 for (int j = 1; j <= k; ++j) {
415 sign = -sign;
416 sum += sign * binomialCoefficient(k, j) * ArithmeticUtils.pow(j, n);
417 if (sum < 0) {
418 // there was an overflow somewhere
419 throw new MathRuntimeException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
420 n, 0, stirlingS2.length - 1);
421 }
422 }
423 return sum / factorial(k);
424 }
425 }
426
427 }
428
429 /**
430 * Returns an iterator whose range is the k-element subsets of {0, ..., n - 1}
431 * represented as {@code int[]} arrays.
432 * <p>
433 * The arrays returned by the iterator are sorted in descending order and
434 * they are visited in lexicographic order with significance from right to
435 * left. For example, combinationsIterator(4, 2) returns an Iterator that
436 * will generate the following sequence of arrays on successive calls to
437 * {@code next()}:</p><p>
438 * {@code [0, 1], [0, 2], [1, 2], [0, 3], [1, 3], [2, 3]}
439 * </p><p>
440 * If {@code k == 0} an Iterator containing an empty array is returned and
441 * if {@code k == n} an Iterator containing [0, ..., n -1] is returned.</p>
442 *
443 * @param n Size of the set from which subsets are selected.
444 * @param k Size of the subsets to be enumerated.
445 * @return an {@link Iterator iterator} over the k-sets in n.
446 * @throws MathIllegalArgumentException if {@code n < 0}.
447 * @throws MathIllegalArgumentException if {@code k > n}.
448 */
449 public static Iterator<int[]> combinationsIterator(int n, int k) {
450 return new Combinations(n, k).iterator();
451 }
452
453 /**
454 * Check binomial preconditions.
455 *
456 * @param n Size of the set.
457 * @param k Size of the subsets to be counted.
458 * @throws MathIllegalArgumentException if {@code n < 0}.
459 * @throws MathIllegalArgumentException if {@code k > n}.
460 */
461 public static void checkBinomial(final int n,
462 final int k)
463 throws MathIllegalArgumentException {
464 if (n < k) {
465 throw new MathIllegalArgumentException(LocalizedCoreFormats.BINOMIAL_INVALID_PARAMETERS_ORDER,
466 k, n, true);
467 }
468 if (n < 0) {
469 throw new MathIllegalArgumentException(LocalizedCoreFormats.BINOMIAL_NEGATIVE_PARAMETER, n);
470 }
471 }
472
473 /** Compute the Bell number (number of partitions of a set).
474 * @param n number of elements of the set
475 * @return Bell number Bₙ
476 * @since 2.2
477 */
478 public static long bellNumber(final int n) {
479
480 if (n < 0) {
481 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, n, 0);
482 }
483 if (n > MAX_BELL) {
484 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE, n, MAX_BELL);
485 }
486
487 long[] bell = BELL.get();
488
489 if (bell == null) {
490
491 // the cache has never been initialized, compute the numbers using the Bell triangle
492 // storage for one line of the Bell triangle
493 bell = new long[MAX_BELL];
494 bell[0] = 1l;
495
496 final long[] row = new long[bell.length];
497 for (int k = 1; k < row.length; ++k) {
498
499 // first row, with one element
500 row[0] = 1l;
501
502 // iterative computation of rows
503 for (int i = 1; i < k; ++i) {
504 long previous = row[0];
505 row[0] = row[i - 1];
506 for (int j = 1; j <= i; ++j) {
507 long rj = row[j - 1] + previous;
508 previous = row[j];
509 row[j] = rj;
510 }
511 }
512
513 bell[k] = row[k - 1];
514
515 }
516
517 BELL.compareAndSet(null, bell);
518
519 }
520
521 return bell[n];
522
523 }
524
525 /** Generate a stream of partitions of a list.
526 * <p>
527 * This method implements the iterative algorithm described in
528 * <a href="https://academic.oup.com/comjnl/article/32/3/281/331557">Short Note:
529 * A Fast Iterative Algorithm for Generating Set Partitions</a>
530 * by B. Djokić, M. Miyakawa, S. Sekiguchi, I. Semba, and I. Stojmenović
531 * (The Computer Journal, Volume 32, Issue 3, 1989, Pages 281–282,
532 * <a href="https://doi.org/10.1093/comjnl/32.3.281">https://doi.org/10.1093/comjnl/32.3.281</a>
533 * </p>
534 * @param <T> type of the list elements
535 * @param list list to partition
536 * @return stream of partitions of the list, each partition is an array or parts
537 * and each part is a list of elements
538 * @since 2.2
539 */
540 public static <T> Stream<List<T>[]> partitions(final List<T> list) {
541
542 // handle special cases of empty and singleton lists
543 if (list.size() < 2) {
544 @SuppressWarnings("unchecked")
545 final List<T>[] partition = (List<T>[]) Array.newInstance(List.class, 1);
546 partition[0] = list;
547 final Stream.Builder<List<T>[]> builder = Stream.builder();
548 return builder.add(partition).build();
549 }
550
551 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new PartitionsIterator<T>(list),
552 Spliterator.DISTINCT | Spliterator.NONNULL |
553 Spliterator.IMMUTABLE | Spliterator.ORDERED),
554 false);
555
556 }
557
558 /** Generate a stream of permutations of a list.
559 * <p>
560 * This method implements the Steinhaus–Johnson–Trotter algorithm
561 * with Even's speedup
562 * <a href="https://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm">Steinhaus–Johnson–Trotter algorithm</a>
563 * @param <T> type of the list elements
564 * @param list list to permute
565 * @return stream of permutations of the list
566 * @since 2.2
567 */
568 public static <T> Stream<List<T>> permutations(final List<T> list) {
569
570 // handle special cases of empty and singleton lists
571 if (list.size() < 2) {
572 return Stream.of(list);
573 }
574
575 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new PermutationsIterator<T>(list),
576 Spliterator.DISTINCT | Spliterator.NONNULL |
577 Spliterator.IMMUTABLE | Spliterator.ORDERED),
578 false);
579
580 }
581
582 /**
583 * Class for computing the natural logarithm of the factorial of {@code n}.
584 * It allows to allocate a cache of precomputed values.
585 * In case of cache miss, computation is preformed by a call to
586 * {@link Gamma#logGamma(double)}.
587 */
588 public static final class FactorialLog {
589 /**
590 * Precomputed values of the function:
591 * {@code LOG_FACTORIALS[i] = log(i!)}.
592 */
593 private final double[] LOG_FACTORIALS;
594
595 /**
596 * Creates an instance, reusing the already computed values if available.
597 *
598 * @param numValues Number of values of the function to compute.
599 * @param cache Existing cache.
600 * @throw MathIllegalArgumentException if {@code n < 0}.
601 */
602 private FactorialLog(int numValues,
603 double[] cache) {
604 if (numValues < 0) {
605 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_SMALL, numValues, 0);
606 }
607
608 LOG_FACTORIALS = new double[numValues];
609
610 final int beginCopy = 2;
611 final int endCopy = cache == null || cache.length <= beginCopy ?
612 beginCopy : cache.length <= numValues ?
613 cache.length : numValues;
614
615 // Copy available values.
616 for (int i = beginCopy; i < endCopy; i++) {
617 LOG_FACTORIALS[i] = cache[i];
618 }
619
620 // Precompute.
621 for (int i = endCopy; i < numValues; i++) {
622 LOG_FACTORIALS[i] = LOG_FACTORIALS[i - 1] + FastMath.log(i);
623 }
624 }
625
626 /**
627 * Creates an instance with no precomputed values.
628 * @return instance with no precomputed values
629 */
630 public static FactorialLog create() {
631 return new FactorialLog(0, null);
632 }
633
634 /**
635 * Creates an instance with the specified cache size.
636 *
637 * @param cacheSize Number of precomputed values of the function.
638 * @return a new instance where {@code cacheSize} values have been
639 * precomputed.
640 * @throws MathIllegalArgumentException if {@code n < 0}.
641 */
642 public FactorialLog withCache(final int cacheSize) {
643 return new FactorialLog(cacheSize, LOG_FACTORIALS);
644 }
645
646 /**
647 * Computes {@code log(n!)}.
648 *
649 * @param n Argument.
650 * @return {@code log(n!)}.
651 * @throws MathIllegalArgumentException if {@code n < 0}.
652 */
653 public double value(final int n) {
654 if (n < 0) {
655 throw new MathIllegalArgumentException(LocalizedCoreFormats.FACTORIAL_NEGATIVE_PARAMETER,
656 n);
657 }
658
659 // Use cache of precomputed values.
660 if (n < LOG_FACTORIALS.length) {
661 return LOG_FACTORIALS[n];
662 }
663
664 // Use cache of precomputed factorial values.
665 if (n < FACTORIALS.length) {
666 return FastMath.log(FACTORIALS[n]);
667 }
668
669 // Delegate.
670 return Gamma.logGamma(n + 1);
671 }
672 }
673 }