/*
 *  Mathlib : A C Library of Special Functions
 *  Copyright (C) 1998   Ross Ihaka
 *  Copyright (C) 2000-9 The R Development Core Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, a copy is available at
 *  http://www.r-project.org/Licenses/
 */
package jdistlib;

import jdistlib.generic.GenericDistribution;
import jdistlib.math.UnivariateFunction;
import jdistlib.math.opt.Optimization;
import jdistlib.rng.RandomEngine;
import static java.lang.Math.*;
import static jdistlib.math.Constants.DBL_MIN;

/**
 * Inverse normal (or Wald) distribution. Taken from package gamlss.dist.
 * Parameterization: mu and sigma. Note: lambda = 1/sigma^2.
 *
 */
public class InvNormal extends GenericDistribution {
	public static final double density(double x, double mu, double sigma, boolean give_log) {
		if (Double.isNaN(mu) || Double.isNaN(sigma)) return mu + sigma;
		if (mu <= 0 || sigma <= 0) return Double.NaN;
		double v = (x/mu - 1) / sigma;
		x = -0.5*log(2*PI)-log(sigma)-(3/2)*log(x)-(v*v)/(2*x);
	    return give_log ? x : exp(x);
	}

	public static final double cumulative(double q, double mu, double sigma, boolean lower_tail, boolean log_p) {
		if (Double.isNaN(mu) || Double.isNaN(sigma)) return mu + sigma;
		if (mu <= 0 || sigma <= 0) return Double.NaN;
		double cdf1 = Normal.cumulative(((q/mu)-1)/(sigma*sqrt(q)), 0, 1, true, false);
		double lcdf2 = (2/(mu*sigma*sigma)) + Normal.cumulative((-((q/mu)+1))/(sigma*sqrt(q)), 0, 1, true, true);
		q = cdf1 + exp(lcdf2);
		if (!lower_tail) q = 1 - q; 
	    return log_p ? log(q) : q;
	}

	public static final double quantile(double p, double mu, double sigma, boolean lower_tail, boolean log_p) {
		if (Double.isNaN(mu) || Double.isNaN(sigma)) return mu + sigma;
		if (mu <= 0 || sigma <= 0 || p < 0 || p > 1) return Double.NaN;
		if (log_p) p = exp(p);
		if (!lower_tail) p = 1-p;
		double ax = DBL_MIN, bx = mu;
		if (cumulative(mu, mu, sigma, true, false) < p) {
			ax = mu;
			int j = 1;
			do {
				bx = mu + j * sigma;
				if (cumulative(bx, mu, sigma, true, false) >= p) break;
				j++;
			} while (true);
		}
		UnivariateFunction f = new UnivariateFunction() {
			double mu, sigma, p;
			public double eval(double x) {
				return cumulative(x, mu, sigma, true, false) - p;
			}
			public void setObjects(Object... obj) {}
			public void setParameters(double... params) {
				mu = params[0];
				sigma = params[1];
				p = params[2];
			}
		};
		f.setParameters(mu, sigma, p);
		return Optimization.zeroin(f, ax, bx, 0, 10000);
	}

	public static final double random(double mu, double sigma, RandomEngine random) {
		if (Double.isNaN(mu) || Double.isNaN(sigma)) return mu + sigma;
		if (mu <= 0 || sigma <= 0) return Double.NaN;
		return quantile(random.nextDouble(), mu, sigma, true, false);
	}

	public static final double[] random(int n, double mu, double sigma, RandomEngine random) {
		double[] rand = new double[n];
		for (int i = 0; i < n; i++)
			rand[i] = random(mu, sigma, random);
		return rand;
	}

	protected double mu, sigma;

	public InvNormal(double mu, double sigma) {
		this.mu = mu; this.sigma = sigma;
	}

	@Override
	public double density(double x, boolean log) {
		return density(x, mu, sigma, log);
	}

	@Override
	public double cumulative(double p, boolean lower_tail, boolean log_p) {
		return cumulative(p, mu, sigma, lower_tail, log_p);
	}

	@Override
	public double quantile(double q, boolean lower_tail, boolean log_p) {
		return quantile(q, mu, sigma, lower_tail, log_p);
	}

	@Override
	public double random() {
		return random(mu, sigma, random);
	}

	/*
	public static final void main(String[] args) {
		double x, y, z;
		for (int i = 1; i <= 600; i++) {
			x = i/100.0;
			y = cumulative(x, 1, 0.5, true, false);
			z = quantile(y, 1, 0.5, true, false);
			System.out.println(x + ", " + y + ", " + z);
		}
	}
	//*/
}

 

Ads help maintain this website.