Mega Code Archive

 
Categories / Java / Development Class
 

Return a sample from the GammaPoissionGaussian distribution, with parameter IA

/* Copyright (C) 2002 Univ. of Massachusetts Amherst, Computer Science Dept.    This file is part of "MALLET" (MAchine Learning for LanguagE Toolkit).    http://www.cs.umass.edu/~mccallum/mallet    This software is provided under the terms of the Common Public License,    version 1.0, as published by http://www.opensource.org.  For further    information, see the file `LICENSE' included with this distribution. */ /**     @author Andrew McCallum <a href="mailto:mccallum@cs.umass.edu">mccallum@cs.umass.edu</a>  */ //package cc.mallet.util; import java.util.*; public class Randoms extends java.util.Random {   public Randoms (int seed) {     super(seed);   }      public Randoms () {     super();   }      /** Return random integer from Poission with parameter lambda.      * The mean of this distribution is lambda.  The variance is lambda. */   public synchronized int nextPoisson(double lambda) {     int i,j,v=-1;     double l=Math.exp(-lambda),p;     p=1.0;     while (p>=l) {       p*=nextUniform();       v++;     }     return v;   }   /** Return nextPoisson(1). */   public synchronized int nextPoisson() {     return nextPoisson(1);   }   /** Return a random boolean, equally likely to be true or false. */   public synchronized boolean nextBoolean() {     return (next(32) & 1 << 15) != 0;   }   /** Return a random boolean, with probability p of being true. */   public synchronized boolean nextBoolean(double p) {     double u=nextUniform();     if(u < p) return true;     return false;   }   /** Return a random BitSet with "size" bits, each having probability p of being true. */   public synchronized BitSet nextBitSet (int size, double p)   {     BitSet bs = new BitSet (size);     for (int i = 0; i < size; i++)       if (nextBoolean (p)) {         bs.set (i);       }     return bs;   }   /** Return a random double in the range 0 to 1, inclusive, uniformly sampled from that range.     * The mean of this distribution is 0.5.  The variance is 1/12. */   public synchronized double nextUniform() {     long l = ((long)(next(26)) << 27) + next(27);     return l / (double)(1L << 53);   }   /** Return a random double in the range a to b, inclusive, uniformly sampled from that range.    * The mean of this distribution is (b-a)/2.  The variance is (b-a)^2/12 */   public synchronized double nextUniform(double a,double b) {     return a + (b-a)*nextUniform();   }   /** Draw a single sample from multinomial "a". */   public synchronized int nextDiscrete (double[] a) {     double b = 0, r = nextUniform();     for (int i = 0; i < a.length; i++) {       b += a[i];       if (b > r) {         return i;       }     }     return a.length-1;   }   /** draw a single sample from (unnormalized) multinomial "a", with normalizing factor "sum". */   public synchronized int nextDiscrete (double[] a, double sum) {     double b = 0, r = nextUniform() * sum;     for (int i = 0; i < a.length; i++) {       b += a[i];       if (b > r) {         return i;       }     }     return a.length-1;   }   private double nextGaussian;   private boolean haveNextGaussian = false;   /** Return a random double drawn from a Gaussian distribution with mean 0 and variance 1. */   public synchronized double nextGaussian() {     if (!haveNextGaussian) {       double v1=nextUniform(),v2=nextUniform();       double x1,x2;       x1=Math.sqrt(-2*Math.log(v1))*Math.cos(2*Math.PI*v2);       x2=Math.sqrt(-2*Math.log(v1))*Math.sin(2*Math.PI*v2);       nextGaussian=x2;       haveNextGaussian=true;       return x1;     }     else {       haveNextGaussian=false;       return nextGaussian;     }   }   /** Return a random double drawn from a Gaussian distribution with mean m and variance s2. */   public synchronized double nextGaussian(double m,double s2) {     return nextGaussian()*Math.sqrt(s2)+m;   }   // generate Gamma(1,1)   // E(X)=1 ; Var(X)=1   /** Return a random double drawn from a Gamma distribution with mean 1.0 and variance 1.0. */   public synchronized double nextGamma() {     return nextGamma(1,1,0);   }   /** Return a random double drawn from a Gamma distribution with mean alpha and variance 1.0. */   public synchronized double nextGamma(double alpha) {     return nextGamma(alpha,1,0);   }   /* Return a sample from the Gamma distribution, with parameter IA */   /* From Numerical "Recipes in C", page 292 */   public synchronized double oldNextGamma (int ia)   {     int j;     double am, e, s, v1, v2, x, y;     assert (ia >= 1) ;     if (ia < 6)      {       x = 1.0;       for (j = 1; j <= ia; j++)         x *= nextUniform ();       x = - Math.log (x);     }     else     {       do       {         do         {           do           {             v1 = 2.0 * nextUniform () - 1.0;             v2 = 2.0 * nextUniform () - 1.0;           }           while (v1 * v1 + v2 * v2 > 1.0);           y = v2 / v1;           am = ia - 1;           s = Math.sqrt (2.0 * am + 1.0);           x = s * y + am;         }         while (x <= 0.0);         e = (1.0 + y * y) * Math.exp (am * Math.log (x/am) - s * y);       }       while (nextUniform () > e);     }     return x;   }      /** Return a random double drawn from a Gamma distribution with mean alpha*beta and variance alpha*beta^2. */   public synchronized double nextGamma(double alpha, double beta) {     return nextGamma(alpha,beta,0);   }   /** Return a random double drawn from a Gamma distribution with mean alpha*beta+lamba and variance alpha*beta^2. */   public synchronized double nextGamma(double alpha,double beta,double lambda) {     double gamma=0;     if (alpha <= 0 || beta <= 0) {       throw new IllegalArgumentException ("alpha and beta must be strictly positive.");     }     if (alpha < 1) {       double b,p;       boolean flag=false;       b=1+alpha*Math.exp(-1);       while(!flag) {         p=b*nextUniform();         if (p>1) {           gamma=-Math.log((b-p)/alpha);           if (nextUniform()<=Math.pow(gamma,alpha-1)) flag=true;         }         else {           gamma=Math.pow(p,1/alpha);           if (nextUniform()<=Math.exp(-gamma)) flag=true;         }       }     }     else if (alpha == 1) {       gamma = -Math.log (nextUniform ());     } else {       double y = -Math.log (nextUniform ());       while (nextUniform () > Math.pow (y * Math.exp (1 - y), alpha - 1))         y = -Math.log (nextUniform ());       gamma = alpha * y;     }     return beta*gamma+lambda;   }   /** Return a random double drawn from an Exponential distribution with mean 1 and variance 1. */   public synchronized double nextExp() {     return nextGamma(1,1,0);   }   /** Return a random double drawn from an Exponential distribution with mean beta and variance beta^2. */   public synchronized double nextExp(double beta) {     return nextGamma(1,beta,0);   }   /** Return a random double drawn from an Exponential distribution with mean beta+lambda and variance beta^2. */   public synchronized double nextExp(double beta,double lambda) {     return nextGamma(1,beta,lambda);   }   /** Return a random double drawn from an Chi-squarted distribution with mean 1 and variance 2.     * Equivalent to nextChiSq(1) */   public synchronized double nextChiSq() {     return nextGamma(0.5,2,0);   }   /** Return a random double drawn from an Chi-squared distribution with mean df and variance 2*df.  */   public synchronized double nextChiSq(int df) {     return nextGamma(0.5*(double)df,2,0);   }   /** Return a random double drawn from an Chi-squared distribution with mean df+lambda and variance 2*df.  */   public synchronized double nextChiSq(int df,double lambda) {     return nextGamma(0.5*(double)df,2,lambda);   }   /** Return a random double drawn from a Beta distribution with mean a/(a+b) and variance ab/((a+b+1)(a+b)^2).  */   public synchronized double nextBeta(double alpha,double beta) {     if (alpha <= 0 || beta <= 0) {       throw new IllegalArgumentException ("alpha and beta must be strictly positive.");     }     if (alpha == 1 && beta == 1) {       return nextUniform ();     } else if (alpha >= 1 && beta >= 1) {       double A = alpha - 1,               B = beta - 1,               C = A + B,               L = C * Math.log (C),               mu = A / C,               sigma = 0.5 / Math.sqrt (C);       double y = nextGaussian (), x = sigma * y + mu;       while (x < 0 || x > 1) {         y = nextGaussian ();         x = sigma * y + mu;       }       double u = nextUniform ();       while (Math.log (u) >= A * Math.log (x / A) + B * Math.log ((1 - x) / B) + L + 0.5 * y * y) {         y = nextGaussian ();         x = sigma * y + mu;         while (x < 0 || x > 1) {           y = nextGaussian ();           x = sigma * y + mu;         }         u = nextUniform ();       }       return x;     } else {       double v1 = Math.pow (nextUniform (), 1 / alpha),               v2 = Math.pow (nextUniform (), 1 / beta);       while (v1 + v2 > 1) {         v1 = Math.pow (nextUniform (), 1 / alpha);         v2 = Math.pow (nextUniform (), 1 / beta);       }       return v1 / (v1 + v2);     }   }   public static void main (String[] args)   {     // Prints the nextGamma() and oldNextGamma() distributions to     // System.out for testing/comparison.     Randoms r = new Randoms();     final int resolution = 60;     int[] histogram1 = new int[resolution];     int[] histogram2 = new int[resolution];     int scale = 10;     for (int i = 0; i < 10000; i++) {       double x = 4;       int index1 = ((int)(r.nextGamma(x)/scale * resolution)) % resolution;       int index2 = ((int)(r.oldNextGamma((int)x)/scale * resolution)) % resolution;       histogram1[index1]++;       histogram2[index2]++;     }     for (int i = 0; i < resolution; i++) {       for (int y = 0; y < histogram1[i]/scale; y++)         System.out.print("*");       System.out.print("\n");       for (int y = 0; y < histogram2[i]/scale; y++)         System.out.print("-");       System.out.print("\n");     }   }    }