Added static RNGs, like ExponentialVariable::GetSingleValue(mean)
authorRaj Bhattacharjea <raj.b@gatech.edu>
Thu, 03 May 2007 14:19:33 -0400
changeset 442 96d3e7dc8bb2
parent 441 d824620eac38
child 523 eb380b33ae24
Added static RNGs, like ExponentialVariable::GetSingleValue(mean)
src/core/random-variable.cc
src/core/random-variable.h
--- a/src/core/random-variable.cc	Wed May 02 15:23:35 2007 -0400
+++ b/src/core/random-variable.cc	Thu May 03 14:19:33 2007 -0400
@@ -44,16 +44,33 @@
 
 uint32_t      RandomVariable::runNumber = 0;
 bool          RandomVariable::initialized = false;   // True if RngStream seed set 
-bool          RandomVariable::useDevRandom = false;  // True if use /dev/random desired
+bool          RandomVariable::useDevRandom = false;  // True if use /dev/random
 bool          RandomVariable::globalSeedSet = false; // True if GlobalSeed called
 int           RandomVariable::devRandom = -1;
-uint32_t        RandomVariable::globalSeed[6];
+uint32_t      RandomVariable::globalSeed[6];
 unsigned long RandomVariable::heuristic_sequence;
+RngStream*    RandomVariable::m_static_generator = 0;
+
+//the static object random_variable_initializer initializes the static members
+//of RandomVariable
+static class RandomVariableInitializer
+{
+  public:
+  RandomVariableInitializer()
+  {
+    RandomVariable::Initialize(); // sets the static package seed
+    RandomVariable::m_static_generator = new RngStream();
+    RandomVariable::m_static_generator->InitializeStream();
+  }
+  ~RandomVariableInitializer()
+  {
+    delete RandomVariable::m_static_generator;
+  }
+} random_variable_initializer;
 
 RandomVariable::RandomVariable() 
 {
   m_generator = new RngStream();
-  RandomVariable::Initialize(); // sets the seed for the static object
   m_generator->InitializeStream();
   m_generator->ResetNthSubstream(RandomVariable::runNumber);
 }
@@ -173,7 +190,7 @@
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-// UniformVariable methods
+// UniformVariable
 UniformVariable::UniformVariable() 
   : m_min(0), m_max(1.0) { }
   
@@ -192,6 +209,12 @@
 {
   return new UniformVariable(*this);
 }
+
+double UniformVariable::GetSingleValue(double s, double l)
+{
+  return s + m_static_generator->RandU01() * (l - s);;
+}
+
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // ConstantVariable methods
@@ -291,6 +314,12 @@
 {
   return new ExponentialVariable(*this);
 }
+double ExponentialVariable::GetSingleValue(double m, double b/*=0*/)
+{
+  double r = -m*log(m_static_generator->RandU01());
+  if (b != 0 && r > b) return b;
+  return r;
+}
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // ParetoVariable methods
@@ -322,6 +351,14 @@
 {
   return new ParetoVariable(*this);
 }
+
+double ParetoVariable::GetSingleValue(double m, double s, double b/*=0*/)
+{
+  double scale = m * ( s - 1.0) / s;
+  double r = (scale * ( 1.0 / pow(m_static_generator->RandU01(), 1.0 / s)));
+  if (b != 0 && r > b) return b;
+  return r;
+}
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // WeibullVariable methods
@@ -348,14 +385,25 @@
 {
   return new WeibullVariable(*this);
 }
+
+double WeibullVariable::GetSingleValue(double m, double s, double b/*=0*/)
+{
+  double exponent = 1.0 / s;
+  double r = m * pow( -log(m_static_generator->RandU01()), exponent);
+  if (b != 0 && r > b) return b;
+  return r;
+}
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // NormalVariable methods
+bool         NormalVariable::m_static_nextValid = false;
+double       NormalVariable::m_static_next;
 const double NormalVariable::INFINITE_VALUE = 1e307;
+
 NormalVariable::NormalVariable() 
   : m_mean(0.0), m_variance(1.0), m_bound(INFINITE_VALUE), m_nextValid(false){}
 
-NormalVariable::NormalVariable(double m, double v, double b)
+NormalVariable::NormalVariable(double m, double v, double b/*=INFINITE_VALUE*/)
   : m_mean(m), m_variance(v), m_bound(b), m_nextValid(false) { }
 
 NormalVariable::NormalVariable(const NormalVariable& c)
@@ -395,6 +443,34 @@
   return new NormalVariable(*this);
 }
 
