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