/* *
 * Title:        

* Description:

* Copyright: Copyright (c)

* Company:

* @author * @version 1.0 */ package umontreal.iro.lecuyer.probdist; import umontreal.iro.lecuyer.util.*; import umontreal.iro.lecuyer.functions.MathFunction; /** * Extends the class {@link ContinuousDistribution} for the * Cramér-von Mises distribution (see). * Given a sample of n independent uniforms Ui over [0, 1], * the Cramér-von Mises statistic Wn2 is defined by *

*

*
* Wn2 = 1/12n + ∑j=1n(U(j) - (j-0.5)/n)2, *

* where the U(j) are the Ui sorted in increasing order. * The distribution function (the cumulative probabilities) * is defined as * Fn(x) = P[Wn2 <= x]. * */ public class CramerVonMisesDist extends ContinuousDistribution { protected int n; private static class Function implements MathFunction { protected int n; protected double u; public Function (int n, double u) { this.n = n; this.u = u; } public double evaluate (double x) { return u - cdf(n,x); } } /** * Constructs a Cramér-von Mises distribution for a sample of size n. * */ public CramerVonMisesDist (int n) { setN (n); } public double density (double x) { return density (n, x); } public double cdf (double x) { return cdf (n, x); } public double barF (double x) { return barF (n, x); } public double inverseF (double u) { return inverseF (n, u); } public double getMean() { return CramerVonMisesDist.getMean (n); } public double getVariance() { return CramerVonMisesDist.getVariance (n); } public double getStandardDeviation() { return CramerVonMisesDist.getStandardDeviation (n); } /** * Computes the density function * for a Cramér-von Mises distribution with parameter n. * */ public static double density (int n, double x) { if (n <= 0) throw new IllegalArgumentException ("n <= 0"); if (x <= 1.0/(12.0*n) || x >= n/3.0) return 0.0; if (n == 1) return 1.0 / Math.sqrt (x - 1.0/12.0); if (x <= 0.002 || x > 3.95) return 0.0; throw new UnsupportedOperationException("density not implemented."); } /** * Computes the Cramér-von Mises distribution function with parameter n. * Returns an approximation of * P[Wn2 <= x], where Wn2 is the * Cramér von Mises statistic (see). * The approximation is based on the distribution function of * W2 = limn -> ∞Wn2, which has the following series expansion derived * by Anderson and Darling: *

*

*
*         P(W2 <= x)  =  $\displaystyle {\frac{1}{{\pi\sqrt x}}}$∑j=0∞(- 1)j$\displaystyle \binom{-1/2}{j} $(4j+1)1/2    exp{ - $\displaystyle {\frac{{(4j+1)^2}}{{16 x}}}$}K1/4([tex2html_wrap_indisplay246]), *

* where * Kν is the modified Bessel function of the * second kind. * To correct for the deviation between * P(Wn2 <= x) and * P(W2 <= x), * we add a correction in 1/n, obtained empirically by simulation. * For n = 10, 20, 40, the error is less than * 0.002, 0.001, and 0.0005, respectively, while for * n >= 100 it is less than 0.0005. * For * n -> ∞, we estimate that the method returns * at least 6 decimal digits of precision. * For n = 1, the method uses the exact distribution: * * P(W12 <= x) = 2(x - 1/12)1/2 for * 1/12 <= x <= 1/3. * */ public static double cdf (int n, double x) { if (n <= 0) throw new IllegalArgumentException ("n <= 0"); if (n == 1) { if (x <= 1.0/12.0) return 0.0; if (x >= 1.0/3.0) return 1.0; return 2.0*Math.sqrt (x - 1.0/12.0); } if (x <= 1.0/(12.0*n)) return 0.0; if (x <= (n + 3.0)/(12.0*n*n)) { double t = Num.lnFactorial(n) - Num.lnGamma (1.0 + 0.5*n) + 0.5*n*Math.log (Math.PI*(x - 1.0/(12.0*n))); return Math.exp(t); } if (x <= 0.002) return 0.0; if (x > 3.95 || x >= n/3.0) return 1.0; final double EPSILON = Num.DBL_EPSILON; final int JMAX = 20; int j = 0; double Cor, Res, arg; double termX, termS, termJ; termX = 0.0625/x; // 1 / (16x) Res = 0.0; final double A[] = { 1.0, 1.11803398875, 1.125, 1.12673477358, 1.1274116945, 1.12774323743, 1.1279296875, 1.12804477649, 1.12812074678, 1.12817350091 }; do { termJ = 4*j + 1; arg = termJ*termJ*termX; termS = A[j]*Math.exp (-arg)*Num.besselK025 (arg); Res += termS; ++j; } while (!(termS < EPSILON || j > JMAX)); if (j > JMAX) System.err.println ("cramerVonMises: iterations have not converged"); Res /= Math.PI*Math.sqrt (x); // Empirical correction in 1/n if (x < 0.0092) Cor = 0.0; else if (x < 0.03) Cor = -0.0121763 + x*(2.56672 - 132.571*x); else if (x < 0.06) Cor = 0.108688 + x*(-7.14677 + 58.0662*x); else if (x < 0.19) Cor = -0.0539444 + x*(-2.22024 + x*(25.0407 - 64.9233*x)); else if (x < 0.5) Cor = -0.251455 + x*(2.46087 + x*(-8.92836 + x*(14.0988 - x*(5.5204 + 4.61784*x)))); else if (x <= 1.1) Cor = 0.0782122 + x*(-0.519924 + x*(1.75148 + x*(-2.72035 + x*(1.94487 - 0.524911*x)))); else Cor = Math.exp (-0.244889 - 4.26506*x); Res += Cor/n; // This empirical correction is not very precise, so ... if (Res <= 1.0) return Res; else return 1.0; } /** * Computes the complementary distribution function * bar(F)n(x) * with parameter n. * */ public static double barF (int n, double x) { return 1.0 - cdf(n,x); } /** * Computes * x = Fn-1(u), where Fn is the * Cramér-von Mises distribution with parameter n. * */ public static double inverseF (int n, double u) { if (n <= 0) throw new IllegalArgumentException ("n <= 0"); if (u < 0.0 || u > 1.0) throw new IllegalArgumentException ("u must be in [0,1]"); if (u >= 1.0) return n/3.0; if (u <= 0.0) return 1.0/(12.0*n); if (n == 1) return 1.0/12.0 + 0.25*u*u; Function f = new Function (n,u); return RootFinder.brentDekker (0.0, 10.0, f, 1e-6); } /** * Returns the mean of the distribution with parameter n. * * @return the mean * */ public static double getMean (int n) { return 1.0 / 6.0; } /** * Returns the variance of the distribution with parameter n. * * @return variance * */ public static double getVariance (int n) { return (4.0 * n - 3.0) / (180.0 * n ); } /** * Returns the standard deviation of the distribution with * parameter n. * * @return the standard deviation * */ public static double getStandardDeviation (int n) { return Math.sqrt(getVariance(n)); } /** * Returns the parameter n of this object. * */ public int getN() { return n; } /** * Sets the parameter n of this object. * */ public void setN (int n) { if (n <= 0) throw new IllegalArgumentException ("n <= 0"); this.n = n; supportA = 1.0/(12.0*n); supportB = n/3.0; } /** * Return an array containing the parameter n of this object. * * */ public double[] getParams () { double[] retour = {n}; return retour; } public String toString () { return getClass().getSimpleName() + " : n = " + n; } }

Ads help maintain this website.