001/* An actor that outputs a random sequence with a Binomial distribution.
002
003 Copyright (c) 2004-2016 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.actor.lib.colt;
029
030import cern.jet.random.Binomial;
031import ptolemy.actor.parameters.PortParameter;
032import ptolemy.data.BooleanToken;
033import ptolemy.data.DoubleToken;
034import ptolemy.data.IntToken;
035import ptolemy.data.expr.SingletonParameter;
036import ptolemy.data.type.BaseType;
037import ptolemy.kernel.CompositeEntity;
038import ptolemy.kernel.util.IllegalActionException;
039import ptolemy.kernel.util.NameDuplicationException;
040
041///////////////////////////////////////////////////////////////////
042//// Binomial
043
044/**
045 Produce a random sequence with a Binomial distribution.  On each
046 iteration, a new random number is produced.  The output port is of
047 type DoubleToken.  The values that are generated are independent
048 and identically distributed with the mean and the standard
049 deviation given by parameters.  In addition, the seed can be
050 specified as a parameter to control the sequence that is generated.
051
052 <p> This actor instantiates a
053 <a href="http://hoschek.home.cern.ch/hoschek/colt/V1.0.3/doc/cern/jet/random/Binomial.html">cern.jet.random.Binomial</a> object with
054 n, the number of trials (also known as the sample size) set to 1
055 and p, the probability of success, set to 0.5.
056
057 A definition of Binomial by Wolfgang Hoschek can be found at
058 <a href="http://hoschek.home.cern.ch/hoschek/colt/V1.0.3/doc/cern/jet/stat/Probability.html#binomial(int,%20int,%20double)"><code>http://hoschek.home.cern.ch/hoschek/colt/V1.0.3/doc/cern/jet/stat/Probability.html#binomial(int,%20int,%20double)</code></a>:
059 <blockquote>
060 <h3>
061 binomial</h3>
062 <pre>public static double <b>binomial</b>(int&nbsp;k,
063 int&nbsp;n,
064 double&nbsp;p)</pre>
065
066 <p>Returns the sum of the terms <tt>0</tt> through <tt>k</tt> of the Binomial
067 probability density.
068 <pre>   k
069 --  ( n )   j      n-j
070 &gt;   (   )  p  (1-p)
071 --  ( j )
072 j=0
073 </pre>
074 The terms are not summed directly; instead the incomplete
075 beta integral is employed, according to the formula
076 <p>
077 <tt>y = binomial( k, n, p ) = Gamma.incompleteBeta( n-k, k+1, 1-p )</tt>.
078 </p><p>
079
080 All arguments must be positive,</p>
081 <p><b>Parameters:</b>
082 <br><code>k</code> - end term.
083 <br><code>n</code> - the number of trials.
084 <br><code>p</code> - the probability of success (must be in <tt>(0.0,1.0)</tt>).
085 </blockquote>
086 The above description of binomial() is
087 <a href="doc-files/colt-copyright.htm">copyrighted</a>.
088
089 @author David Bauer and Kostas Oikonomou
090 @version $Id$
091 @since Ptolemy II 4.1
092 @Pt.ProposedRating Red (cxh)
093 @Pt.AcceptedRating Red (cxh)
094 */
095public class ColtBinomial extends ColtRandomSource {
096    /** Construct an actor with the given container and name.
097     *  @param container The container.
098     *  @param name The name of this actor.
099     *  @exception IllegalActionException If the actor cannot be contained
100     *   by the proposed container.
101     *  @exception NameDuplicationException If the container already has an
102     *   actor with this name.
103     */
104    public ColtBinomial(CompositeEntity container, String name)
105            throws NameDuplicationException, IllegalActionException {
106        super(container, name);
107
108        output.setTypeEquals(BaseType.INT);
109
110        n = new PortParameter(this, "n", new IntToken(1));
111        n.setTypeEquals(BaseType.INT);
112        new SingletonParameter(n.getPort(), "_showName")
113                .setToken(BooleanToken.TRUE);
114
115        p = new PortParameter(this, "p", new DoubleToken(0.5));
116        p.setTypeEquals(BaseType.DOUBLE);
117        new SingletonParameter(p.getPort(), "_showName")
118                .setToken(BooleanToken.TRUE);
119
120        p.moveToFirst();
121        n.moveToFirst();
122    }
123
124    ///////////////////////////////////////////////////////////////////
125    ////                     ports and parameters                  ////
126
127    /** n.
128     *  This has type int with default 1.
129     */
130    public PortParameter n;
131
132    /** p.
133     *  This has type double with default 0.5.
134     */
135    public PortParameter p;
136
137    ///////////////////////////////////////////////////////////////////
138    ////                         public methods                    ////
139
140    /** Send a random number with a Binomial distribution to the output.
141     *  This number is only changed in the prefire() method, so it will
142     *  remain constant throughout an iteration.
143     *  @exception IllegalActionException If there is no director.
144     */
145    @Override
146    public void fire() throws IllegalActionException {
147        n.update();
148        p.update();
149        super.fire();
150        output.send(0, new IntToken(_current));
151    }
152
153    ///////////////////////////////////////////////////////////////////
154    ////                         protected methods                 ////
155
156    /** Method that is called after _randomNumberGenerator is changed.
157     */
158    @Override
159    protected void _createdNewRandomNumberGenerator() {
160        _generator = new Binomial(1, 0.5, _randomNumberGenerator);
161    }
162
163    /** Generate a new random number.
164     *  @exception IllegalActionException If parameter values are incorrect.
165     */
166    @Override
167    protected void _generateRandomNumber() throws IllegalActionException {
168
169        // The following logic protects the binomial generation call
170        // because the Colt library will throw an exception (even
171        // though they are valid limit cases).  The limits can occur
172        // during the course of a simulation, and this actor should
173        // produce valid results if they do occur.
174
175        int nValue = ((IntToken) n.getToken()).intValue();
176        if (nValue == 0) {
177            _current = 0;
178        } else {
179            double pValue = ((DoubleToken) p.getToken()).doubleValue();
180            if (pValue == 0.0) {
181                _current = 0;
182            } else if (pValue == 1.0) {
183                _current = nValue;
184            } else {
185                _current = _generator.nextInt(nValue, pValue);
186            }
187        }
188    }
189
190    ///////////////////////////////////////////////////////////////////
191    ////                         private variables                 ////
192
193    /** The random number for the current iteration. */
194    private int _current;
195
196    /** The random number generator. */
197    private Binomial _generator;
198}