/* *
* Title:
* Description:
* Copyright: Copyright (c)
* Company:
* @author
* @version 1.0
*/
package umontreal.iro.lecuyer.probdist;
import umontreal.iro.lecuyer.util.Num;
/**
* Extends the class {@link ContinuousDistribution} for
* the Johnson SU distribution.
* It has shape parameters γ and
* δ > 0, location parameter
* ξ, and scale parameter
* λ > 0.
* Denoting
* y = (x - ξ)/λ, the distribution has density
*
*
*
* f (x) = δ/(λ(y^2 + 1)1/2(2π)1/2exp(- (1/2)[γ + δln[y + (y^2 + 1)1/2]]2)) for - ∞ < x < ∞,
*
* and distribution function
*
*
*
* F(x) = Φ{γ + δln[y + (y^2 + 1)1/2]}, for - ∞ < x < ∞,
*
* where Φ is the standard normal distribution function.
* The inverse distribution function is
*
*
*
* F-1(u) = ξ + λ(et(u) - e-t(u))/2, for 0 <= u < 1,
*
* where
*
*
*
* t(u) = [Φ-1(u) - γ]/δ.
*
*
*
* This class relies on the methods {@link NormalDist#cdf01 NormalDist.cdf01} and
* {@link NormalDist#inverseF01 NormalDist.inverseF01} of {@link NormalDist} to
* approximate Φ and Φ-1.
*
*/
public class JohnsonSUDist extends ContinuousDistribution {
private double gamma;
private double delta;
private double xi;
private double lambda;
private static double calcR (double a, double b, double x) {
/* ** Soit y = (x - a)/b; cette fonction calcule r
r = y + sqrt(y*y + 1)
en utilisant un algorithme stable ****/
double y = (x - a)/b;
boolean negative;
if (y < 0.0) {
y = -y;
negative = true;
} else
negative = false;
double r;
if (y < 1.0e10)
r = y + Math.sqrt (1.0 + y*y);
else
r = 2.0 * y;
if (negative)
r = 1.0 / r;
return r;
}
/**
* Same as {@link #JohnsonSUDist(double,double,double,double) JohnsonSUDist}
* (gamma, delta, 0.0, 1.0).
*
*/
public JohnsonSUDist (double gamma, double delta) {
if (delta <= 0)
throw new IllegalArgumentException ("delta <= 0");
this.gamma = gamma;
this.delta = delta;
this.xi = 0.0;
this.lambda = 1.0;
}
/**
* Constructs a JohnsonSUDist object
* with shape parameters γ and δ,
* location parameter ξ, and scale parameter λ.
*
*/
public JohnsonSUDist (double gamma, double delta,
double xi, double lambda) {
setParams (gamma, delta, xi, lambda);
}
public double density (double x) {
return density (gamma, delta, xi, lambda, x);
}
public double cdf (double x) {
return cdf (gamma, delta, xi, lambda, x);
}
public double barF (double x) {
return barF (gamma, delta, xi, lambda, x);
}
public double inverseF (double u){
return inverseF (gamma, delta, xi, lambda, u);
}
public double getMean() {
return JohnsonSUDist.getMean (gamma, delta, xi, lambda);
}
public double getVariance() {
return JohnsonSUDist.getVariance (gamma, delta, xi, lambda);
}
public double getStandardDeviation() {
return JohnsonSUDist.getStandardDeviation (gamma, delta, xi, lambda);
}
/**
* Computes the density function f (x).
*
*/
public static double density (double gamma, double delta,
double xi, double lambda, double x) {
if (lambda <= 0)
throw new IllegalArgumentException ("lambda <= 0");
if (delta <= 0)
throw new IllegalArgumentException ("delta <= 0");
double r = calcR (xi, lambda, x);
if (r <= 0.0)
return 0.0;
double t = gamma + delta*Math.log (r);
double y = (x - xi)/lambda;
return delta/(lambda*Math.sqrt (2.0*Math.PI)*Math.sqrt (y*y + 1.0))*
Math.exp (-t*t/2.0);
}
/**
* Computes the distribution function F(x).
*
*/
public static double cdf (double gamma, double delta,
double xi, double lambda, double x) {
if (lambda <= 0)
throw new IllegalArgumentException ("lambda <= 0");
if (delta <= 0)
throw new IllegalArgumentException ("delta <= 0");
double r = calcR (xi, lambda, x);
if (r > 0.0)
return NormalDist.cdf01 (gamma + delta*Math.log (r));
else
return 0.0;
}
/**
* Computes the complementary distribution function 1 - F(x).
*
*/
public static double barF (double gamma, double delta,
double xi, double lambda, double x) {
if (lambda <= 0)
throw new IllegalArgumentException ("lambda <= 0");
if (delta <= 0)
throw new IllegalArgumentException ("delta <= 0");
double r = calcR (xi, lambda, x);
if (r > 0.0)
return NormalDist.barF01 (gamma + delta * Math.log (r));
else
return 1.0;
}
/**
* Computes the inverse distribution function F-1(u).
*
*/
public static double inverseF (double gamma, double delta,
double xi, double lambda, double u) {
if (lambda <= 0)
throw new IllegalArgumentException ("lambda <= 0");
if (delta <= 0)
throw new IllegalArgumentException ("delta <= 0");
if (u > 1.0 || u < 0.0)
throw new IllegalArgumentException ("u not in [0,1]");
if (u >= 1.0)
return Double.POSITIVE_INFINITY;
if (u <= 0.0)
return Double.NEGATIVE_INFINITY;
double z = NormalDist.inverseF01 (u);
double v = (z - gamma)/delta;
if (v >= Num.LN2*Num.DBL_MAX_EXP)
return Double.POSITIVE_INFINITY;
if (v <= Num.LN2*Num.DBL_MIN_EXP)
return Double.NEGATIVE_INFINITY;
return xi + lambda * Math.sinh(v);
}
/**
* Computes and returns the mean
* of the Johnson SU distribution with parameters γ, δ, ξ and λ.
*
* @return the mean of the Johnson SU distribution
*
* E[X] = ξ - λexp1/(2δ2)sinh(γ/δ)
*
*/
public static double getMean (double gamma, double delta,
double xi, double lambda) {
if (lambda <= 0.0)
throw new IllegalArgumentException ("lambda <= 0");
if (delta <= 0.0)
throw new IllegalArgumentException ("delta <= 0");
return (xi - (lambda * Math.exp(1.0 / (2.0 * delta * delta)) *
Math.sinh(gamma / delta)));
}
/**
* Computes and returns the variance
* of the Johnson SU distribution with parameters γ, δ, ξ and λ.
*
* @return the variance of the Johnson SU distribution
*
* Var[X] = (λ2/2)(exp1/δ2 -1)(exp1/δ2cosh(2γ/δ) + 1)
*
*/
public static double getVariance (double gamma, double delta,
double xi, double lambda) {
double omega2;
if (lambda <= 0.0)
throw new IllegalArgumentException ("lambda <= 0");
if (delta <= 0.0)
throw new IllegalArgumentException ("delta <= 0");
omega2 = Math.exp(1 / (delta * delta));
return ((omega2 - 1) * (omega2 * Math.cosh(2 * gamma / delta) + 1) / 2 * lambda * lambda);
}
/**
* Computes and returns the standard deviation of the Johnson SU
* distribution with parameters γ, δ, ξ and λ.
*
* @return the standard deviation of the Johnson SU distribution
*
*/
public static double getStandardDeviation (double gamma, double delta,
double xi, double lambda) {
return Math.sqrt (JohnsonSUDist.getVariance (gamma, delta, xi, lambda));
}
/**
* Returns the value of γ for this object.
*
*/
public double getGamma() {
return gamma;
}
/**
* Returns the value of δ for this object.
*
*/
public double getDelta() {
return delta;
}
/**
* Returns the value of ξ for this object.
*
*/
public double getXi() {
return xi;
}
/**
* Returns the value of λ for this object.
*
*/
public double getLambda() {
return lambda;
}
/**
* Sets the value of the parameters γ, δ, ξ and
* λ for this object.
*
*/
public void setParams (double gamma, double delta,
double xi, double lambda) {
if (lambda <= 0)
throw new IllegalArgumentException ("lambda <= 0");
if (delta <= 0)
throw new IllegalArgumentException ("delta <= 0");
this.gamma = gamma;
this.delta = delta;
this.xi = xi;
this.lambda = lambda;
}
/**
* Return a table containing the parameters of the current distribution.
* This table is put in regular order: [γ, δ, ξ, λ].
*
*
*/
public double[] getParams () {
double[] retour = {gamma, delta, xi, lambda};
return retour;
}
public String toString () {
return getClass().getSimpleName() + " : gamma = " + gamma + ", delta = " + delta + ", xi = " + xi + ", lambda = " + lambda;
}
}
Ads help maintain this website.