+double NormalVariable::GetSingleValue(double m, double v, double b)
+{
+  if (m_static_nextValid)
+    { // use previously generated
+      m_static_nextValid = false;
+      return m_static_next;
+    }
+  while(1)
+    { // See Simulation Modeling and Analysis p. 466 (Averill Law)
+      // for algorithm
+      double u1 = m_static_generator->RandU01();
+      double u2 = m_static_generator->RandU01();;
+      double v1 = 2 * u1 - 1;
+      double v2 = 2 * u2 - 1;
+      double w = v1 * v1 + v2 * v2;
+      if (w <= 1.0)
+        { // Got good pair
+          double y = sqrt((-2 * log(w))/w);
+          m_static_next = m + v2 * y * sqrt(v);
+          if (fabs(m_static_next) > b) m_static_next = b * (m_static_next)/fabs(m_static_next);
+          m_static_nextValid = true;
+          double x1 = m + v1 * y * sqrt(v);
+          if (fabs(x1) > b) x1 = b * (x1)/fabs(x1);
+          return x1;
+        }
+    }
+}
+
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // ValueCDF methods
@@ -533,9 +609,8 @@
 }
 
 LogNormalVariable::LogNormalVariable (double mu, double sigma)
+    :m_mu(mu), m_sigma(sigma) 
 {
-  m_mu = mu;
-  m_sigma = sigma;
 }
 
 // The code from this function was adapted from the GNU Scientific
@@ -588,5 +663,26 @@
   return z;
 }
 
+double LogNormalVariable::GetSingleValue(double sigma,double mu)
+{
+  double u, v, r2, normal, z;
+  do
+    {
+      /* choose x,y in uniform square (-1,-1) to (+1,+1) */
+      u = -1 + 2 * m_static_generator->RandU01 ();
+      v = -1 + 2 * m_static_generator->RandU01 ();
+
+      /* see if it is in the unit circle */
+      r2 = u * u + v * v;
+    }
+  while (r2 > 1.0 || r2 == 0);
+
+  normal = u * sqrt (-2.0 * log (r2) / r2);
+
+  z =  exp (sigma * normal + mu);
+
+  return z;
+}
+
 }//namespace ns3
 
--- a/src/core/random-variable.h	Wed May 02 15:23:35 2007 -0400
+++ b/src/core/random-variable.h	Thu May 03 14:19:33 2007 -0400
@@ -182,8 +182,10 @@
   static int  devRandom;       // File handle for /dev/random
   static uint32_t globalSeed[6]; // The global seed to use
   static uint32_t runNumber;
+  friend class RandomVariableInitializer;
 protected:
   static unsigned long heuristic_sequence;
+  static RngStream* m_static_generator;
   RngStream* m_generator;  //underlying generator being wrapped
 };
 
