001: import java.awt.*;
002: import java.awt.event.*;
003: import JSci.awt.*;
004: import JSci.maths.statistics.*;
005:
006: /**
007: * DistributionGenerator generates random numbers from a probability distribution.
008: * @author Mark Hale
009: * @version 1.1
010: */
011: public final class DistributionGenerator extends Frame implements
012: Runnable {
013: private final double mean;
014: private final double width;
015: private final ProbabilityDistribution dist;
016: private final HistogramModel model;
017:
018: public static void main(String arg[]) {
019: // set distribution here
020: DistributionGenerator app = new DistributionGenerator(
021: new CauchyDistribution(), 0.0, 10.0);
022: // DistributionGenerator app=new DistributionGenerator(new PoissonDistribution(50.0), 50.0, 100.0);
023: Thread thr = new Thread(app);
024: thr.setPriority(Thread.MIN_PRIORITY);
025: thr.start();
026: }
027:
028: /**
029: * Constructs a distribution generator.
030: * @param pd a probability distribution
031: * @param m the mean of the sampling region
032: * @param w the width of the sampling region
033: */
034: public DistributionGenerator(ProbabilityDistribution pd, double m,
035: double w) {
036: super ("Distribution Generator");
037: dist = pd;
038: mean = m;
039: width = w;
040: model = new HistogramModel();
041: ScatterGraph graph = new ScatterGraph(model);
042: addWindowListener(new WindowAdapter() {
043: public void windowClosing(WindowEvent evt) {
044: dispose();
045: System.exit(0);
046: }
047: });
048: add(graph);
049: setSize(300, 300);
050: setVisible(true);
051: }
052:
053: public void run() {
054: for (int i = 0; i < 10000; i++)
055: model.add(random());
056: }
057:
058: /**
059: * Returns a random number from the distribution.
060: * Uses the rejection method.
061: */
062: public double random() {
063: /*
064: * We use the uniform function f(x)=1 to be totally general.
065: * For greater efficiency use a function f(x) which roughly
066: * over-approximates the required distribution.
067: */
068: double x, y;
069: do {
070: /*
071: * random x coordinate:
072: * x is such that int(f(s),min,x,ds) = Math.random()*int(f(s),min,max,ds)
073: */
074: // uniform comparison function
075: x = mean + width * (Math.random() - 0.5);
076: // Lorentzian comparison function
077: // x=mean+Math.tan(Math.PI*Math.random());
078: // uncomment line below if using a discrete distribution
079: // x=Math.floor(x);
080: /*
081: * random y coordinate:
082: * y = Math.random()*f(x)
083: */
084: // uniform comparison function
085: y = Math.random();
086: // Lorentzian comparison function
087: // y=Math.random()/(1.0+(x-mean)*(x-mean));
088: } while (y > dist.probability(x));
089: return x;
090: }
091:
092: private class HistogramModel extends AbstractGraphModel implements
093: Graph2DModel {
094: private final int histogram[] = new int[101];
095: private final double binwidth = width / (histogram.length - 1);
096:
097: public HistogramModel() {
098: }
099:
100: public float getXCoord(int i) {
101: return (float) (binwidth
102: * (i - (histogram.length - 1) / 2.0) + mean);
103: }
104:
105: public float getYCoord(int i) {
106: return histogram[i];
107: }
108:
109: public int seriesLength() {
110: return histogram.length;
111: }
112:
113: public void firstSeries() {
114: }
115:
116: public boolean nextSeries() {
117: return false;
118: }
119:
120: public void add(double x) {
121: int bin = (int) ((x - mean) / binwidth)
122: + (histogram.length - 1) / 2;
123: if (bin >= 0 && bin < histogram.length) {
124: histogram[bin]++;
125: fireGraphSeriesUpdated(0);
126: }
127: }
128: }
129: }
|