For the rejection
method discussed in Chapter
7: Tech and in the section Custom
Probability Distributions in this chapter, we need a function
g(y) to
which we can compare the "second throw" of the uniform
random number generator, if we make an analogy to throwing dice.
If the second throw is equal or below g(y),
the program accepts the value y
obtained in the "first throw".
A histogram
distribution can be modified to act as such a probability distribution
(called experimental distributions in Bisset)
:
pi = ni/N
for bin i
with ni
contents and total histogram entries N.
Then the probability density goes as
p(x) = pi/w = ni/wN
where w
is the bin width and i
= (x - xmin)/w for a histogram of values between
xmin and
xmax.
However, for f(x)
we want to reject as few attempts as possible, so it's more efficient
to normalize to the maximum bin value. That is,
fi = ni/nmax
where nmax
equals the number of entries in the largest bin. Our uniform random
number generator will provide values in the range
xmin < r1 < xmax.
Selecting the bin closes we can compare the second throw to a simple
constant comparison function c(x)=1.
(A comparison function that more closely fits f(x)
will reduce the rejection rate.) If
r2 < fi then the value of the first
throw xmin
< r1 < xmax will be accepted.
In the beam case mentioned in the previous
section, we used a simple function to give us the g(x)
for the rejection method to simulate the distribution of tracks
through a detector. What if the situation was made more complicated
by, say, a beampipe flange that screened out a portion of the tracks.
In this and other real world problems can result in distributions
that can easily be approximated with simple functions.
In such situations, it might be easier to first use
an experimentally obtained distribution, say from a test beam, and
then use the resulting histogram for our rejection method when doing
other simulation studies.
For example, when studying the behavior of one detector
element, I might want to consider only those particle tracks that
traversed sensitive areas of the detector element in front of it.
I could generate such tracks by using the experimentally obtained
distribution for the detector element in front of the one of interest.
The program below shows a similar display as in the
previous example except that a histogram
provides the distribution of track angles. For generating the random
values we use a histogram of facsimile experimental data where some
areas are empty (due perhaps to obstacles in the support structure
of the detector or insensitive areas in the detector.)
As you add entries to the histogram, it will gradually
come to follow more and more closely the experimental data distribution:
RanDistHistApplet.java
- The first histogram holds a distribution that emulates
what one might obtain from an experiment. The second histogram
displays a distribution of random values that follows
the pattern in the first histogram.
+ Previous classes:
Chapter
6:Tech: Histogram.java,
HistPanel.java
Chapter
6:Tech: PlotPanel.java,
PlotFormat.java
|
import
javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* The first histogram holds a distribution
that emulates what one
* might obtain from an experiment.
The second histogram displays
* a distribution of random values
that follows the pattern in
* the first histogram.
*
* The applet uses two instances of
HistPanel to display contents of
* two instances of Histogram.
*
*
* Includes "Go" button to add random
values that follow the data
* histogram distribution. The number
of values taken from
* entry in a JTextField. "Clear" button
clears the histogram.
* In standalone mode, the Exit button
closes the program.
*
* This program will run as an applet
inside
* an application frame.
**/
public class RanDistHistApplet extends JApplet
implements ActionListener
{
// Use the HistPanel JPanel subclass here
HistPanel fOutputPanel;
Histogram fHistogram;
int fNumDataPoints = 1000;
// Create the histogram distribution function.
HistPanel fRanHistPanel;
Histogram fRanHistogram;
int fRanHistBins;
double [] fRanDist;
// Set the angular range for scattered tracks
double fMinAngle;
double fMaxAngle;
double fAngleRange;
// Random number generator
java.util.Random fRan;
// A text field for input strings
JTextField textField = null;
// Flag for whether the applet is in a browser
// or running via the main () below.
boolean fInBrowser = true;
//Buttons
JButton fGoButton;
JButton fClearButton;
JButton fExitButton;
/**
* Create a User Interface with histograms
and buttons to
* control the program. A textfield
holds number of entries
* to be generated for the histogram.
**/
public void init () {
JPanel panel = new JPanel (new BorderLayout
());
// Get the data and make the histogram
to use for
// generating the random distributions.
getRanHist ();
// Create a histogram with Gaussian
distribution.
makeHist ();
// JPanel subclass here.
fOutputPanel = new HistPanel (fHistogram);
fRanHistPanel = new HistPanel (fRanHistogram);
JPanel hists_panel = new JPanel
(new GridLayout (1,2));
hists_panel.add (fRanHistPanel);
hists_panel.add (fOutputPanel);
panel.add (hists_panel,"Center");
// Use a textfield for an input
parameter.
textField =
new JTextField (Integer.toString
(fNumDataPoints), 10);
// If return hit after entering
text, the
// actionPerformed will be invoked.
textField.addActionListener (this);
fGoButton = new JButton ("Go");
fGoButton.addActionListener (this);
fClearButton = new JButton ("Clear");
fClearButton.addActionListener (this);
fExitButton = new JButton ("Exit");
fExitButton.addActionListener (this);
JPanel control_panel = new JPanel
();
control_panel.add (textField);
control_panel.add (fGoButton);
control_panel.add (fClearButton);
control_panel.add (fExitButton);
if (fInBrowser) fExitButton.setEnabled
(false);
panel.add (control_panel,"South");
// Add text area with scrolling
to the contentPane.
add (panel);
} // init
public void actionPerformed (ActionEvent e){
Object source = e.getSource ();
if (source == fGoButton || source
== textField) {
String strNumDataPoints
= textField.getText ();
try {
fNumDataPoints
= Integer.parseInt (strNumDataPoints);
}
catch (NumberFormatException
ex) {
// Could
open an error dialog here but just
// display
a message on the browser status line.
showStatus
("Bad input value");
return;
}
makeHist ();
repaint ();
}
else if (source == fClearButton)
{
fHistogram.clear
();
repaint
();
} else if (!fInBrowser)
System.exit
(0);
} // actionPerformed
/**
* Create a random distribution of
angles to
* simulate the tracks in a particle
scattering
* experiment entering a detector
element.
**/
void makeHist () {
// Create an instance of the Random
class for
// producing our random values.
fRan = new java.util.Random ();
// Create an instance of our basic
histogram class.
// Make it wide enough enough to
include most of the
// gaussian values.
if (fHistogram == null)
fHistogram
= new Histogram ("Ran Dist from Data Histogram",
"Degrees",
50,fMinAngle,fMaxAngle);
// Use the transformation method
to generate a
// radioactive decay distribution
for (int i=0; i < fNumDataPoints;
i++) {
// Generate random vals
0.0 to 1.0
double r1 = fRan.nextDouble
();
double angle = fMinAngle
+ (fMaxAngle-fMinAngle)*r1;
if (acceptAngle (angle)
){
fHistogram.add
(angle);
}
}
} // makeHist
/**
* This method creates
the histogram that will be used to provide
* a random value distribution
that matches a data distribution.
* In this case, the histogram
is made with a fake set of data.
* For an actual experiment,
this routine would obtain the data
* from a file in which
the a histogram filled with real was saved.
**/
void getRanHist (){
// Simulated data for creating the
desired distibution.
int [] ranData =
{ 20, 26,
34, 5, 0, 57, 65, 70, 0, 3,
85, 93,
101, 0, 0, 122, 130, 138, 1, 3,
158, 166,
174, 180, 188};
// Range of the histogram.
fMinAngle = 25.0;
fMaxAngle = 50.0;
fAngleRange = 25.0;
fRanHistBins = ranData.length;
// Create a histogram to provide
the ran number distribution.
fRanHistogram = new Histogram ("Expt.
Data Dist",
"Degrees",
25,fMinAngle,fMaxAngle);
fRanHistogram.pack (ranData, 0,
0, fMinAngle, fMaxAngle);
fRanDist = new double[ranData.length];
int maxVal = fRanHistogram.getMax
();
// Create that comparison function
for generating the
// random distribution.
for (int i=0; i < fRanHistBins;
i++){
fRanDist[i]
= ( (double)ranData[i])/maxVal;
}
} // getRanHist
/**
* This rejection function uses a
simple linear
* function to determine the acceptance
of the
* angle.
**/
boolean acceptAngle (double angle){
if ( angle < fMinAngle || angle
>= fMaxAngle) return false;
double val = angle - fMinAngle;
// Casting to int will round off
to lower
// integer value.
int bin = (int) (fRanHistBins
* (val/fAngleRange) );
double r2 = fRan.nextDouble ();
if ( r2 <= fRanDist[bin]) return
true;
return false;
} // acceptAngle
public static void main (String[] args) {
//
int frame_width=450;
int frame_height=300;
// Create an applet and add it to
a frame.
RanDistHistApplet applet = new RanDistHistApplet
();
applet.fInBrowser = false;
applet.init ();
// Following anonymous class used
to close window & exit program
JFrame f = new JFrame ("Demo");
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
// Add applet to the frame
f.getContentPane ().add ( applet);
f.setSize (new Dimension (frame_width,frame_height));
f.setVisible (true);
} // main
} // RanDistHistApplet
|
References & Web Resources
Most recent update Oct. 22, 2005
|