@@ -191,6 +193,13 @@
 /**
  * \brief The uniform distribution RNG for NS-3.
  * \ingroup randomvariable
+ * This class supports the creation of objects that return random numbers
+ * from a fixed uniform distribution.  It also supports the generation of 
+ * single random numbers from various uniform distributions.
+ * \code
+ * UniformVariable x(0,10);
+ * x.GetValue();  //will always return numbers [0,10]
+ * UniformVariable::GetSingleValue(100,1000); //returns a value [100,1000]
  */
 class UniformVariable : public RandomVariable {
 public:
@@ -214,6 +223,13 @@
    */
   virtual double GetValue();
   virtual RandomVariable*  Copy() const;
+public:
+  /**
+   * \param s Low end of the range
+   * \param l High end of the range
+   * \return A uniformly distributed random number between s and l
+   */
+  static double GetSingleValue(double s, double l);
 private:
   double m_min;
   double m_max;
@@ -317,8 +333,16 @@
 /**
  * \brief Exponentially Distributed random var
  * \ingroup randomvariable
+ * This class supports the creation of objects that return random numbers
+ * from a fixed exponential distribution.  It also supports the generation of 
+ * single random numbers from various exponential distributions.
+ * \code
+ * ExponentialVariable x(3.14);
+ * x.GetValue();  //will always return with mean 3.14
+ * ExponentialVariable::GetSingleValue(20.1); //returns with mean 20.1
+ * ExponentialVariable::GetSingleValue(108); //returns with mean 108
+ * \endcode
  *
- * ExponentialVariable defines a random variable with an exponential distribution
  */
 class ExponentialVariable : public RandomVariable { 
 public:
@@ -354,6 +378,13 @@
    */
   virtual double GetValue();
   virtual RandomVariable* Copy() const;
+public:
+  /**
+   * \param m The mean of the distribution from which the return value is drawn
+   * \param b The upper bound value desired, beyond which values get clipped
+   * \return A random number from an exponential distribution with mean m
+   */
+  static double GetSingleValue(double m, double b=0);
 private:
   double m_mean;  // Mean value of RV
   double m_bound; // Upper bound on value (if non-zero)
@@ -362,8 +393,17 @@
 /**
  * \brief ParetoVariable distributed random var
  * \ingroup randomvariable
+ * This class supports the creation of objects that return random numbers
+ * from a fixed pareto distribution.  It also supports the generation of 
+ * single random numbers from various pareto distributions.
+ * \code
+ * ParetoVariable x(3.14);
+ * x.GetValue();  //will always return with mean 3.14
+ * ParetoVariable::GetSingleValue(20.1); //returns with mean 20.1
+ * ParetoVariable::GetSingleValue(108); //returns with mean 108
+ * \endcode
  */
-class ParetoVariable : public RandomVariable { // 
+class ParetoVariable : public RandomVariable {
 public:
   /**
    * Constructs a pareto random variable with a mean of 1 and a shape
@@ -389,6 +429,7 @@
   /**
    * \brief Constructs a pareto random variable with the specified mean
    * \brief value, shape (alpha), and upper bound.
+   *
    * Since pareto distributions can theoretically return unbounded values,
    * it is sometimes useful to specify a fixed upper limit.  Note however
    * when the upper limit is specified, the true mean of the distribution
@@ -406,6 +447,17 @@
    */
   virtual double GetValue();
   virtual RandomVariable* Copy() const;
+public:
+  /**
+   * \param m The mean value of the distribution from which the return value
+   * is drawn.
+   * \param s The shape parameter of the distribution from which the return
+   * value is drawn.
+   * \param b The upper bound to which to restrict return values
+   * \return A random number from a Pareto distribution with mean m and shape
+   * parameter s.
+   */
+  static double GetSingleValue(double m, double s, double b=0);
 private:
   double m_mean;  // Mean value of RV
   double m_shape; // Shape parameter
@@ -415,6 +467,9 @@
 /**
  * \brief WeibullVariable distributed random var
  * \ingroup randomvariable
+ * This class supports the creation of objects that return random numbers
+ * from a fixed weibull distribution.  It also supports the generation of 
+ * single random numbers from various weibull distributions.
  */
 class WeibullVariable : public RandomVariable {
 public:
@@ -460,6 +515,14 @@
    */
   virtual double GetValue();
   virtual RandomVariable* Copy() const;
+public:
+  /**
+   * \param m Mean value for the distribution.
+   * \param s Shape (alpha) parameter for the distribution.
+   * \param b Upper limit on returned values
+   * \return Random number from a distribution specified by m,s, and b
+   */
+  static double GetSingleValue(double m, double s, double b=0);
 private:
   double m_mean;  // Mean value of RV
   double m_alpha; // Shape parameter
@@ -469,6 +532,10 @@
 /**
  * \brief Class NormalVariable defines a random variable with a
  * normal (Gaussian) distribution.
+ * 
+ * This class supports the creation of objects that return random numbers
+ * from a fixed normal distribution.  It also supports the generation of 
+ * single random numbers from various normal distributions.
  * \ingroup randomvariable
  */
 class NormalVariable : public RandomVariable { // Normally Distributed random var
@@ -481,7 +548,6 @@
    */ 
   NormalVariable();
 
-
   /**
    * \brief Construct a normal random variable with specified mean and variance
    * \param m Mean value
@@ -497,12 +563,22 @@
    */
   virtual double GetValue();
   virtual RandomVariable* Copy() const;
+public:
+  /**
+   * \param m Mean value
+   * \param v Variance
+   * \param b Bound.  The NormalVariable is bounded within +-bound.
+   * \return A random number from a distribution specified by m,v, and b.
+   */ 
+  static double GetSingleValue(double m, double v, double b = INFINITE_VALUE);
 private:
   double m_mean;      // Mean value of RV
   double m_variance;  // Mean value of RV
   double m_bound;     // Bound on value (absolute value)
-  bool     m_nextValid; // True if next valid
+  bool   m_nextValid; // True if next valid
   double m_next;      // The algorithm produces two values at a time
+  static bool   m_static_nextValid;
+  static double m_static_next;
 };
 
 /**
@@ -620,6 +696,9 @@
  * distribution.  If one takes the natural logarithm of random
  * variable following the log-normal distribution, the obtained values
  * follow a normal distribution.
+ *  This class supports the creation of objects that return random numbers
+ * from a fixed lognormal distribution.  It also supports the generation of
+ * single random numbers from various lognormal distributions.
  */
 class LogNormalVariable : public RandomVariable { 
 public:
@@ -645,6 +724,13 @@
    */
   virtual double GetValue ();
   virtual RandomVariable* Copy() const;
+public:
+  /**
+   * \param mu Mean value of the underlying normal distribution.
+   * \param sigma Standard deviation of the underlying normal distribution.
+   * \return A random number from the distribution specified by mu and sigma
+   */
+  static double GetSingleValue(double mu, double sigma);
 private:
   double m_mu;
   double m_sigma;