source: src/main/java/weka/core/RandomVariates.java @ 4

Last change on this file since 4 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 8.7 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    RandomVariates.java
19 *    Copyright (C) 2002 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.core;
24
25import java.util.Random;
26
27/**
28 * Class implementing some simple random variates generator.
29 *
30 * @author Xin Xu (xx5@cs.waikato.ac.nz)
31 * @version $Revision: 5359 $
32 */
33public final class RandomVariates extends Random implements RevisionHandler {
34
35  /** for serialization */
36  private static final long serialVersionUID = -4763742718209460354L;
37
38  /**
39   * Simply the constructor of super class
40   */
41  public RandomVariates(){ super(); }
42
43  /**
44   * Simply the constructor of super class
45   *
46   * @param seed the seed in this random object
47   */
48  public RandomVariates(long seed){ super(seed); }
49
50  /**
51   * Simply use the method of the super class
52   *
53   * @param bits - random bits
54   * @return the next pseudorandom value from this random number
55   * generator's sequence.
56   */
57  protected int next(int bits) {return super.next(bits);}
58
59  /**
60   * Generate a value of a variate following standard exponential
61   * distribution using simple inverse method.<p>
62   *
63   * Variates related to standard Exponential can be generated using simple
64   * transformations.
65   * @return a value of the variate
66   */ 
67  public double nextExponential(){
68    return -Math.log(1.0-super.nextDouble());
69  }
70
71  /**
72   * Generate a value of a variate following standard Erlang distribution.
73   * It can be used when the shape parameter is an integer and not too large,
74   * say, <100.  When the parameter is not an integer (which is often named
75   * Gamma distribution) or is large, use <code>nextGamma(double a)</code>
76   * instead.
77   *
78   * @param a the shape parameter, must be no less than 1
79   * @return a value of the variate
80   * @exception Exception if parameter less than 1
81   */
82  public double nextErlang(int a) throws Exception{
83    if(a<1)
84      throw new Exception("Shape parameter of Erlang distribution must be greater than 1!");
85
86    double product = 1.0;
87    for(int i=1; i<=a; i++)
88      product *= super.nextDouble();
89
90    return -Math.log(product);
91  }
92
93  /**
94   * Generate a value of a variate following standard Gamma distribution
95   * with shape parameter a.<p>
96   * If a>1, it uses a rejection method developed by Minh(1988)"Generating
97   * Gamma Variates", ACM Trans. on Math. Software, Vol.14, No.3, pp261-266.
98   * <br>
99   * If a<1, it uses the algorithm "GS" developed by Ahrens and Dieter(1974)
100   * "COMPUTER METHODS FOR SAMPLING FROM GAMMA, BETA, POISSON AND BINOMIAL
101   * DISTRIBUTIONS", COMPUTING, 12 (1974), pp223-246, and further implemented
102   * in Fortran by Ahrens, Kohrt and Dieter(1983) "Algorithm 599: sampling
103   * from Gamma and Poisson distributions", ACM Trans. on Math. Software,
104   * Vol.9 No.2, pp255-257.<p>
105   *
106   * Variates related to standard Gamma can be generated using simple
107   * transformations.
108   *
109   * @param a the shape parameter, must be greater than 1
110   * @return a value of the variate
111   * @exception Exception if parameter not greater than 1
112   */
113  public double nextGamma(double a) throws Exception{
114    if(a<=0.0)
115      throw new Exception("Shape parameter of Gamma distribution"+
116      "must be greater than 0!");
117    else if (a==1.0)
118      return nextExponential();
119    else if (a<1.0){
120      double b=1.0+Math.exp(-1.0)*a, p,x, condition;
121      do{
122        p=b*super.nextDouble();
123        if(p<1.0){
124          x = Math.exp(Math.log(p)/a);
125          condition = x;
126        }
127        else{
128          x = -Math.log((b-p)/a);
129          condition = (1.0-a)*Math.log(x);
130        }
131      }
132      while(nextExponential() < condition);
133      return x;     
134    }
135    else{ // a>1
136      double b=a-1.0, D=Math.sqrt(b), D1,x1,x2,xl,f1,f2,x4,x5,xr,f4,f5,
137      p1,p2,p3,p4;
138
139      // Initialization
140      if(a<=2.0){
141        D1 = b/2.0;
142        x1 = 0.0;
143        x2 = D1;
144        xl = -1.0;
145        f1 = 0.0;
146      }
147      else{
148        D1 = D-0.5;
149        x2 = b-D1;
150        x1 = x2-D1;
151        xl = 1.0-b/x1;
152        f1 = Math.exp(b*Math.log(x1/b)+2.0*D1);
153      }
154
155      f2=Math.exp(b*Math.log(x2/b)+D1);
156      x4 = b+D;
157      x5 = x4+D;
158      xr = 1.0-b/x5;
159      f4 = Math.exp(b*Math.log(x4/b)-D);
160      f5 = Math.exp(b*Math.log(x5/b)-2.0*D);
161      p1 = 2.0*f4*D;
162      p2 = 2.0*f2*D1+p1;
163      p3 = f5/xr+p2;
164      p4 = -f1/xl+p3;
165
166      // Generation
167      double u, w=Double.MAX_VALUE, x=b, v, xp;
168      while(Math.log(w) > (b*Math.log(x/b)+b-x) || x < 0.0){
169        u=super.nextDouble()*p4;
170        if(u<=p1){ // step 5-6
171          w = u/D-f4;
172          if(w<=0.0) return (b+u/f4);
173          if(w<=f5)  return (x4+(w*D)/f5);
174
175          v = super.nextDouble();
176          x=x4+v*D;
177          xp=2.0*x4-x;
178
179          if(w >= f4+(f4-1)*(x-x4)/(x4-b))
180            return xp;
181          if(w <= f4+(b/x4-1)*f4*(x-x4))
182            return x;
183          if((w < 2.0*f4-1.0) || 
184              (w < 2.0*f4-Math.exp(b*Math.log(xp/b)+b-xp)))
185            continue;
186          return xp;
187        }
188        else if(u<=p2){ // step 7-8
189          w = (u-p1)/D1-f2;
190          if(w<=0.0) return (b-(u-p1)/f2);
191          if(w<=f1)  return (x1+w*D1/f1);
192
193          v = super.nextDouble();
194          x=x1+v*D1;
195          xp=2.0*x2-x;
196
197          if(w >= f2+(f2-1)*(x-x2)/(x2-b))
198            return xp;
199          if(w <= f2*(x-x1)/D1)
200            return x;
201          if((w < 2.0*f2-1.0) || 
202              (w < 2.0*f2-Math.exp(b*Math.log(xp/b)+b-xp)))
203            continue;
204          return xp;
205        }
206        else if(u<p3){ // step 9
207          w = super.nextDouble();
208          u = (p3-u)/(p3-p2);
209          x = x5-Math.log(u)/xr;
210          if(w <= (xr*(x5-x)+1.0)/u) return x;
211          w = w*f5*u;
212        }
213        else{ // step 10
214          w = super.nextDouble();
215          u = (p4-u)/(p4-p3);
216          x = x1-Math.log(u)/xl;
217          if(x<0.0) continue;
218          if(w <= (xl*(x1-x)+1.0)/u) return x;
219          w = w*f1*u;
220        }
221      }
222
223      return x;
224    }   
225  }
226
227  /**
228   * Returns the revision string.
229   *
230   * @return            the revision
231   */
232  public String getRevision() {
233    return RevisionUtils.extract("$Revision: 5359 $");
234  }
235
236
237  /**
238   * Main method for testing this class.
239   *
240   * @param ops # of variates/seed, default is 10/45
241   */
242  public static void main(String[] ops) {
243
244    int n = Integer.parseInt(ops[0]);
245    if(n<=0)
246      n=10;
247    long seed = Long.parseLong(ops[1]);
248    if(seed <= 0)
249      seed = 45;
250    RandomVariates var = new RandomVariates(seed);
251    double varb[] = new double[n];
252
253    try {
254      System.out.println("Generate "+n+" values with std. exp dist:");
255      for(int i=0; i<n; i++){
256        varb[i] = var.nextExponential();
257        System.out.print("["+i+"] "+varb[i]+", ");
258      }
259
260      System.out.println("\nMean is "+Utils.mean(varb)+
261          ", Variance is "+Utils.variance(varb)+
262          "\n\nGenerate "+n+" values with"+
263      " std. Erlang-5 dist:");
264
265      for(int i=0; i<n; i++){
266        varb[i] = var.nextErlang(5);
267        System.out.print("["+i+"] "+varb[i]+", ");
268      }
269
270      System.out.println("\nMean is "+Utils.mean(varb)+
271          ", Variance is "+Utils.variance(varb)+
272          "\n\nGenerate "+n+" values with"+
273      " std. Gamma(4.5) dist:");
274
275      for(int i=0; i<n; i++){
276        varb[i] = var.nextGamma(4.5);
277        System.out.print("["+i+"] "+varb[i]+", ");
278      } 
279
280      System.out.println("\nMean is "+Utils.mean(varb)+
281          ", Variance is "+Utils.variance(varb)+
282          "\n\nGenerate "+n+" values with"+
283      " std. Gamma(0.5) dist:");
284
285      for(int i=0; i<n; i++){
286        varb[i] = var.nextGamma(0.5);
287        System.out.print("["+i+"] "+varb[i]+", ");
288      }           
289
290      System.out.println("\nMean is "+Utils.mean(varb)+
291          ", Variance is "+Utils.variance(varb)+
292          "\n\nGenerate "+n+" values with"+
293      " std. Gaussian(5, 2) dist:");
294
295      for(int i=0; i<n; i++){
296        varb[i] = var.nextGaussian()*2.0+5.0;
297        System.out.print("["+i+"] "+varb[i]+", ");
298      }           
299      System.out.println("\nMean is "+Utils.mean(varb)+
300          ", Variance is "+Utils.variance(varb)+"\n");
301
302    } catch (Exception e) {
303      e.printStackTrace();
304    }
305  }
306}
Note: See TracBrowser for help on using the repository browser.