Gamma.java

/*
 * Copyright (c) 2005, Regents of the University of California
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.  
 *
 * * Neither the name of the University of California, Berkeley nor
 *   the names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior 
 *   written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package blog.distrib;

import blog.*;
import java.util.*;
import common.Util;



A Gamma distribution with shape parameter k and scale parameter 1/lambda. Defined as f(x) = (lambdae^(-lambdax)(lambdax)^(k - 1)) / Gamma(k) where Gamma(k) = integral from 0 to infinity of t^(k-1) e^(-t) dt



public class Gamma extends AbstractCondProbDistrib {
    

Creates a new Gamma distribution with parameters k and lambda.


    public Gamma(List params) {
	if (!((params.get(0) instanceof Number) 
	      && (params.get(1) instanceof Number))) {
	    throw new IllegalArgumentException
		("Gamma expects two numerical arguments "
		 + "{k, lambda} where both are Numbers. Got: " + params);
	}
	k = ((Number)params.get(0)).doubleValue();
	lambda = ((Number)params.get(1)).doubleValue();
    }
 
    

Creates a new Gamma distribution with parameters k and lambda.


    public Gamma(double k, double lambda) {
	this.k = k;
	this.lambda = lambda;
    }
	
    

Returns the probability of x under this distribution


    public double getProb(List args, Object value) {
	if (!(value instanceof Number)) {
	    throw new IllegalArgumentException
		("Gamma CPD defines a distribution over objects" 
		 + " of class Number, not " + value.getClass() + ".");
	} else {
	    double x = ((Number)value).doubleValue();
	    return (lambda*Math.exp(-lambda*x)
		    * Math.pow(lambda*x, k-1) / gamma(k));
	}
    }

    

Returns the log of the probability of x under this distribution.


    public double getLogProb(List args, Object value) {
	if (!(value instanceof Number)) {
	    throw new IllegalArgumentException
		("Gamma CPD defines a distribution over objects" 
		 + " of class Number, not " + value.getClass() + ".");
	} else {
	    return Math.log(getProb(args, value));
	}
    }

    

Returns a double sampled according to this distribution. Uniformly fast for all k > 0. (Reference: Non-Uniform Random Variate Generation, Devroye http://cgm.cs.mcgill.ca/~luc/rnbookindex.html) Uses Cheng's rejection algorithm (GB) for k>=1, rejection from Weibull distribution for 0 < k < 1.


    public Object sampleVal(List args, Type childType) {
	boolean accept = false;
	if (k >= 1) {
	    //Cheng's algorithm
	    double b = (k - Math.log(4));
	    double c = (k + Math.sqrt(2*k - 1));
	    double lam = Math.sqrt(2*k - 1);
	    double cheng = (1 + Math.log(4.5));
	    double u, v, x, y, z, r;
	    do {
		u = Util.random();
		v = Util.random();
		y = ((1 / lam) * Math.log(v / (1 - v)));
		x = (k * Math.exp(y));
		z = (u * v * v);
		r = (b + (c * y) - x);
		if ((r >= ((4.5 * z) - cheng)) || (r >= Math.log(z))) {
		    accept = true;
		}
	    } while (!accept );
	    return new Double(x / lambda);
	}
	else {
	    //Weibull algorithm
	    double c = (1 / k);
	    double d = ((1 - k) * Math.pow(k, (k / (1 - k))));
	    double u, v, z, e, x;
	    do {
		u = Util.random();
		v = Util.random();
		z = -Math.log(u); //generating random exponential variates
		e = -Math.log(v);
		x = Math.pow(z, c);
		if ((z + e) >= (d + x)) {
		    accept = true;
		}
	    } while (!accept);
	    return new Double(x / lambda);
	}
    }

	
    /*
     * Returns an approximation of the Gamma function of x
     * r(x) = integral from 0 to infinity of (t^(x-1) * e^(-t) dt)
     * with |error| < 2e-10.  Laczos Approximation
     * Reference: Numerical Recipes in C
     * http://www.library.cornell.edu/nr/cbookcpdf.html
     */
    public static double gamma(double x) {
	return Math.exp(lgamma(x));
    }
    /*
     * Returns an approximation of the log of the Gamma function
     * of x.  Laczos Approximation
     * Reference: Numerical Recipes in C
     * http://www.library.cornell.edu/nr/cbookcpdf.html
     */
    public static double lgamma(double x) {
	double[] cof = {76.18009172947146, -86.50532032941677,
			24.01409824083091,-1.231739572450155,
			0.1208650973866179e-2,-0.5395239384953e-5};
	double y, z, ser, tmp;
	y = x;
	tmp = x + 5.5;
	tmp -= ((x + 0.5) * Math.log(tmp));
	ser = 1.000000000190015;
	for (int j = 0; j < 6; j += 1) {
	    y += 1;
	    ser += (cof[j] / y);
	}
	return (-tmp + Math.log(2.5066282746310005*ser / x));
    }

    private double lambda;
    private double k;
}


This file was generated on Tue Jun 08 17:53:47 PDT 2010 from file Gamma.java
by the ilog.language.tools.Hilite Java tool written by Hassan Aït-Kaci