1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.math.random;
19
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.FileReader;
23 import java.io.IOException;
24 import java.io.InputStreamReader;
25 import java.io.Serializable;
26 import java.net.URL;
27 import java.util.ArrayList;
28 import java.util.List;
29
30 import org.apache.commons.math.MathRuntimeException;
31 import org.apache.commons.math.stat.descriptive.StatisticalSummary;
32 import org.apache.commons.math.stat.descriptive.SummaryStatistics;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class EmpiricalDistributionImpl implements Serializable, EmpiricalDistribution {
62
63
64 private static final long serialVersionUID = 5729073523949762654L;
65
66
67 private List<SummaryStatistics> binStats = null;
68
69
70 private SummaryStatistics sampleStats = null;
71
72
73 private int binCount = 1000;
74
75
76 private boolean loaded = false;
77
78
79 private double[] upperBounds = null;
80
81
82 private RandomData randomData = new RandomDataImpl();
83
84
85
86
87 public EmpiricalDistributionImpl() {
88 binStats = new ArrayList<SummaryStatistics>();
89 }
90
91
92
93
94
95
96 public EmpiricalDistributionImpl(int binCount) {
97 this.binCount = binCount;
98 binStats = new ArrayList<SummaryStatistics>();
99 }
100
101
102
103
104
105
106
107 public void load(double[] in) {
108 DataAdapter da = new ArrayDataAdapter(in);
109 try {
110 da.computeStats();
111 fillBinStats(in);
112 } catch (Exception e) {
113 throw new MathRuntimeException(e);
114 }
115 loaded = true;
116
117 }
118
119
120
121
122
123
124
125 public void load(URL url) throws IOException {
126 BufferedReader in =
127 new BufferedReader(new InputStreamReader(url.openStream()));
128 try {
129 DataAdapter da = new StreamDataAdapter(in);
130 try {
131 da.computeStats();
132 } catch (IOException ioe) {
133
134 throw ioe;
135 } catch (RuntimeException rte) {
136
137 throw rte;
138 } catch (Exception e) {
139 throw MathRuntimeException.createIOException(e);
140 }
141 if (sampleStats.getN() == 0) {
142 throw MathRuntimeException.createEOFException("URL {0} contains no data",
143 url);
144 }
145 in = new BufferedReader(new InputStreamReader(url.openStream()));
146 fillBinStats(in);
147 loaded = true;
148 } finally {
149 try {
150 in.close();
151 } catch (IOException ex) {
152
153 }
154 }
155 }
156
157
158
159
160
161
162
163 public void load(File file) throws IOException {
164 BufferedReader in = new BufferedReader(new FileReader(file));
165 try {
166 DataAdapter da = new StreamDataAdapter(in);
167 try {
168 da.computeStats();
169 } catch (IOException ioe) {
170
171 throw ioe;
172 } catch (RuntimeException rte) {
173
174 throw rte;
175 } catch (Exception e) {
176 throw MathRuntimeException.createIOException(e);
177 }
178 in = new BufferedReader(new FileReader(file));
179 fillBinStats(in);
180 loaded = true;
181 } finally {
182 try {
183 in.close();
184 } catch (IOException ex) {
185
186 }
187 }
188 }
189
190
191
192
193
194 private abstract class DataAdapter{
195
196
197
198
199
200
201
202 public abstract void computeBinStats(double min, double delta)
203 throws Exception;
204
205
206
207
208
209 public abstract void computeStats() throws Exception;
210 }
211
212
213
214
215
216 private class DataAdapterFactory{
217
218
219
220
221
222
223 public DataAdapter getAdapter(Object in) {
224 if (in instanceof BufferedReader) {
225 BufferedReader inputStream = (BufferedReader) in;
226 return new StreamDataAdapter(inputStream);
227 } else if (in instanceof double[]) {
228 double[] inputArray = (double[]) in;
229 return new ArrayDataAdapter(inputArray);
230 } else {
231 throw MathRuntimeException.createIllegalArgumentException(
232 "input data comes from unsupported datasource: {0}, " +
233 "supported sources: {1}, {2}",
234 in.getClass().getName(),
235 BufferedReader.class.getName(), double[].class.getName());
236 }
237 }
238 }
239
240
241
242 private class StreamDataAdapter extends DataAdapter{
243
244
245 private BufferedReader inputStream;
246
247
248
249
250
251
252 public StreamDataAdapter(BufferedReader in){
253 super();
254 inputStream = in;
255 }
256
257
258
259
260
261
262
263 @Override
264 public void computeBinStats(double min, double delta)
265 throws IOException {
266 String str = null;
267 double val = 0.0d;
268 while ((str = inputStream.readLine()) != null) {
269 val = Double.parseDouble(str);
270 SummaryStatistics stats = binStats.get(findBin(min, val, delta));
271 stats.addValue(val);
272 }
273
274 inputStream.close();
275 inputStream = null;
276 }
277
278
279
280
281
282 @Override
283 public void computeStats() throws IOException {
284 String str = null;
285 double val = 0.0;
286 sampleStats = new SummaryStatistics();
287 while ((str = inputStream.readLine()) != null) {
288 val = Double.valueOf(str).doubleValue();
289 sampleStats.addValue(val);
290 }
291 inputStream.close();
292 inputStream = null;
293 }
294 }
295
296
297
298
299 private class ArrayDataAdapter extends DataAdapter{
300
301
302 private double[] inputArray;
303
304
305
306
307
308
309 public ArrayDataAdapter(double[] in){
310 super();
311 inputArray = in;
312 }
313
314
315
316
317
318 @Override
319 public void computeStats() throws IOException {
320 sampleStats = new SummaryStatistics();
321 for (int i = 0; i < inputArray.length; i++) {
322 sampleStats.addValue(inputArray[i]);
323 }
324 }
325
326
327
328
329
330
331
332 @Override
333 public void computeBinStats(double min, double delta)
334 throws IOException {
335 for (int i = 0; i < inputArray.length; i++) {
336 SummaryStatistics stats =
337 binStats.get(findBin(min, inputArray[i], delta));
338 stats.addValue(inputArray[i]);
339 }
340 }
341 }
342
343
344
345
346
347
348
349 private void fillBinStats(Object in) throws IOException {
350
351 double min = sampleStats.getMin();
352 double max = sampleStats.getMax();
353 double delta = (max - min)/(Double.valueOf(binCount)).doubleValue();
354 double[] binUpperBounds = new double[binCount];
355 binUpperBounds[0] = min + delta;
356 for (int i = 1; i< binCount - 1; i++) {
357 binUpperBounds[i] = binUpperBounds[i-1] + delta;
358 }
359 binUpperBounds[binCount -1] = max;
360
361
362 if (!binStats.isEmpty()) {
363 binStats.clear();
364 }
365 for (int i = 0; i < binCount; i++) {
366 SummaryStatistics stats = new SummaryStatistics();
367 binStats.add(i,stats);
368 }
369
370
371 DataAdapterFactory aFactory = new DataAdapterFactory();
372 DataAdapter da = aFactory.getAdapter(in);
373 try {
374 da.computeBinStats(min, delta);
375 } catch (IOException ioe) {
376
377 throw ioe;
378 } catch (RuntimeException rte) {
379
380 throw rte;
381 } catch (Exception e) {
382 throw MathRuntimeException.createIOException(e);
383 }
384
385
386 upperBounds = new double[binCount];
387 upperBounds[0] =
388 ((double) binStats.get(0).getN()) / (double) sampleStats.getN();
389 for (int i = 1; i < binCount-1; i++) {
390 upperBounds[i] = upperBounds[i-1] +
391 ((double) binStats.get(i).getN()) / (double) sampleStats.getN();
392 }
393 upperBounds[binCount-1] = 1.0d;
394 }
395
396
397
398
399
400
401
402
403
404 private int findBin(double min, double value, double delta) {
405 return Math.min(
406 Math.max((int) Math.ceil((value- min) / delta) - 1, 0),
407 binCount - 1);
408 }
409
410
411
412
413
414
415
416 public double getNextValue() throws IllegalStateException {
417
418 if (!loaded) {
419 throw MathRuntimeException.createIllegalStateException("distribution not loaded");
420 }
421
422
423 double x = Math.random();
424
425
426 for (int i = 0; i < binCount; i++) {
427 if (x <= upperBounds[i]) {
428 SummaryStatistics stats = binStats.get(i);
429 if (stats.getN() > 0) {
430 if (stats.getStandardDeviation() > 0) {
431 return randomData.nextGaussian
432 (stats.getMean(),stats.getStandardDeviation());
433 } else {
434 return stats.getMean();
435 }
436 }
437 }
438 }
439 throw new MathRuntimeException("no bin selected");
440 }
441
442
443
444
445
446
447
448
449
450 public StatisticalSummary getSampleStats() {
451 return sampleStats;
452 }
453
454
455
456
457
458
459 public int getBinCount() {
460 return binCount;
461 }
462
463
464
465
466
467
468
469
470 public List<SummaryStatistics> getBinStats() {
471 return binStats;
472 }
473
474
475
476
477
478
479
480
481
482 public double[] getUpperBounds() {
483 int len = upperBounds.length;
484 double[] out = new double[len];
485 System.arraycopy(upperBounds, 0, out, 0, len);
486 return out;
487 }
488
489
490
491
492
493
494 public boolean isLoaded() {
495 return loaded;
496 }
497 }