source: src/main/java/agents/anac/y2019/harddealer/math3/util/CombinatoricsUtils.java

Last change on this file was 204, checked in by Katsuhide Fujita, 5 years ago

Fixed errors of ANAC2019 agents

  • Property svn:executable set to *
File size: 17.4 KB
Line 
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 * http://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 */
17package agents.anac.y2019.harddealer.math3.util;
18
19import java.util.Iterator;
20import java.util.concurrent.atomic.AtomicReference;
21
22import agents.anac.y2019.harddealer.math3.exception.MathArithmeticException;
23import agents.anac.y2019.harddealer.math3.exception.NotPositiveException;
24import agents.anac.y2019.harddealer.math3.exception.NumberIsTooLargeException;
25import agents.anac.y2019.harddealer.math3.exception.util.LocalizedFormats;
26
27/**
28 * Combinatorial utilities.
29 *
30 * @since 3.3
31 */
32public final class CombinatoricsUtils {
33
34 /** All long-representable factorials */
35 static final long[] FACTORIALS = new long[] {
36 1l, 1l, 2l,
37 6l, 24l, 120l,
38 720l, 5040l, 40320l,
39 362880l, 3628800l, 39916800l,
40 479001600l, 6227020800l, 87178291200l,
41 1307674368000l, 20922789888000l, 355687428096000l,
42 6402373705728000l, 121645100408832000l, 2432902008176640000l };
43
44 /** Stirling numbers of the second kind. */
45 static final AtomicReference<long[][]> STIRLING_S2 = new AtomicReference<long[][]> (null);
46
47 /** Private constructor (class contains only static methods). */
48 private CombinatoricsUtils() {}
49
50
51 /**
52 * Returns an exact representation of the <a
53 * href="http://mathworld.wolfram.com/BinomialCoefficient.html"> Binomial
54 * Coefficient</a>, "{@code n choose k}", the number of
55 * {@code k}-element subsets that can be selected from an
56 * {@code n}-element set.
57 * <p>
58 * <Strong>Preconditions</strong>:
59 * <ul>
60 * <li> {@code 0 <= k <= n } (otherwise
61 * {@code MathIllegalArgumentException} is thrown)</li>
62 * <li> The result is small enough to fit into a {@code long}. The
63 * largest value of {@code n} for which all coefficients are
64 * {@code < Long.MAX_VALUE} is 66. If the computed value exceeds
65 * {@code Long.MAX_VALUE} a {@code MathArithMeticException} is
66 * thrown.</li>
67 * </ul></p>
68 *
69 * @param n the size of the set
70 * @param k the size of the subsets to be counted
71 * @return {@code n choose k}
72 * @throws NotPositiveException if {@code n < 0}.
73 * @throws NumberIsTooLargeException if {@code k > n}.
74 * @throws MathArithmeticException if the result is too large to be
75 * represented by a long integer.
76 */
77 public static long binomialCoefficient(final int n, final int k)
78 throws NotPositiveException, NumberIsTooLargeException, MathArithmeticException {
79 CombinatoricsUtils.checkBinomial(n, k);
80 if ((n == k) || (k == 0)) {
81 return 1;
82 }
83 if ((k == 1) || (k == n - 1)) {
84 return n;
85 }
86 // Use symmetry for large k
87 if (k > n / 2) {
88 return binomialCoefficient(n, n - k);
89 }
90
91 // We use the formula
92 // (n choose k) = n! / (n-k)! / k!
93 // (n choose k) == ((n-k+1)*...*n) / (1*...*k)
94 // which could be written
95 // (n choose k) == (n-1 choose k-1) * n / k
96 long result = 1;
97 if (n <= 61) {
98 // For n <= 61, the naive implementation cannot overflow.
99 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}
Note: See TracBrowser for help on using the repository browser.