1
2
3
4 package org.lcsim.math.probability;
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 public class BivariateDistribution {
22
23 private int _nx;
24 private int _ny;
25 private double _xmin;
26 private double _ymin;
27 private double _dx;
28 private double _dy;
29 private double[] _h;
30 private double[] _k;
31
32
33 private double[] _w6 = {0.1713244923791705, 0.3607615730481384, 0.4679139345726904};
34 private double[] _x6 = {0.9324695142031522, 0.6612093864662647, 0.2386191860831970};
35
36
37 private double[] _w12 = {.04717533638651177, 0.1069393259953183, 0.1600783285433464,
38 0.2031674267230659, 0.2334925365383547, 0.2491470458134029};
39 private double[] _x12 = {0.9815606342467191, 0.9041172563704750, 0.7699026741943050,
40 0.5873179542866171, 0.3678314989981802, 0.1252334085114692};
41
42
43 private double[] _w20 = {.01761400713915212, .04060142980038694, .06267204833410906,
44 .08327674157670475, 0.1019301198172404, 0.1181945319615184,
45 0.1316886384491766, 0.1420961093183821, 0.1491729864726037,
46 0.1527533871307259};
47 private double[] _x20 = {0.9931285991850949, 0.9639719272779138, 0.9122344282513259,
48 0.8391169718222188, 0.7463319064601508, 0.6360536807265150,
49 0.5108670019508271, 0.3737060887154196, 0.2277858511416451,
50 0.07652652113349733};
51
52
53
54
55
56
57
58
59 public void xBins(int nx, double xmin, double dx) {
60 _nx = nx;
61 _xmin = xmin;
62 _dx = dx;
63 _h = new double[_nx + 1];
64 }
65
66
67
68
69
70
71
72
73 public void yBins(int ny, double ymin, double dy) {
74 _ny = ny;
75 _ymin = ymin;
76 _dy = dy;
77 _k = new double[_ny + 1];
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 public double[][] Calculate(double x0, double y0, double sigx, double sigy,
96 double rho) {
97
98
99 for (int i = 0; i < _nx + 1; i++) {
100 _h[i] = (_xmin + i * _dx - x0) / sigx;
101 }
102
103
104 for (int j = 0; j < _ny + 1; j++) {
105 _k[j] = (_ymin + j * _dy - y0) / sigy;
106 }
107
108
109 double[][] bi = new double[_nx][_ny];
110
111
112 for (int i = 0; i < _nx + 1; i++) {
113 for (int j = 0; j < _ny + 1; j++) {
114
115
116 double prob = GenzCalc(_h[i], _k[j], rho);
117
118
119
120
121
122 if (i > 0 && j > 0) {
123 bi[i - 1][j - 1] += prob;
124 }
125 if (i > 0 && j < _ny) {
126 bi[i - 1][j] -= prob;
127 }
128 if (i < _nx && j > 0) {
129 bi[i][j - 1] -= prob;
130 }
131 if (i < _nx && j < _ny) {
132 bi[i][j] += prob;
133 }
134 }
135 }
136
137 return bi;
138 }
139
140 private double GenzCalc(double dh, double dk, double rho) {
141
142 double twopi = 2. * Math.PI;
143
144
145 int ng;
146 double[] w;
147 double[] x;
148
149 if (Math.abs(rho) < 0.3) {
150
151 ng = 3;
152 w = _w6;
153 x = _x6;
154 } else if (Math.abs(rho) < 0.75) {
155
156 ng = 6;
157 w = _w12;
158 x = _x12;
159 } else {
160
161 ng = 10;
162 w = _w20;
163 x = _x20;
164 }
165
166
167 double bvn = 0.;
168 double h = dh;
169 double k = dk;
170 double hk = h * k;
171
172
173 if (Math.abs(rho) < 0.925) {
174
175
176
177
178
179 double hs = (h * h + k * k) / 2.;
180 double asr = Math.asin(rho);
181 double sn;
182 for (int i = 0; i < ng; i++) {
183 sn = Math.sin(asr * (1 - x[i]) / 2.);
184 bvn += w[i] * Math.exp((sn * hk - hs) / (1 - sn * sn));
185 sn = Math.sin(asr * (1 + x[i]) / 2.);
186 bvn += w[i] * Math.exp((sn * hk - hs) / (1 - sn * sn));
187 }
188
189
190 bvn = bvn * asr / (2. * twopi) + Erf.phi(-h) * Erf.phi(-k);
191
192 } else {
193
194
195
196
197
198 if (rho < 0.) {
199 k = -k;
200 hk = -hk;
201 }
202
203 if (Math.abs(rho) < 1.) {
204
205 double as = (1 - rho) * (1 + rho);
206 double a = Math.sqrt(as);
207 double bs = (h - k) * (h - k);
208 double c = (4. - hk) / 8.;
209 double d = (12. - hk) / 16.;
210 double asr = -(bs / as + hk) / 2.;
211
212 if (asr > -100.) {
213 bvn = a * Math.exp(asr) *
214 (1. - c * (bs - as) * (1. - d * bs / 5.) / 3. +
215 c * d * as * as / 5.);
216 }
217
218 if (-hk < 100.) {
219 double b = Math.sqrt(bs);
220 bvn -= Math.exp(-hk / 2.) * Math.sqrt(twopi) * Erf.phi(-b / a) *
221 b * (1 - c * bs * (1 - d * bs / 5.) / 3.);
222 }
223
224 a = a / 2.;
225 for (int i = 0; i < ng; i++) {
226 for (int j = 0; j < 2; j++) {
227 int is = -1;
228 if (j > 0) {
229 is = 1;
230 }
231 double xs = Math.pow(a * (is * x[i] + 1), 2);
232 double rs = Math.sqrt(1 - xs);
233 asr = -(bs / xs + hk) / 2;
234
235 if (asr > -100) {
236 double sp = (1 + c * xs * (1 + d * xs));
237 double ep = Math.exp(-hk * (1 - rs) / (2 * (1 + rs))) / rs;
238 bvn += a * w[i] * Math.exp(asr) * (ep - sp);
239 }
240 }
241 }
242
243 bvn = -bvn / twopi;
244 }
245
246 if (rho > 0) {
247 bvn = bvn + Erf.phi(-Math.max(h, k));
248 } else {
249 bvn = -bvn;
250 if (k > h) {
251 bvn += Erf.phi(k) - Erf.phi(h);
252 }
253 }
254 }
255
256 return Math.max(0, Math.min(1, bvn));
257 }
258 }