00001 /* 00002 00003 Copyright (C) 2006-2012 John W. Eaton 00004 00005 This file is part of Octave. 00006 00007 Octave is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 Octave is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with Octave; see the file COPYING. If not, see 00019 <http://www.gnu.org/licenses/>. 00020 00021 */ 00022 00023 /* Original version written by Paul Kienzle distributed as free 00024 software in the in the public domain. */ 00025 00026 /* 00027 00028 double randg(a) 00029 void fill_randg(a,n,x) 00030 00031 Generate a series of standard gamma distributions. 00032 00033 See: Marsaglia G and Tsang W (2000), "A simple method for generating 00034 gamma variables", ACM Transactions on Mathematical Software 26(3) 363-372 00035 00036 Needs the following defines: 00037 * NAN: value to return for Not-A-Number 00038 * RUNI: uniform generator on (0,1) 00039 * RNOR: normal generator 00040 * REXP: exponential generator, or -log(RUNI) if one isn't available 00041 * INFINITE: function to test whether a value is infinite 00042 00043 Test using: 00044 mean = a 00045 variance = a 00046 skewness = 2/sqrt(a) 00047 kurtosis = 3 + 6/sqrt(a) 00048 00049 Note that randg can be used to generate many distributions: 00050 00051 gamma(a,b) for a>0, b>0 (from R) 00052 r = b*randg(a) 00053 beta(a,b) for a>0, b>0 00054 r1 = randg(a,1) 00055 r = r1 / (r1 + randg(b,1)) 00056 Erlang(a,n) 00057 r = a*randg(n) 00058 chisq(df) for df>0 00059 r = 2*randg(df/2) 00060 t(df) for 0<df<inf (use randn if df is infinite) 00061 r = randn() / sqrt(2*randg(df/2)/df) 00062 F(n1,n2) for 0<n1, 0<n2 00063 r1 = 2*randg(n1/2)/n1 or 1 if n1 is infinite 00064 r2 = 2*randg(n2/2)/n2 or 1 if n2 is infinite 00065 r = r1 / r2 00066 negative binonial (n, p) for n>0, 0<p<=1 00067 r = randp((1-p)/p * randg(n)) 00068 (from R, citing Devroye(1986), Non-Uniform Random Variate Generation) 00069 non-central chisq(df,L), for df>=0 and L>0 (use chisq if L=0) 00070 r = randp(L/2) 00071 r(r>0) = 2*randg(r(r>0)) 00072 r(df>0) += 2*randg(df(df>0)/2) 00073 (from R, citing formula 29.5b-c in Johnson, Kotz, Balkrishnan(1995)) 00074 Dirichlet(a1,...,ak) for ai > 0 00075 r = (randg(a1),...,randg(ak)) 00076 r = r / sum(r) 00077 (from GSL, citing Law & Kelton(1991), Simulation Modeling and Analysis) 00078 */ 00079 00080 #if defined (HAVE_CONFIG_H) 00081 #include <config.h> 00082 #endif 00083 00084 #include <stdio.h> 00085 00086 #include "lo-ieee.h" 00087 #include "lo-math.h" 00088 #include "randmtzig.h" 00089 #include "randgamma.h" 00090 00091 #undef NAN 00092 #define NAN octave_NaN 00093 #define INFINITE lo_ieee_isinf 00094 #define RUNI oct_randu() 00095 #define RNOR oct_randn() 00096 #define REXP oct_rande() 00097 00098 void 00099 oct_fill_randg (double a, octave_idx_type n, double *r) 00100 { 00101 octave_idx_type i; 00102 /* If a < 1, start by generating gamma(1+a) */ 00103 const double d = (a < 1. ? 1.+a : a) - 1./3.; 00104 const double c = 1./sqrt(9.*d); 00105 00106 /* Handle invalid cases */ 00107 if (a <= 0 || INFINITE(a)) 00108 { 00109 for (i=0; i < n; i++) 00110 r[i] = NAN; 00111 return; 00112 } 00113 00114 for (i=0; i < n; i++) 00115 { 00116 double x, xsq, v, u; 00117 restart: 00118 x = RNOR; 00119 v = (1+c*x); 00120 v *= v*v; 00121 if (v <= 0) 00122 goto restart; /* rare, so don't bother moving up */ 00123 u = RUNI; 00124 xsq = x*x; 00125 if (u >= 1.-0.0331*xsq*xsq && log(u) >= 0.5*xsq + d*(1-v+log(v))) 00126 goto restart; 00127 r[i] = d*v; 00128 } 00129 if (a < 1) 00130 { /* Use gamma(a) = gamma(1+a)*U^(1/a) */ 00131 /* Given REXP = -log(U) then U^(1/a) = exp(-REXP/a) */ 00132 for (i = 0; i < n; i++) 00133 r[i] *= exp(-REXP/a); 00134 } 00135 } 00136 00137 double 00138 oct_randg (double a) 00139 { 00140 double ret; 00141 oct_fill_randg(a,1,&ret); 00142 return ret; 00143 }