1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.rng.sampling.distribution;
19
20 import org.apache.commons.rng.UniformRandomProvider;
21 import org.apache.commons.rng.sampling.SharedStateSampler;
22
23
24
25
26
27
28 final class InternalUtils {
29
30 private static final long[] FACTORIALS = new long[] {
31 1L, 1L, 2L,
32 6L, 24L, 120L,
33 720L, 5040L, 40320L,
34 362880L, 3628800L, 39916800L,
35 479001600L, 6227020800L, 87178291200L,
36 1307674368000L, 20922789888000L, 355687428096000L,
37 6402373705728000L, 121645100408832000L, 2432902008176640000L };
38
39
40 private static final int BEGIN_LOG_FACTORIALS = 2;
41
42
43 private InternalUtils() {}
44
45
46
47
48
49
50
51 public static long factorial(int n) {
52 return FACTORIALS[n];
53 }
54
55
56
57
58
59
60
61
62
63
64 public static double validateProbabilities(double[] probabilities) {
65 if (probabilities == null || probabilities.length == 0) {
66 throw new IllegalArgumentException("Probabilities must not be empty.");
67 }
68
69 double sumProb = 0;
70 for (final double prob : probabilities) {
71 validateProbability(prob);
72 sumProb += prob;
73 }
74
75 if (Double.isInfinite(sumProb) || sumProb <= 0) {
76 throw new IllegalArgumentException("Invalid sum of probabilities: " + sumProb);
77 }
78 return sumProb;
79 }
80
81
82
83
84
85
86
87 public static void validateProbability(double probability) {
88 if (probability < 0 ||
89 Double.isInfinite(probability) ||
90 Double.isNaN(probability)) {
91 throw new IllegalArgumentException("Invalid probability: " +
92 probability);
93 }
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107 static NormalizedGaussianSampler newNormalizedGaussianSampler(
108 NormalizedGaussianSampler sampler,
109 UniformRandomProvider rng) {
110 if (!(sampler instanceof SharedStateSampler<?>)) {
111 throw new UnsupportedOperationException("The underlying sampler cannot share state");
112 }
113 final Object newSampler = ((SharedStateSampler<?>) sampler).withUniformRandomProvider(rng);
114 if (!(newSampler instanceof NormalizedGaussianSampler)) {
115 throw new UnsupportedOperationException(
116 "The underlying sampler did not create a normalized Gaussian sampler");
117 }
118 return (NormalizedGaussianSampler) newSampler;
119 }
120
121
122
123
124
125
126
127 public static final class FactorialLog {
128
129
130
131
132 private final double[] logFactorials;
133
134
135
136
137
138
139
140
141 private FactorialLog(int numValues,
142 double[] cache) {
143 logFactorials = new double[numValues];
144
145 int endCopy;
146 if (cache != null && cache.length > BEGIN_LOG_FACTORIALS) {
147
148 endCopy = Math.min(cache.length, numValues);
149 System.arraycopy(cache, BEGIN_LOG_FACTORIALS, logFactorials, BEGIN_LOG_FACTORIALS,
150 endCopy - BEGIN_LOG_FACTORIALS);
151 } else {
152
153 endCopy = BEGIN_LOG_FACTORIALS;
154 }
155
156
157 for (int i = endCopy; i < numValues; i++) {
158 if (i < FACTORIALS.length) {
159 logFactorials[i] = Math.log(FACTORIALS[i]);
160 } else {
161 logFactorials[i] = logFactorials[i - 1] + Math.log(i);
162 }
163 }
164 }
165
166
167
168
169
170
171 public static FactorialLog create() {
172 return new FactorialLog(0, null);
173 }
174
175
176
177
178
179
180
181
182
183 public FactorialLog withCache(final int cacheSize) {
184 return new FactorialLog(cacheSize, logFactorials);
185 }
186
187
188
189
190
191
192
193
194 public double value(final int n) {
195
196 if (n < logFactorials.length) {
197 return logFactorials[n];
198 }
199
200
201 if (n < FACTORIALS.length) {
202 return Math.log(FACTORIALS[n]);
203 }
204
205
206 return InternalGamma.logGamma(n + 1.0);
207 }
208 }
209 }