diff --git a/src/core/random-variable.cc b/src/core/random-variable.cc index e14930791..c797841e1 100644 --- a/src/core/random-variable.cc +++ b/src/core/random-variable.cc @@ -44,16 +44,33 @@ namespace ns3{ 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 @@ void RandomVariable::SetRunNumber(uint32_t n) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -// UniformVariable methods +// UniformVariable UniformVariable::UniformVariable() : m_min(0), m_max(1.0) { } @@ -192,6 +209,12 @@ RandomVariable* UniformVariable::Copy() const { 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 @@ RandomVariable* ExponentialVariable::Copy() const { 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 @@ RandomVariable* ParetoVariable::Copy() const { 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 @@ RandomVariable* WeibullVariable::Copy() const { 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 @@ RandomVariable* NormalVariable::Copy() const 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 @@ RandomVariable* LogNormalVariable::Copy () const } 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 @@ LogNormalVariable::GetValue () 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 diff --git a/src/core/random-variable.h b/src/core/random-variable.h index 6f955167d..b5076ca5f 100644 --- a/src/core/random-variable.h +++ b/src/core/random-variable.h @@ -182,8 +182,10 @@ private: 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 @@ protected: /** * \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 @@ public: */ 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 @@ private: /** * \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 @@ public: */ 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 @@ private: /** * \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 @@ public: /** * \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 @@ public: */ 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 @@ private: /** * \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 @@ public: */ 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 @@ private: /** * \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 @@ public: */ NormalVariable(); - /** * \brief Construct a normal random variable with specified mean and variance * \param m Mean value @@ -497,12 +563,22 @@ public: */ 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 @@ private: * 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 @@ public: */ 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;