SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
KolmogorovSmirnovPlusDist.java
1/*
2 * Class: KolmogorovSmirnovPlusDist
3 * Description: Kolmogorov-Smirnov+ distribution
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.probdist;
26
27import umontreal.ssj.util.*;
28import umontreal.ssj.functions.MathFunction;
29
52 protected int n;
53
54 private static class Function implements MathFunction {
55 protected int n;
56 protected double u;
57
58 public Function(int n, double u) {
59 this.n = n;
60 this.u = u;
61 }
62
63 public double evaluate(double x) {
64 return u - cdf(n, x);
65 }
66 }
67
73 setN(n);
74 }
75
76 public double density(double x) {
77 return density(n, x);
78 }
79
80 public double cdf(double x) {
81 return cdf(n, x);
82 }
83
84 public double barF(double x) {
85 return barF(n, x);
86 }
87
88 public double inverseF(double u) {
89 return inverseF(n, u);
90 }
91
92 private static double dclem(int n, double x, double EPS) {
93 return (cdf(n, x + EPS) - cdf(n, x - EPS)) / (2.0 * EPS);
94 }
95
100 public static double density(int n, double x) {
101 if (n <= 0)
102 throw new IllegalArgumentException("Calling kolmogorovSmirnovPlus with n < 1");
103 if (x <= 0.0 || x >= 1.0)
104 return 0.0;
105 if (n == 1)
106 return 1.0;
107 final double EPS = 1.0 / 100.0;
108 final double D1 = dclem(n, x, EPS);
109 final double D2 = dclem(n, x, 2.0 * EPS);
110 final double RES = D1 + (D1 - D2) / 3.0;
111 if (RES < 0.0)
112 return 0.0;
113 return RES;
114 }
115
145 public static double cdf(int n, double x) {
146 if (n <= 0)
147 throw new IllegalArgumentException("Calling kolmogorovSmirnovPlus with n < 1");
148 if (x <= 0.0)
149 return 0.0;
150 if ((x >= 1.0) || (n * x * x >= 25.0))
151 return 1.0;
152 if (n == 1)
153 return x;
154
155 final double NXPARAM = 6.5; // frontier: alternating series
156 final int NPARAM = 4000; // frontier: non-alternating series
157 double q;
158 double Sum = 0.0;
159 double term;
160 double Njreal;
161 double jreal;
162 double LogCom = Math.log((double) n);
163 int j;
164 int jmax;
165
166 // --------------------------------------------------------------
167 // the alternating series is stable and fast for n*x very small
168 // --------------------------------------------------------------
169
170 if (n * x <= NXPARAM) {
171 final double EPSILON = Num.DBL_MIN;
172 jmax = (int) (n * x);
173 int Sign = -1;
174 for (j = 1; j <= jmax; j++) {
175 jreal = j;
176 Njreal = n - j;
177 q = jreal / n - x;
178 // we must avoid log (0.0) for j = jmax and n*x near an integer
179 if (-q > EPSILON) {
180 term = LogCom + jreal * Math.log(-q) + (Njreal - 1.0) * Math.log1p(-q);
181 Sum += Sign * Math.exp(term);
182 }
183 Sign = -Sign;
184 LogCom += Math.log(Njreal / (j + 1));
185 }
186 // add the term j = 0
187 Sum += Math.exp((n - 1) * Math.log1p(x));
188 return Sum * x;
189 }
190
191 // -----------------------------------------------------------
192 // For nx > NxParam, we use the other exact series for small
193 // n, and the asymptotic form for n larger than NPARAM
194 // -----------------------------------------------------------
195
196 if (n <= NPARAM) {
197 jmax = (int) (n * (1.0 - x));
198 if (1.0 - x - (double) jmax / n <= 0.0)
199 --jmax;
200 for (j = 1; j <= jmax; j++) {
201 jreal = j;
202 Njreal = n - j;
203 q = jreal / n + x;
204 term = LogCom + (jreal - 1.0) * Math.log(q) + Njreal * Math.log1p(-q);
205 Sum += Math.exp(term);
206 LogCom += Math.log(Njreal / (jreal + 1.0));
207 }
208 Sum *= x;
209
210 // add the term j = 0; avoid log (0.0)
211 if (1.0 > x)
212 Sum += Math.exp(n * Math.log1p(-x));
213 return 1.0 - Sum;
214 }
215
216 // --------------------------
217 // Use an asymptotic formula
218 // --------------------------
219
220 term = 2.0 / 3.0;
221 q = x * x * n;
222 Sum = 1.0 - Math.exp(-2.0 * q)
223 * (1.0 - term * x * (1.0 - x * (1.0 - term * q) - term / n * (0.2 - 19.0 / 15.0 * q + term * q * q)));
224 return Sum;
225 }
226
227 private static double KSPlusbarAsymp(int n, double x) {
228 /*
229 * Compute the probability of the complementary KSPlus distribution using an
230 * asymptotic formula
231 */
232 double t = (6.0 * n * x + 1);
233 double z = t * t / (18.0 * n);
234 double v = 1.0 - (2.0 * z * z - 4.0 * z - 1.0) / (18.0 * n);
235 if (v <= 0.0)
236 return 0.0;
237 v = v * Math.exp(-z);
238 if (v >= 1.0)
239 return 1.0;
240 return v;
241 }
242
243//-------------------------------------------------------------------------
244
245 static double KSPlusbarUpper(int n, double x) {
246 /*
247 * Compute the probability of the complementary KS+ distribution in the upper
248 * tail using Smirnov's stable formula
249 */
250
251 if (n > 200000)
252 return KSPlusbarAsymp(n, x);
253
254 int jmax = (int) (n * (1.0 - x));
255 // Avoid log(0) for j = jmax and q ~ 1.0
256 if ((1.0 - x - (double) jmax / n) <= 0.0)
257 jmax--;
258
259 int jdiv;
260 if (n > 3000)
261 jdiv = 2;
262 else
263 jdiv = 3;
264 int j = jmax / jdiv + 1;
265
266 double LogCom = Num.lnFactorial(n) - Num.lnFactorial(j) - Num.lnFactorial(n - j);
267 final double LOGJM = LogCom;
268
269 final double EPSILON = 1.0E-12;
270 double q;
271 double term;
272 double t;
273 double Sum = 0.0;
274
275 while (j <= jmax) {
276 q = (double) j / n + x;
277 term = LogCom + (j - 1) * Math.log(q) + (n - j) * Math.log1p(-q);
278 t = Math.exp(term);
279 Sum += t;
280 LogCom += Math.log((double) (n - j) / (j + 1));
281 if (t <= Sum * EPSILON)
282 break;
283 j++;
284 }
285
286 j = jmax / jdiv;
287 LogCom = LOGJM + Math.log((double) (j + 1) / (n - j));
288
289 while (j > 0) {
290 q = (double) j / n + x;
291 term = LogCom + (j - 1) * Math.log(q) + (n - j) * Math.log1p(-q);
292 t = Math.exp(term);
293 Sum += t;
294 LogCom += Math.log((double) j / (n - j + 1));
295 if (t <= Sum * EPSILON)
296 break;
297 j--;
298 }
299
300 Sum *= x;
301 // add the term j = 0
302 Sum += Math.exp(n * Math.log1p(-x));
303 return Sum;
304 }
305
310 public static double barF(int n, double x) {
311 if (n <= 0)
312 throw new IllegalArgumentException("Calling kolmogorovSmirnovPlus with n < 1");
313 if (x <= 0.0)
314 return 1.0;
315 if ((x >= 1.0) || (n * x * x >= 365.0))
316 return 0.0;
317 if (n == 1)
318 return 1.0 - x;
319
320 final double NXPARAM = 6.5; // frontier: alternating series
321 final int NPARAM = 4000; // frontier: non-alternating series
322 final int NASYMP = 200000; // frontier: asymptotic
323
324 // the alternating series is stable and fast for n*x very small
325 if (n * x <= NXPARAM)
326 return 1.0 - cdf(n, x);
327
328 if (n >= NASYMP)
329 return KSPlusbarAsymp(n, x);
330
331 if ((n <= NPARAM) || (n * x * x > 1.0))
332 return KSPlusbarUpper(n, x);
333
334 return KSPlusbarAsymp(n, x);
335 // return (1.0 - 2.0*x/3.0)*Math.exp(-2.0*n*x*x);
336 }
337
342 public static double inverseF(int n, double u) {
343 if (n <= 0)
344 throw new IllegalArgumentException("n <= 0");
345 if (u < 0.0 || u > 1.0)
346 throw new IllegalArgumentException("u must be in [0,1]");
347 if (u == 1.0)
348 return 1.0;
349 if (u == 0.0)
350 return 0.0;
351 Function f = new Function(n, u);
352 return RootFinder.brentDekker(0.0, 1.0, f, 1e-8);
353 }
354
358 public int getN() {
359 return n;
360 }
361
365 public void setN(int n) {
366 if (n <= 0)
367 throw new IllegalArgumentException("n <= 0");
368 this.n = n;
369 supportA = 0.0;
370 supportB = 1.0;
371 }
372
376 public double[] getParams() {
377 double[] retour = { n };
378 return retour;
379 }
380
384 public String toString() {
385 return getClass().getSimpleName() + " : n = " + n;
386 }
387
388}
Classes implementing continuous distributions should inherit from this base class.
KolmogorovSmirnovPlusDist(int n)
Constructs an Kolmogorov–Smirnov+ distribution for a sample of size .
double[] getParams()
Returns an array containing the parameter of this object.
static double cdf(int n, double x)
Computes the Kolmogorov–Smirnov+ distribution function.
static double inverseF(int n, double u)
Computes the inverse of the distribution with parameter .
int getN()
Returns the parameter of this object.
double inverseF(double u)
Returns the inverse distribution function .
static double barF(int n, double x)
Computes the complementary distribution function with parameter .
double density(double x)
Returns , the density evaluated at .
void setN(int n)
Sets the parameter of this object.
static double density(int n, double x)
Computes the density of the Kolmogorov–Smirnov+ distribution with parameter .
double barF(double x)
Returns the complementary distribution function.
String toString()
Returns a String containing information about the current distribution.
double cdf(double x)
Returns the distribution function .
This class provides various constants and methods to compute numerical quantities such as factorials,...
Definition Num.java:35
static final double DBL_MIN
Smallest normalized positive floating-point double.
Definition Num.java:113
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.