1 package nl.tudelft.simulation.jstats.distributions;
2
3 import org.djutils.exceptions.Throw;
4 import org.djutils.logger.CategoryLogger;
5
6 import nl.tudelft.simulation.jstats.math.ProbMath;
7 import nl.tudelft.simulation.jstats.streams.StreamInterface;
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 public class DistGamma extends DistContinuous
25 {
26
27 private static final long serialVersionUID = 1L;
28
29
30 private final double shape;
31
32
33 private final double scale;
34
35
36
37
38
39
40
41
42
43
44 public DistGamma(final StreamInterface stream, final double shape, final double scale)
45 {
46 super(stream);
47 Throw.when(shape <= 0.0 || scale <= 0.0, IllegalArgumentException.class, "Error Gamma - shape <= 0.0 or scale <= 0.0");
48 this.shape = shape;
49 this.scale = scale;
50 }
51
52
53 @Override
54 public double draw()
55 {
56
57
58 if (this.shape < 1.0)
59 {
60 double b = (Math.E + this.shape) / Math.E;
61 int counter = 0;
62 while (counter < 1000)
63 {
64
65 double p = b * this.stream.nextDouble();
66 if (p <= 1.0d)
67 {
68
69 double y = Math.pow(p, 1.0d / this.shape);
70 double u2 = this.stream.nextDouble();
71 if (u2 <= Math.exp(-y))
72 {
73 return this.scale * y;
74 }
75 }
76 else
77 {
78
79 double y = -Math.log((b - p) / this.shape);
80 double u2 = this.stream.nextDouble();
81 if (u2 <= Math.pow(y, this.shape - 1.0d))
82 {
83 return this.scale * y;
84 }
85 }
86 counter++;
87 }
88 CategoryLogger.always().info("Gamma distribution -- 1000 tries for alpha<1.0");
89 return 1.0d;
90 }
91 else if (this.shape > 1.0)
92 {
93
94
95 double a = 1.0d / Math.sqrt(2.0d * this.shape - 1.0d);
96 double b = this.shape - Math.log(4.0d);
97 double q = this.shape + (1.0d / a);
98 double theta = 4.5d;
99 double d = 1.0d + Math.log(theta);
100 int counter = 0;
101 while (counter < 1000)
102 {
103
104 double u1 = this.stream.nextDouble();
105 double u2 = this.stream.nextDouble();
106
107 double v = a * Math.log(u1 / (1.0d - u1));
108 double y = this.shape * Math.exp(v);
109 double z = u1 * u1 * u2;
110 double w = b + q * v - y;
111
112 if ((w + d - theta * z) >= 0.0d)
113 {
114 return this.scale * y;
115 }
116
117 if (w > Math.log(z))
118 {
119 return this.scale * y;
120 }
121 counter++;
122 }
123 CategoryLogger.always().info("Gamma distribution -- 1000 tries for alpha>1.0");
124 return 1.0d;
125 }
126 else
127
128 {
129
130 return -this.scale * Math.log(this.stream.nextDouble());
131 }
132 }
133
134
135 @Override
136 public double getProbabilityDensity(final double x)
137 {
138 if (x <= 0)
139 {
140 return 0.0;
141 }
142 return (Math.pow(this.scale, -this.shape) * Math.pow(x, this.shape - 1) * Math.exp(-1 * x / this.scale))
143 / ProbMath.gamma(this.shape);
144 }
145
146
147
148
149 public double getShape()
150 {
151 return this.shape;
152 }
153
154
155
156
157 public double getScale()
158 {
159 return this.scale;
160 }
161
162
163 @Override
164 public String toString()
165 {
166 return "Gamma(" + this.shape + "," + this.scale + ")";
167 }
168 }