SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
KolmogorovSmirnovDist.java
1/*
2 * Class: KolmogorovSmirnovDist
3 * Description: Kolmogorov-Smirnov distribution
4 * Environment: Java
5 * Software: SSJ
6 * Organization: DIRO, Universite de Montreal
7 * @author
8 * @since
9 *
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 *
23 */
24package umontreal.ssj.probdist;
25
26import umontreal.ssj.util.*;
27import umontreal.ssj.functions.MathFunction;
28
53 protected int n;
54 protected static final int NEXACT = 500;
55
56 // For the Durbin matrix algorithm
57 private static final double NORM = 1.0e140;
58 private static final double INORM = 1.0e-140;
59 private static final int LOGNORM = 140;
60
61 // ========================================================================
62
63 private static class Function implements MathFunction {
64 protected int n;
65 protected double u;
66
67 public Function(int n, double u) {
68 this.n = n;
69 this.u = u;
70 }
71
72 public double evaluate(double x) {
73 return u - cdf(n, x);
74 }
75 }
76
82 public KolmogorovSmirnovDist(int n) {
83 setN(n);
84 }
85
86 public double density(double x) {
87 return density(n, x);
88 }
89
90 public double cdf(double x) {
91 return cdf(n, x);
92 }
93
94 public double barF(double x) {
95 return barF(n, x);
96 }
97
98 public double inverseF(double u) {
99 return inverseF(n, u);
100 }
101
102 private static double dclem(int n, double x, double EPS) {
103 return (cdf(n, x + EPS) - cdf(n, x - EPS)) / (2.0 * EPS);
104 }
105
106 protected static double densConnue(int n, double x) {
107 if ((x >= 1.0) || (x <= 0.5 / n))
108 return 0.0;
109 if (n == 1)
110 return 2.0;
111
112 if (x <= 1.0 / n) {
113 double w;
114 double t = 2.0 * x * n - 1.0;
115 if (n <= NEXACT) {
116 w = 2.0 * n * n * Num.factoPow(n);
117 w *= Math.pow(t, (double) (n - 1));
118 return w;
119 }
120 w = Num.lnFactorial(n) + (n - 1) * Math.log(t / n);
121 return 2 * n * Math.exp(w);
122 }
123
124 if (x >= 1.0 - 1.0 / n)
125 return 2.0 * n * Math.pow(1.0 - x, (double) (n - 1));
126
127 return -1.0;
128 }
129
134 public static double density(int n, double x) {
135 double Res = densConnue(n, x);
136 if (Res != -1.0)
137 return Res;
138
139 double EPS = 1.0 / 200.0;
140 final double D1 = dclem(n, x, EPS);
141 final double D2 = dclem(n, x, 2.0 * EPS);
142 Res = D1 + (D1 - D2) / 3.0;
143 if (Res <= 0.0)
144 return 0.0;
145 return Res;
146 }
147
148 /*
149 * =========================================================================
150 *
151 * The following implements the Durbin matrix algorithm and was programmed in C
152 * by G. Marsaglia, Wai Wan Tsang and Jingbo Wong in C.
153 *
154 * I have translated their program in Java. Only small modifications have been
155 * made in their program; the most important is to prevent the return of NAN or
156 * infinite values in some regions. (Richard Simard)
157 *
158 * =========================================================================
159 */
160
161 /*
162 * The C program to compute Kolmogorov's distribution
163 *
164 * K(n,d) = Prob(D_n < d), where
165 *
166 * D_n = max(x_1-0/n,x_2-1/n...,x_n-(n-1)/n,1/n-x_1,2/n-x_2,...,n/n-x_n)
167 *
168 * with x_1<x_2,...<x_n a purported set of n independent uniform [0,1) random
169 * variables sorted into increasing order. See G. Marsaglia, Wai Wan Tsang and
170 * Jingbo Wong, J.Stat.Software, 8, 18, pp 1--4, (2003).
171 */
172
173 private static void mMultiply(double[] A, double[] B, double[] C, int m) {
174 int i, j, k;
175 double s;
176 for (i = 0; i < m; i++)
177 for (j = 0; j < m; j++) {
178 s = 0.0;
179 for (k = 0; k < m; k++)
180 s += A[i * m + k] * B[k * m + j];
181 C[i * m + j] = s;
182 }
183 }
184
185 private static void renormalize(double[] V, int m, int[] p) {
186 int i;
187 for (i = 0; i < m * m; i++)
188 V[i] *= INORM;
189 p[0] += LOGNORM;
190 }
191
192 private static void mPower(double[] A, int eA, double[] V, int[] eV, int m, int n) {
193 int i;
194 if (n == 1) {
195 for (i = 0; i < m * m; i++)
196 V[i] = A[i];
197 eV[0] = eA;
198 return;
199 }
200 mPower(A, eA, V, eV, m, n / 2);
201
202 double[] B = new double[m * m];
203 int[] pB = new int[1];
204
205 mMultiply(V, V, B, m);
206 pB[0] = 2 * (eV[0]);
207 if (B[(m / 2) * m + (m / 2)] > NORM)
208 renormalize(B, m, pB);
209
210 if (n % 2 == 0) {
211 for (i = 0; i < m * m; i++)
212 V[i] = B[i];
213 eV[0] = pB[0];
214 } else {
215 mMultiply(A, B, V, m);
216 eV[0] = eA + pB[0];
217 }
218
219 if (V[(m / 2) * m + (m / 2)] > NORM)
220 renormalize(V, m, eV);
221 }
222
223 protected static double DurbinMatrix(int n, double d) {
224 int k, m, i, j, g, eH;
225 double h, s;
226 double[] H;
227 double[] Q;
228 int[] pQ;
229
230 // Omit next two lines if you require >7 digit accuracy in the right tail
231 if (false) {
232 s = d * d * n;
233 if (s > 7.24 || (s > 3.76 && n > 99))
234 return 1 - 2 * Math.exp(-(2.000071 + .331 / Math.sqrt(n) + 1.409 / n) * s);
235 }
236 k = (int) (n * d) + 1;
237 m = 2 * k - 1;
238 h = k - n * d;
239 H = new double[m * m];
240 Q = new double[m * m];
241 pQ = new int[1];
242
243 for (i = 0; i < m; i++)
244 for (j = 0; j < m; j++)
245 if (i - j + 1 < 0)
246 H[i * m + j] = 0;
247 else
248 H[i * m + j] = 1;
249 for (i = 0; i < m; i++) {
250 H[i * m] -= Math.pow(h, (double) (i + 1));
251 H[(m - 1) * m + i] -= Math.pow(h, (double) (m - i));
252 }
253 H[(m - 1) * m] += (2 * h - 1 > 0 ? Math.pow(2 * h - 1, (double) m) : 0);
254 for (i = 0; i < m; i++)
255 for (j = 0; j < m; j++)
256 if (i - j + 1 > 0)
257 for (g = 1; g <= i - j + 1; g++)
258 H[i * m + j] /= g;
259 eH = 0;
260 mPower(H, eH, Q, pQ, m, n);
261 s = Q[(k - 1) * m + k - 1];
262
263 for (i = 1; i <= n; i++) {
264 s = s * (double) i / n;
265 if (s < INORM) {
266 s *= NORM;
267 pQ[0] -= LOGNORM;
268 }
269 }
270 s *= Math.pow(10., (double) pQ[0]);
271 return s;
272 }
273
274 protected static double cdfConnu(int n, double x) {
275 // For nx^2 > 18, barF(n, x) is smaller than 5e-16
276 if ((n * x * x >= 18.0) || (x >= 1.0))
277 return 1.0;
278
279 if (x <= 0.5 / n)
280 return 0.0;
281
282 if (n == 1)
283 return 2.0 * x - 1.0;
284
285 if (x <= 1.0 / n) {
286 double w;
287 double t = 2.0 * x * n - 1.0;
288 if (n <= NEXACT) {
289 w = Num.factoPow(n);
290 return w * Math.pow(t, (double) n);
291 }
292 w = Num.lnFactorial(n) + n * Math.log(t / n);
293 return Math.exp(w);
294 }
295
296 if (x >= 1.0 - 1.0 / n) {
297 return 1.0 - 2.0 * Math.pow(1.0 - x, (double) n);
298 }
299
300 return -1.0;
301 }
302
310 public static double cdf(int n, double x) {
311 double Res = cdfConnu(n, x);
312 if (Res != -1.0)
313 return Res;
314
315 return DurbinMatrix(n, x);
316 }
317
318 protected static double barFConnu(int n, double x) {
319 final double w = n * x * x;
320
321 if ((w >= 370.0) || (x >= 1.0))
322 return 0.0;
323 if ((w <= 0.0274) || (x <= 0.5 / n))
324 return 1.0;
325 if (n == 1)
326 return 2.0 - 2.0 * x;
327
328 if (x <= 1.0 / n) {
329 double v;
330 final double t = 2.0 * x * n - 1.0;
331 if (n <= NEXACT) {
332 v = Num.factoPow(n);
333 return 1.0 - v * Math.pow(t, (double) n);
334 }
335 v = Num.lnFactorial(n) + n * Math.log(t / n);
336 return 1.0 - Math.exp(v);
337 }
338
339 if (x >= 1.0 - 1.0 / n) {
340 return 2.0 * Math.pow(1.0 - x, (double) n);
341 }
342
343 return -1.0;
344 }
345
351 public static double barF(int n, double x) {
352 double h = barFConnu(n, x);
353 if (h >= 0.0)
354 return h;
355
356 h = 1.0 - cdf(n, x);
357 if (h >= 0.0)
358 return h;
359 return 0.0;
360 }
361
362 protected static double inverseConnue(int n, double u) {
363 if (n <= 0)
364 throw new IllegalArgumentException("n <= 0");
365 if (u < 0.0 || u > 1.0)
366 throw new IllegalArgumentException("u must be in [0,1]");
367 if (u == 1.0)
368 return 1.0;
369
370 if (u == 0.0)
371 return 0.5 / n;
372
373 if (n == 1)
374 return (u + 1.0) / 2.0;
375
376 final double NLNN = n * Math.log(n);
377 final double LNU = Math.log(u) - Num.lnFactorial(n);
378 if (LNU <= -NLNN) {
379 double t = 1.0 / n * (LNU);
380 return 0.5 * (Math.exp(t) + 1.0 / n);
381 }
382
383 if (u >= 1.0 - 2.0 / Math.exp(NLNN))
384 return 1.0 - Math.pow((1.0 - u) / 2.0, 1.0 / n);
385
386 return -1.0;
387 }
388
393 public static double inverseF(int n, double u) {
394 double Res = inverseConnue(n, u);
395 if (Res != -1.0)
396 return Res;
397 Function f = new Function(n, u);
398 return RootFinder.brentDekker(0.5 / n, 1.0, f, 1e-10);
399 }
400
404 public int getN() {
405 return n;
406 }
407
411 public void setN(int n) {
412 if (n <= 0)
413 throw new IllegalArgumentException("n <= 0");
414 this.n = n;
415 supportA = 0.5 / n;
416 supportB = 1.0;
417 }
418
422 public double[] getParams() {
423 double[] retour = { n };
424 return retour;
425 }
426
430 public String toString() {
431 return getClass().getSimpleName() + " : n = " + n;
432 }
433
434}
Classes implementing continuous distributions should inherit from this base class.
void setN(int n)
Sets the parameter of this object.
static double cdf(int n, double x)
Computes the Kolmogorov–Smirnov distribution function with parameter using Durbin’s matrix formula ...
double[] getParams()
Returns an array containing the parameter of this object.
double cdf(double x)
Returns the distribution function .
static double barF(int n, double x)
Computes the complementary distribution function with parameter .
static double inverseF(int n, double u)
Computes the inverse of the Kolmogorov–Smirnov distribution with parameter .
String toString()
Returns a String containing information about the current distribution.
KolmogorovSmirnovDist(int n)
Constructs a Kolmogorov–Smirnov distribution with parameter.
double inverseF(double u)
Returns the inverse distribution function .
static double density(int n, double x)
Computes the density for the Kolmogorov–Smirnov distribution with parameter .
double barF(double x)
Returns the complementary distribution function.
int getN()
Returns the parameter of this object.
double density(double x)
Returns , the density evaluated at .
This class provides various constants and methods to compute numerical quantities such as factorials,...
Definition Num.java:35
static double factoPow(int n)
Returns the value of .
Definition Num.java:356
static double lnFactorial(int n)
Returns the value of , the natural logarithm of factorial .
Definition Num.java:313
This class provides numerical methods to solve non-linear equations.
static double brentDekker(double a, double b, MathFunction f, double tol)
Computes a root of the function in f using the Brent-Dekker method.
This interface should be implemented by classes which represent univariate mathematical functions.