001/* Base class for Colt Random Sources.
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 java.util.Random;
031
032import cern.jet.random.engine.DRand;
033import cern.jet.random.engine.MersenneTwister;
034import edu.cornell.lassp.houle.RngPack.RandomElement;
035import edu.cornell.lassp.houle.RngPack.Ranecu;
036import edu.cornell.lassp.houle.RngPack.Ranlux;
037import edu.cornell.lassp.houle.RngPack.Ranmar;
038import ptolemy.actor.lib.RandomSource;
039import ptolemy.actor.parameters.SharedParameter;
040import ptolemy.data.LongToken;
041import ptolemy.data.StringToken;
042import ptolemy.data.Token;
043import ptolemy.kernel.CompositeEntity;
044import ptolemy.kernel.util.Attribute;
045import ptolemy.kernel.util.IllegalActionException;
046import ptolemy.kernel.util.NameDuplicationException;
047
048///////////////////////////////////////////////////////////////////
049//// ColtRandomSource
050
051/** Base class for Colt random sources.
052 This base class manages the choice of
053 random number generator class.  When the random number
054 generator class is set for any one actor in a model,
055 it gets set to match in all other actors within the
056 same top-level container (unless this actor is within
057 an EntityLibrary).
058
059 @author David Bauer, Kostas Oikonomou, and Edward A. Lee
060 @version $Id$
061 @since Ptolemy II 4.1
062 @Pt.ProposedRating Yellow (eal)
063 @Pt.AcceptedRating Red (cxh)
064 */
065public abstract class ColtRandomSource extends RandomSource {
066    /** Construct an actor with the given container and name.
067     *  @param container The container.
068     *  @param name The name of this actor.
069     *  @exception IllegalActionException If the actor cannot be contained
070     *   by the proposed container.
071     *  @exception NameDuplicationException If the container already has an
072     *   actor with this name.
073     */
074    public ColtRandomSource(CompositeEntity container, String name)
075            throws NameDuplicationException, IllegalActionException {
076        super(container, name);
077
078        generatorClass = new SharedParameter(this, "generatorClass",
079                ColtRandomSource.class, "DRand");
080        generatorClass.setStringMode(true);
081
082        generatorClass.addChoice("DRand");
083        generatorClass.addChoice("MersenneTwister (MT19937)");
084        generatorClass.addChoice("Ranecu");
085        generatorClass.addChoice("Ranlux");
086        generatorClass.addChoice("Ranmar");
087    }
088
089    ///////////////////////////////////////////////////////////////////
090    ////                         ports and parameter               ////
091
092    /** The low-level random number generator (RNG) class name.
093     *  This is a string that defaults to "DRand".
094     *  Below are possible values for this parameter and links
095     *  to pages that define the meaning of the parameter.
096     *  This is a "shared parameter", which means that
097     *  changing this parameter in any one actor will cause
098     *  a similar change to be applied to all other Colt
099     *  actors within the same top level (unless this is in
100     *  a library).
101     *  <menu>
102     *  <li><code>"DRand"</code>
103     *  (<a href="http://hoschek.home.cern.ch/hoschek/colt/V1.0.3/doc/cern/jet/random/engine/DRand.html#in_browser">Definition</a>)
104     *  <li><code>"MersenneTwister (MT19937)"</code>
105     *  (<a href="http://hoschek.home.cern.ch/hoschek/colt/V1.0.3/doc/cern/jet/random/engine/MersenneTwister.html#in_browser">Definition</a>)
106     *  <li><code>"Ranecu""</code>
107     *  (<a href="http://hoschek.home.cern.ch/hoschek/colt/V1.0.3/doc/edu/cornell/lassp/houle/RngPack/Ranecu.html#in_browser">Definition</a>)
108     *  <li><code>"Ranlux"</code>
109     *  (<a href="http://hoschek.home.cern.ch/hoschek/colt/V1.0.3/doc/cern/jet/random/engine/Ranlux.html#in_browser">Definition</a>)
110     *  <li><code>"Ranmar"</code>
111     *  (<a href="http://hoschek.home.cern.ch/hoschek/colt/V1.0.3/doc/cern/jet/random/engine/Ranmar.html#in_browser">Definition</a>)
112     *  </menu>
113     */
114    public SharedParameter generatorClass;
115
116    ///////////////////////////////////////////////////////////////////
117    ////                         public methods                    ////
118
119    /** If the attribute is <i>generatorClass</i>
120     *  then create the base random number generator.
121     *  @param attribute The attribute that changed.
122     *  @exception IllegalActionException If the change is not acceptable
123     *   to this container (not thrown in this base class).
124     */
125    @Override
126    public void attributeChanged(Attribute attribute)
127            throws IllegalActionException {
128        if (attribute == generatorClass) {
129            String generatorClassValue = ((StringToken) generatorClass
130                    .getToken()).stringValue();
131
132            if (generatorClassValue != null
133                    && !generatorClassValue.equals(_generatorClassName)) {
134                _needNewGenerator = true;
135            }
136        } else {
137            super.attributeChanged(attribute);
138        }
139    }
140
141    ///////////////////////////////////////////////////////////////////
142    ////                         protected methods                 ////
143
144    /** Method that is called after _randomNumberGenerator is changed. */
145    protected abstract void _createdNewRandomNumberGenerator();
146
147    /** Create the random number generator using current parameter values. */
148    @Override
149    protected void _createGenerator() throws IllegalActionException {
150        long seedValue = ((LongToken) seed.getToken()).longValue();
151        Token token = privateSeed.getToken();
152        if (token != null) {
153            seedValue = ((LongToken) token).longValue();
154            _generatorSeed = seedValue;
155        } else {
156            _generatorSeed = seedValue;
157            if (seedValue == 0L) {
158                seedValue = System.currentTimeMillis() + hashCode();
159            } else {
160                // BTW - the reason to use the full name here is so that
161                // each random number generator generates a sequence
162                // of different random numbers.  If we use just the
163                // display name, then two actors that have the same
164                // name will generate the same sequence of numbers which
165                // is bad for Monte Carlo simulations.
166                // See privateSeed in RandomSource for an alternate
167                // way to set seeds.
168                seedValue = seedValue + getFullName().hashCode();
169            }
170        }
171
172        StringToken generatorToken = (StringToken) generatorClass.getToken();
173        String generatorClassValue = null;
174
175        if (generatorToken != null) {
176            generatorClassValue = generatorToken.stringValue();
177        }
178
179        _generatorClassName = generatorClassValue;
180
181        if (generatorClassValue == null
182                || generatorClassValue.equals("DRand")) {
183            _randomNumberGenerator = new DRand((int) seedValue);
184        } else if (generatorClassValue.equals("MersenneTwister (MT19937)")) {
185            _randomNumberGenerator = new MersenneTwister((int) seedValue);
186        } else if (generatorClassValue.equals("Ranecu")) {
187            _randomNumberGenerator = new Ranecu((int) seedValue);
188        } else if (generatorClassValue.equals("Ranlux")) {
189            _randomNumberGenerator = new Ranlux((int) seedValue);
190        } else if (generatorClassValue.equals("Ranmar")) {
191            _randomNumberGenerator = new Ranmar((int) seedValue);
192        }
193
194        // In the base class, if _random is null, then initialize()
195        // will re-run this method. We don't want this, so even though
196        // we don't need it, we create an instance of Random.
197        _random = new Random();
198        _needNewGenerator = false;
199        _needNew = true;
200
201        _createdNewRandomNumberGenerator();
202    }
203
204    ///////////////////////////////////////////////////////////////////
205    ////                         protected variables               ////
206
207    /** The low-level random number generator.
208     */
209    protected RandomElement _randomNumberGenerator;
210
211    ///////////////////////////////////////////////////////////////////
212    ////                         private variables                 ////
213
214    /** The class name of the current _randomNumberGenerator.
215     */
216    private String _generatorClassName;
217}