diff --git a/SConstruct b/SConstruct index 988125fc2..081afc998 100644 --- a/SConstruct +++ b/SConstruct @@ -22,6 +22,8 @@ core.add_sources([ 'assert.cc', 'ptr.cc', 'test.cc', + 'random-variable.cc', + 'rng-stream.cc', ]) env = Environment() if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin': @@ -44,7 +46,9 @@ core.add_inst_headers([ 'debug.h', 'assert.h', 'fatal-error.h', - 'test.h' + 'test.h', + 'random-variable.h', + 'rng-stream.h' ]) def config_core (env, config): @@ -184,6 +188,7 @@ node.add_sources ([ 'udp-socket.cc', 'udp.cc', 'arp-header.cc', + 'application.cc', 'arp-cache.cc', 'arp-ipv4-interface.cc', 'arp.cc', @@ -200,6 +205,7 @@ node.add_headers ([ 'ipv4-checksum.h', 'udp.h', 'ipv4-l4-protocol.h', + 'application.h', 'arp-header.h', 'arp-cache-cache.h', 'arp.h', diff --git a/src/core/random-variable.cc b/src/core/random-variable.cc new file mode 100644 index 000000000..97cd29d60 --- /dev/null +++ b/src/core/random-variable.cc @@ -0,0 +1,574 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Author: Rajib Bhattacharjea +// + +#include + +#include +#include +#include // for gettimeofday +#include +#include +#include +#include +#include + + +#include "random-variable.h" +#include "rng-stream.h" +#include "fatal-error.h" + +using namespace std; + +namespace ns3{ +// Seed methods + +Seed::~Seed() +{ +} + +RandomSeed::RandomSeed() +{ +} + +RandomSeed::~RandomSeed() +{ +} + +bool RandomSeed::IsRandom() const +{ + return true; +} + +ConstantSeed::~ConstantSeed() +{ +} + +bool ConstantSeed::IsRandom() const +{ + return false; +} + +ConstantSeed::ConstantSeed(uint32_t s) +{ + seeds[0] = s; + seeds[1] = s; + seeds[2] = s; + seeds[3] = s; + seeds[4] = s; + seeds[5] = s; +} + +ConstantSeed::ConstantSeed(uint32_t s0, uint32_t s1, uint32_t s2, + uint32_t s3, uint32_t s4, uint32_t s5) +{ + seeds[0] = s0; + seeds[1] = s1; + seeds[2] = s2; + seeds[3] = s3; + seeds[4] = s4; + seeds[5] = s5; +} +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// RandomVariable methods + +bool RandomVariable::initialized = false; // True if RngStream seed set +bool RandomVariable::useDevRandom = false; // True if use /dev/random desired +bool RandomVariable::globalSeedSet = false; // True if GlobalSeed called +int RandomVariable::devRandom = -1; +uint32_t RandomVariable::globalSeed[6]; +unsigned long RandomVariable::heuristic_sequence; + +RandomVariable::RandomVariable() +{ + m_generator = new RngStream(); + RandomVariable::Initialize(); // sets the seed for the static object + m_generator->InitializeStream(); +} + +RandomVariable::~RandomVariable() +{ + delete m_generator; +} + +uint32_t RandomVariable::GetIntValue() +{ + return (uint32_t)GetValue(); +} + +void RandomVariable::UseDevRandom(bool udr) +{ + RandomVariable::useDevRandom = udr; +} + +bool RandomVariable::SetSeed(const Seed& s) +{ + // Seed this stream with the specified seed + if (s.IsRandom()) + { + uint32_t seeds[6]; + while(true) + { // Insure seeds are valid + GetRandomSeeds(seeds); + if (RngStream::CheckSeed(seeds)) break; + } + m_generator->SetSeeds(seeds); + return true; + } + // Not random seed, use specified + const ConstantSeed& cs = (ConstantSeed&)s; + if (!RngStream::CheckSeed(cs.seeds)) + { + cout << "Constant seed failed valid check" << endl; + return false; // Seed is not valid + } + m_generator->SetSeeds(cs.seeds); + return true; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// RandomVariable static methods +void RandomVariable::UseGlobalSeed(const Seed& s) +{ + if (RandomVariable::globalSeedSet) + { + cout << "Random number generator already initialized!" << endl; + cout << "Call to RandomVariable::UseGlobalSeed() ignored" << endl; + return; + } + if (s.IsRandom()) return; // Random seed is the default + const ConstantSeed& cs = (ConstantSeed&)s; + RandomVariable::globalSeed[0] = cs.seeds[0]; + RandomVariable::globalSeed[1] = cs.seeds[1]; + RandomVariable::globalSeed[2] = cs.seeds[2]; + RandomVariable::globalSeed[3] = cs.seeds[3]; + RandomVariable::globalSeed[4] = cs.seeds[4]; + RandomVariable::globalSeed[5] = cs.seeds[5]; + if (!RngStream::CheckSeed(RandomVariable::globalSeed)) + NS_FATAL_ERROR("Invalid seed"); + + RandomVariable::globalSeedSet = true; +} + +void RandomVariable::Initialize() +{ + if (RandomVariable::initialized) return; // Already initialized and seeded + RandomVariable::initialized = true; + if (!RandomVariable::globalSeedSet) + { // No global seed, try a random one + GetRandomSeeds(globalSeed); + } + // Seed the RngStream package + RngStream::SetPackageSeed(globalSeed); +} + +void RandomVariable::GetRandomSeeds(uint32_t seeds[6]) +{ + // Check if /dev/random exists + if (RandomVariable::useDevRandom && RandomVariable::devRandom < 0) + { + RandomVariable::devRandom = open("/dev/random", O_RDONLY); + } + if (RandomVariable::devRandom > 0) + { // Use /dev/random + while(true) + { + for (int i = 0; i < 6; ++i) + { + read(RandomVariable::devRandom, &seeds[i], sizeof(seeds[i])); + } + if (RngStream::CheckSeed(seeds)) break; // Got a valid one + } + } + else + { // Seed from time of day (code borrowed from ns2 random seeding) + // Thanks to John Heidemann for this technique + while(true) + { + timeval tv; + gettimeofday(&tv, 0); + seeds[0] = (tv.tv_sec^tv.tv_usec^(++heuristic_sequence <<8)) + & 0x7fffffff; + gettimeofday(&tv, 0); + seeds[1] = (tv.tv_sec^tv.tv_usec^(++heuristic_sequence <<8)) + & 0x7fffffff; + gettimeofday(&tv, 0); + seeds[2] = (tv.tv_sec^tv.tv_usec^(++heuristic_sequence <<8)) + & 0x7fffffff; + gettimeofday(&tv, 0); + seeds[3] = (tv.tv_sec^tv.tv_usec^(++heuristic_sequence <<8)) + & 0x7fffffff; + gettimeofday(&tv, 0); + seeds[4] = (tv.tv_sec^tv.tv_usec^(++heuristic_sequence <<8)) + & 0x7fffffff; + gettimeofday(&tv, 0); + seeds[5] = (tv.tv_sec^tv.tv_usec^(++heuristic_sequence <<8)) + & 0x7fffffff; + if (RngStream::CheckSeed(seeds)) break; // Got a valid one + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// UniformVariable methods +UniformVariable::UniformVariable() + : m_min(0), m_max(1.0) { } + +UniformVariable::UniformVariable(double s, double l) + : m_min(s), m_max(l) { } + +UniformVariable::UniformVariable(const UniformVariable& c) + : m_min(c.m_min), m_max(c.m_max) { } + +double UniformVariable::GetValue() +{ + return m_min + m_generator->RandU01() * (m_max - m_min); +} + +RandomVariable* UniformVariable::Copy() const +{ + return new UniformVariable(*this); +} +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// ConstantVariable methods +ConstantVariable::ConstantVariable() + : m_const(0) { } + +ConstantVariable::ConstantVariable(double c) + : m_const(c) { }; + +ConstantVariable::ConstantVariable(const ConstantVariable& c) + : m_const(c.m_const) { } + +void ConstantVariable::NewConstant(double c) + { m_const = c;} + +double ConstantVariable::GetValue() +{ + return m_const; +} + +uint32_t ConstantVariable::GetIntValue() +{ + return (uint32_t)m_const; +} + +RandomVariable* ConstantVariable::Copy() const +{ + return new ConstantVariable(*this); +} +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// SequentialVariable methods +SequentialVariable::SequentialVariable(double f, double l, double i, uint32_t c) + : m_min(f), m_max(l), m_increment(ConstantVariable(i).Copy()), m_consecutive(c), + m_current(f), m_currentConsecutive(0) +{ +} + +SequentialVariable::SequentialVariable(double f, double l, const RandomVariable& i, uint32_t c) + : m_min(f), m_max(l), m_increment(i.Copy()), m_consecutive(c), + m_current(f), m_currentConsecutive(0) +{ +} + +SequentialVariable::SequentialVariable(const SequentialVariable& c) + : m_min(c.m_min), m_max(c.m_max), + m_increment(c.m_increment->Copy()), m_consecutive(c.m_consecutive), + m_current(c.m_current), m_currentConsecutive(c.m_currentConsecutive) +{ +} + +double SequentialVariable::GetValue() +{ // Return a sequential series of values + double r = m_current; + if (++m_currentConsecutive == m_consecutive) + { // Time to advance to next + m_currentConsecutive = 0; + m_current += m_increment->GetValue(); + if (m_current >= m_max) + m_current = m_min + (m_current - m_max); + } + return r; +} + +RandomVariable* SequentialVariable::Copy() const +{ + return new SequentialVariable(*this); +} +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// ExponentialVariable methods +ExponentialVariable::ExponentialVariable() + : m_mean(1.0), m_bound(0) { } + +ExponentialVariable::ExponentialVariable(double m) + : m_mean(m), m_bound(0) { } + +ExponentialVariable::ExponentialVariable(double m, double b) + : m_mean(m), m_bound(b) { } + +ExponentialVariable::ExponentialVariable(const ExponentialVariable& c) + : m_mean(c.m_mean), m_bound(c.m_bound) { } + +double ExponentialVariable::GetValue() +{ + double r = -m_mean*log(m_generator->RandU01()); + if (m_bound != 0 && r > m_bound) return m_bound; + return r; +} + +RandomVariable* ExponentialVariable::Copy() const +{ + return new ExponentialVariable(*this); +} +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// ParetoVariable methods +ParetoVariable::ParetoVariable() + : m_mean(1.0), m_shape(1.5), m_bound(0) { } + +ParetoVariable::ParetoVariable(double m) + : m_mean(m), m_shape(1.5), m_bound(0) { } + +ParetoVariable::ParetoVariable(double m, double s) + : m_mean(m), m_shape(s), m_bound(0) { } + +ParetoVariable::ParetoVariable(double m, double s, double b) + : m_mean(m), m_shape(s), m_bound(b) { } + +ParetoVariable::ParetoVariable(const ParetoVariable& c) + : m_mean(c.m_mean), m_shape(c.m_shape), m_bound(c.m_bound) { } + +double ParetoVariable::GetValue() +{ + double scale = m_mean * ( m_shape - 1.0) / m_shape; + double r = (scale * ( 1.0 / pow(m_generator->RandU01(), 1.0 / m_shape))); + if (m_bound != 0 && r > m_bound) return m_bound; + return r; +} + +RandomVariable* ParetoVariable::Copy() const +{ + return new ParetoVariable(*this); +} +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// WeibullVariable methods +WeibullVariable::WeibullVariable() : m_mean(1.0), m_alpha(1), m_bound(0) { } +WeibullVariable::WeibullVariable(double m) + : m_mean(m), m_alpha(1), m_bound(0) { } +WeibullVariable::WeibullVariable(double m, double s) + : m_mean(m), m_alpha(s), m_bound(0) { } +WeibullVariable::WeibullVariable(double m, double s, double b) + : m_mean(m), m_alpha(s), m_bound(b) { }; +WeibullVariable::WeibullVariable(const WeibullVariable& c) + : m_mean(c.m_mean), m_alpha(c.m_alpha), m_bound(c.m_bound) { } + +double WeibullVariable::GetValue() +{ + double exponent = 1.0 / m_alpha; + double r = m_mean * pow( -log(m_generator->RandU01()), exponent); + if (m_bound != 0 && r > m_bound) return m_bound; + return r; +} + +RandomVariable* WeibullVariable::Copy() const +{ + return new WeibullVariable(*this); +} +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// NormalVariable methods +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) + : m_mean(m), m_variance(v), m_bound(b), m_nextValid(false) { } + +NormalVariable::NormalVariable(const NormalVariable& c) + : m_mean(c.m_mean), m_variance(c.m_variance), m_bound(c.m_bound) { } + +double NormalVariable::GetValue() +{ + if (m_nextValid) + { // use previously generated + m_nextValid = false; + return m_next; + } + while(1) + { // See Simulation Modeling and Analysis p. 466 (Averill Law) + // for algorithm + double u1 = m_generator->RandU01(); + double u2 = m_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_next = m_mean + v2 * y * sqrt(m_variance); + if (fabs(m_next) > m_bound) m_next = m_bound * (m_next)/fabs(m_next); + m_nextValid = true; + double x1 = m_mean + v1 * y * sqrt(m_variance); + if (fabs(x1) > m_bound) x1 = m_bound * (x1)/fabs(x1); + return x1; + } + } +} + +RandomVariable* NormalVariable::Copy() const +{ + return new NormalVariable(*this); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// ValueCDF methods +ValueCDF::ValueCDF() + : value(0.0), cdf(0.0){ } +ValueCDF::ValueCDF(double v, double c) + : value(v), cdf(c) { } +ValueCDF::ValueCDF(const ValueCDF& c) + : value(c.value), cdf(c.cdf) { } + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// EmpiricalVariable methods +EmpiricalVariable::EmpiricalVariable() + : validated(false) { } + +EmpiricalVariable::EmpiricalVariable(const EmpiricalVariable& c) + : validated(c.validated), emp(c.emp) { } + +EmpiricalVariable::~EmpiricalVariable() { } + +double EmpiricalVariable::GetValue() +{ // Return a value from the empirical distribution + // This code based (loosely) on code by Bruce Mah (Thanks Bruce!) + if (emp.size() == 0) return 0.0; // HuH? No empirical data + if (!validated) Validate(); // Insure in non-decreasing + double r = m_generator->RandU01(); + if (r <= emp.front().cdf)return emp.front().value; // Less than first + if (r >= emp.back().cdf) return emp.back().value; // Greater than last + // Binary search + std::vector::size_type bottom = 0; + std::vector::size_type top = emp.size() - 1; + while(1) + { + std::vector::size_type c = (top + bottom) / 2; + if (r >= emp[c].cdf && r < emp[c+1].cdf) + { // Found it + return Interpolate(emp[c].cdf, emp[c+1].cdf, + emp[c].value, emp[c+1].value, + r); + } + // Not here, adjust bounds + if (r < emp[c].cdf) top = c - 1; + else bottom = c + 1; + } +} + +RandomVariable* EmpiricalVariable::Copy() const +{ + return new EmpiricalVariable(*this); +} + +void EmpiricalVariable::CDF(double v, double c) +{ // Add a new empirical datapoint to the empirical cdf + // NOTE. These MUST be inserted in non-decreasing order + emp.push_back(ValueCDF(v, c)); +} + +void EmpiricalVariable::Validate() +{ + ValueCDF prior; + for (std::vector::size_type i = 0; i < emp.size(); ++i) + { + ValueCDF& current = emp[i]; + if (current.value < prior.value || current.cdf < prior.cdf) + { // Error + cout << "Empirical Dist error," + << " current value " << current.value + << " prior value " << prior.value + << " current cdf " << current.cdf + << " prior cdf " << prior.cdf << endl; + NS_FATAL_ERROR("Empirical Dist error"); + } + prior = current; + } + validated = true; +} + +double EmpiricalVariable::Interpolate(double c1, double c2, + double v1, double v2, double r) +{ // Interpolate random value in range [v1..v2) based on [c1 .. r .. c2) + return (v1 + ((v2 - v1) / (c2 - c1)) * (r - c1)); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Integer EmpiricalVariable methods +IntEmpiricalVariable::IntEmpiricalVariable() { } + +uint32_t IntEmpiricalVariable::GetIntValue() +{ + return (uint32_t)GetValue(); +} + +RandomVariable* IntEmpiricalVariable::Copy() const +{ + return new IntEmpiricalVariable(*this); +} + + +double IntEmpiricalVariable::Interpolate(double c1, double c2, + double v1, double v2, double r) +{ // Interpolate random value in range [v1..v2) based on [c1 .. r .. c2) + return ceil(v1 + ((v2 - v1) / (c2 - c1)) * (r - c1)); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// DeterministicVariable +DeterministicVariable::DeterministicVariable(double* d, uint32_t c) + : count(c), next(c), data(d) +{ // Nothing else needed +} + +DeterministicVariable::~DeterministicVariable() { } + +double DeterministicVariable::GetValue() +{ + if (next == count) next = 0; + return data[next++]; +} + +RandomVariable* DeterministicVariable::Copy() const +{ + return new DeterministicVariable(*this); +} + +}//namespace ns3 + diff --git a/src/core/random-variable.h b/src/core/random-variable.h new file mode 100644 index 000000000..e7193f632 --- /dev/null +++ b/src/core/random-variable.h @@ -0,0 +1,584 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Author: Rajib Bhattacharjea +// + +#ifndef __random_variable_h__ +#define __random_variable_h__ + +#include +#include + + +#define INFINITE_VALUE 1e307 +namespace ns3{ + +class RngStream; + +/** + * \brief Pure virtual base class for RNG seeds + */ +class Seed { + // Seed is used to seed the random number generator(s) + // This is a base class for RandomSeed and ConstantSeed +public: + virtual ~Seed(); + virtual bool IsRandom() const = 0; +}; + +/** + * \brief random RNG seeds + */ +class RandomSeed : public Seed { +public: + RandomSeed(); + ~RandomSeed(); + bool IsRandom() const; +}; + +/** + * \brief constant RNG seeds + */ +class ConstantSeed : public Seed +{ +public: + ConstantSeed(uint32_t); // Use six copies of the specified value + ConstantSeed(uint32_t,uint32_t,uint32_t,uint32_t,uint32_t,uint32_t); // Six seeds + bool IsRandom() const; + ~ConstantSeed(); +public: + uint32_t seeds[6]; +}; + +/** + * \brief The basic RNG for NS-3. + * + * Note: The underlying random number generation method used + * by NS-3 is the RngStream code by Pierre L'Ecuyer at + * the University of Montreal. + * + * NS-3 has a rich set of random number generators. + * Class RandomVariable defines the base class functionalty + * required for all random number generators. By default, the underlying + * generator is seeded with the time of day, and then deterministically + * creates a sequence of seeds for each subsequent generator that is created. + * The rest of the documentation outlines how to change this behavior. + */ +class RandomVariable { + +public: + /** + * \brief Constructor for a random number generator with a random seed. + */ + RandomVariable(); + + /** + * \brief Destructor for a random number generator with a random seed. + */ + virtual ~RandomVariable(); + + /** + * \brief Returns a random double from the underlying distribution + * \return A floating point random value + */ + virtual double GetValue() = 0; + + /** + * \brief Returns a random integer integer from the underlying distribution + * \return Integer cast of ::GetValue() + */ + virtual uint32_t GetIntValue(); + + /** + * \return A copy of this object + */ + virtual RandomVariable* Copy() const = 0; + + /** + * \brief Use a private seed and private stream for this generator. + * + * This function explicitly overrides all other seeding behavior for + * this object. For example, even if another seeding method has been + * used (either by default or calls to UseDevRandom, UseGlobalSeed, etc.) + * a call to SetSeed explicitly re-seeds this generator. Example: + * \code + * UniformVariable x(0,10);//with no other code, defaults to time of day seed + * x.SetSeed(...); //overrides time of day seed + * \endcode + * \param s Seed to use. Can either be a RandomSeed or ConstantSeed. + * \return true if valid seed. + */ + bool SetSeed(const Seed& s); + + /** + * \brief Set seeding behavior + * + * Specify whether the POSIX device /dev/random is to + * be used for seeding. When this is used, the underlying + * generator is seeded with data from /dev/random instead of + * being seeded based upon the time of day. For this to be effective, + * it must be called before the creation of the first instance of a + * RandomVariable or subclass. Example: + * \code + * RandomVariable::UseDevRandom(); + * UniformVariable x(2,3); //these are seeded randomly + * ExponentialVariable y(120); //etc + * \endcode + * \param udr True if /dev/random desired. + */ + static void UseDevRandom(bool udr = true); + + /** + * \brief Use the global seed to force precisely reproducible results. + * It is often desirable to create a simulation that uses random + * numbers, while at the same time is completely reproducible. + * Specifying this set of six random seeds initializes the + * random number generator with the specified seed. + * Once this is set, all generators will produce fixed output + * from run to run. This is because each time a new generator is created, + * the underlying RngStream deterministically creates a new seed based upon + * the old one, hence a "stream" of RNGs. Example: + * \code + * RandomVariable::UseGlobalSeed(...); + * UniformVariable x(2,3); //these will give the same output everytime + * ExponentialVariable y(120); //as long as the seed stays the same + * \endcode + * \param s + * \return True if seed is valid. + */ + static void UseGlobalSeed(const Seed& s); + +private: + static bool initialized; // True if package seed is set + static void Initialize(); // Initialize the RNG system + static void GetRandomSeeds(uint32_t seeds[6]); +private: + static bool useDevRandom; // True if using /dev/random desired + static bool globalSeedSet; // True if global seed has been specified + static int devRandom; // File handle for /dev/random + static uint32_t globalSeed[6]; // The global seed to use +protected: + static unsigned long heuristic_sequence; + RngStream* m_generator; //underlying generator being wrapped +}; + + +/** + * \brief The uniform distribution RNG for NS-3. + */ +class UniformVariable : public RandomVariable { +public: + /** + * Creates a uniform random number generator in the + * range [0.0 .. 1.0) + */ + UniformVariable(); + + /** + * Creates a uniform random number generator with the specified range + * \param s Low end of the range + * \param l High end of the range + */ + UniformVariable(double s, double l); + + UniformVariable(const UniformVariable& c); + + /** + * \return A value between low and high values specified by the constructor + */ + virtual double GetValue(); + virtual RandomVariable* Copy() const; +private: + double m_min; + double m_max; +}; + +/** + * \brief A random variable that returns a constant + * Class ConstantVariable defines a random number generator that + * returns the same value every sample. + */ +class ConstantVariable : public RandomVariable { + +public: + /** + * \brief Construct a ConstantVariable RNG that returns zero every sample + */ + ConstantVariable(); + + /** + * Construct a ConstantVariable RNG that returns the specified value + * every sample. + * \param c Unchanging value for this RNG. + */ + ConstantVariable(double c); + + + ConstantVariable(const ConstantVariable& c) ; + + /** + * \brief Specify a new constant RNG for this generator. + * \param c New constant value for this RNG. + */ + void NewConstant(double c); + + /** + * \return The constant value specified + */ + virtual double GetValue(); + virtual uint32_t GetIntValue(); + virtual RandomVariable* Copy() const; +private: + double m_const; +}; + +/** + * \brief Return a sequential list of values + * Class SequentialVariable defines a random number generator that + * returns a sequential sequence. The sequence monotonically + * increases for a period, then wraps around to the low value + * and begins monotonicaly increasing again. + */ +class SequentialVariable : public RandomVariable { + +public: + /** + * \brief Constructor for the SequentialVariable RNG. + * The four parameters define the sequence. For example + * SequentialVariable(0,5,1,2) creates a RNG that has the sequence + * 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 0, 0 ... + * \param f First value of the sequence. + * \param l One more than the last value of the sequence. + * \param i Increment between sequence values + * \param c Number of times each member of the sequence is repeated + */ + SequentialVariable(double f, double l, double i = 1, uint32_t c = 1); + + /** + * \brief Constructor for the SequentialVariable RNG. + * Differs from the first only in that the increment parameter is a + * random variable + * \param f First value of the sequence. + * \param l One more than the last value of the sequence. + * \param i Reference to a Random variable for the sequence increment + * \param c Number of times each member of the sequence is repeated + */ + SequentialVariable(double f, double l, const RandomVariable& i, uint32_t c = 1); + + SequentialVariable(const SequentialVariable& c); + /** + * \return The next value in the Sequence + */ + virtual double GetValue(); + virtual RandomVariable* Copy() const; +private: + double m_min; + double m_max; + RandomVariable* m_increment; + uint32_t m_consecutive; + double m_current; + uint32_t m_currentConsecutive; +}; + +/** + * \brief Exponentially Distributed random var + * ExponentialVariable defines a random variable with an exponential distribution + */ +class ExponentialVariable : public RandomVariable { +public: + /** + * Constructs an exponential random variable with a mean + * value of 1.0. + */ + ExponentialVariable(); + + /** + * \brief Constructs an exponential random variable with a specified mean + * \param m Mean value for the random variable + */ + explicit ExponentialVariable(double m); + + /** + * \brief Constructs an exponential random variable with spefified + * \brief mean and upper limit. + * Since exponential 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 is + * slightly smaller than the mean value specified. + * \param m Mean value of the random variable + * \param b Upper bound on returned values + */ + ExponentialVariable(double m, double b); + + ExponentialVariable(const ExponentialVariable& c); + + /** + * \return A random value from this exponential distribution + */ + virtual double GetValue(); + virtual RandomVariable* Copy() const; +private: + double m_mean; // Mean value of RV + double m_bound; // Upper bound on value (if non-zero) +}; + +/** + * \brief ParetoVariable distributed random var + */ +class ParetoVariable : public RandomVariable { // +public: + /** + * Constructs a pareto random variable with a mean of 1 and a shape + * parameter of 1.5 + */ + ParetoVariable(); + + /** + * Constructs a pareto random variable with specified mean and shape + * parameter of 1.5 + * \param m Mean value of the distribution + */ + explicit ParetoVariable(double m); + + /** + * Constructs a pareto random variable with the specified mean value and + * shape parameter. + * \param m Mean value of the distribution + * \param s Shape parameter for the distribution + */ + ParetoVariable(double m, double s); + + /** + * \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 + * is slightly smaller than the mean value specified. + * \param m Mean value + * \param s Shape parameter + * \param b Upper limit on returned values + */ + ParetoVariable(double m, double s, double b); + + ParetoVariable(const ParetoVariable& c); + + /** + * \return A random value from this Pareto distribution + */ + virtual double GetValue(); + virtual RandomVariable* Copy() const; +private: + double m_mean; // Mean value of RV + double m_shape; // Shape parameter + double m_bound; // Upper bound on value (if non-zero) +}; + +/** + * \brief WeibullVariable distributed random var + */ +class WeibullVariable : public RandomVariable { +public: + /** + * Constructs a weibull random variable with a mean + * value of 1.0 and a shape (alpha) parameter of 1 + */ + WeibullVariable(); + + + /** + * Constructs a weibull random variable with the specified mean + * value and a shape (alpha) parameter of 1.5. + * \param m mean value of the distribution + */ + WeibullVariable(double m) ; + + /** + * Constructs a weibull random variable with the specified mean + * value and a shape (alpha). + * \param m Mean value for the distribution. + * \param s Shape (alpha) parameter for the distribution. + */ + WeibullVariable(double m, double s); + + /** + * \brief Constructs a weibull random variable with the specified mean + * \brief value, shape (alpha), and upper bound. + * Since WeibullVariable distributions can theoretically return unbounded values, + * it is sometimes usefull to specify a fixed upper limit. Note however + * that when the upper limit is specified, the true mean of the distribution + * is slightly smaller than the mean value specified. + * \param m Mean value for the distribution. + * \param s Shape (alpha) parameter for the distribution. + * \param b Upper limit on returned values + */ + WeibullVariable(double m, double s, double b); + + WeibullVariable(const WeibullVariable& c); + + /** + * \return A random value from this Weibull distribution + */ + virtual double GetValue(); + virtual RandomVariable* Copy() const; +private: + double m_mean; // Mean value of RV + double m_alpha; // Shape parameter + double m_bound; // Upper bound on value (if non-zero) +}; + +/** + * Class NormalVariable defines a random variable with a + * normal (Gaussian) distribution. + */ +class NormalVariable : public RandomVariable { // Normally Distributed random var + +public: + /** + * Constructs an normal random variable with a mean + * value of 0 and variance of 1. + */ + NormalVariable(); + + + /** + * \brief Construct a normal random variable with specified mean and variance + * \param m Mean value + * \param v Variance + * \param b Bound. The NormalVariable is bounded within +-bound. + */ + NormalVariable(double m, double v, double b = INFINITE_VALUE); + + NormalVariable(const NormalVariable& c); + + /** + * \return A value from this normal distribution + */ + virtual double GetValue(); + virtual RandomVariable* Copy() const; +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 + double m_next; // The algorithm produces two values at a time +}; + +// Value/CDF pair class for Emiprical Distributions +//Doc:ClassXRef +class ValueCDF { +public: + ValueCDF(); + ValueCDF(double v, double c); + ValueCDF(const ValueCDF& c); + double value; + double cdf; +}; + +/** + * \brief EmpiricalVariable distribution random var + * Defines a random variable that has a specified, empirical + * distribution. The distribution is specified by a + * series of calls the the CDF member function, specifying a + * value and the probability that the function value is less than + * the specified value. When values are requested, + * a uniform random variable is used to select a probabililty, + * and the return value is interpreted linerarly between the + * two appropriate points in the CDF + */ +class EmpiricalVariable : public RandomVariable { +public: + /** + * Constructor for the EmpiricalVariable random variables. + */ + explicit EmpiricalVariable(); + + virtual ~EmpiricalVariable(); + EmpiricalVariable(const EmpiricalVariable& c); + /** + * \return A value from this empirical distribution + */ + virtual double GetValue(); + virtual RandomVariable* Copy() const; + /** + * \brief Specifies a point in the empirical distribution + * \param v The function value for this point + * \param c Probability that the function is less than or equal to v + */ + virtual void CDF(double v, double c); // Value, prob <= Value + +private: + virtual void Validate(); // Insure non-decreasing emiprical values + virtual double Interpolate(double, double, double, double, double); + bool validated; // True if non-decreasing validated + std::vector emp; // Empicical CDF +}; + +/** + * Defines an empirical distribution where all values are integers. + * Indentical to {\tt EmpiricalVariable}, but with slightly different + * interpolation between points. + */ +class IntEmpiricalVariable : public EmpiricalVariable { +public: + + IntEmpiricalVariable(); + + virtual RandomVariable* Copy() const; + /** + * \return An integer value from this empirical distribution + */ + virtual uint32_t GetIntValue(); + virtual double Interpolate(double, double, double, double, double); +}; + +/** + * Defines a random variable that has a specified, predetermined + * sequence. This would be useful when trying to force + * the RNG to return a known sequence, perhaps to + * compare NS-3 to some other simulator + */ +class DeterministicVariable : public RandomVariable { + +public: + /** + * \brief Constructor + * Creates a generator that returns successive elements of the d array + * on successive calls to ::Value(). Note that the d pointer is copied + * for use by the generator (shallow-copy), not its contents, so the + * contents of the array d points to have to remain unchanged for the use + * of DeterministicVariable to be meaningful. + * \param d Pointer to array of random values to return in sequence + * \param c Number of values in the array + */ + explicit DeterministicVariable(double* d, uint32_t c); + + virtual ~DeterministicVariable(); + /** + * \return The next value in the deterministic sequence + */ + virtual double GetValue(); + virtual RandomVariable* Copy() const; +private: + uint32_t count; + uint32_t next; + double* data; +}; + +}//namespace ns3 +#endif diff --git a/src/core/rng-stream.cc b/src/core/rng-stream.cc new file mode 100644 index 000000000..e8397f23d --- /dev/null +++ b/src/core/rng-stream.cc @@ -0,0 +1,468 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (C) 2001 Pierre L'Ecuyer (lecuyer@iro.umontreal.ca) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Modified for ns-3 by: Rajib Bhattacharjea +// + +#include +#include +#include "rng-stream.h" +using namespace std; + +namespace +{ +const double m1 = 4294967087.0; +const double m2 = 4294944443.0; +const double norm = 1.0 / (m1 + 1.0); +const double a12 = 1403580.0; +const double a13n = 810728.0; +const double a21 = 527612.0; +const double a23n = 1370589.0; +const double two17 = 131072.0; +const double two53 = 9007199254740992.0; +const double fact = 5.9604644775390625e-8; /* 1 / 2^24 */ + +// The following are the transition matrices of the two MRG components +// (in matrix form), raised to the powers -1, 1, 2^76, and 2^127, resp. + +const double InvA1[3][3] = { // Inverse of A1p0 + { 184888585.0, 0.0, 1945170933.0 }, + { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 } + }; + +const double InvA2[3][3] = { // Inverse of A2p0 + { 0.0, 360363334.0, 4225571728.0 }, + { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 } + }; + +const double A1p0[3][3] = { + { 0.0, 1.0, 0.0 }, + { 0.0, 0.0, 1.0 }, + { -810728.0, 1403580.0, 0.0 } + }; + +const double A2p0[3][3] = { + { 0.0, 1.0, 0.0 }, + { 0.0, 0.0, 1.0 }, + { -1370589.0, 0.0, 527612.0 } + }; + +const double A1p76[3][3] = { + { 82758667.0, 1871391091.0, 4127413238.0 }, + { 3672831523.0, 69195019.0, 1871391091.0 }, + { 3672091415.0, 3528743235.0, 69195019.0 } + }; + +const double A2p76[3][3] = { + { 1511326704.0, 3759209742.0, 1610795712.0 }, + { 4292754251.0, 1511326704.0, 3889917532.0 }, + { 3859662829.0, 4292754251.0, 3708466080.0 } + }; + +const double A1p127[3][3] = { + { 2427906178.0, 3580155704.0, 949770784.0 }, + { 226153695.0, 1230515664.0, 3580155704.0 }, + { 1988835001.0, 986791581.0, 1230515664.0 } + }; + +const double A2p127[3][3] = { + { 1464411153.0, 277697599.0, 1610723613.0 }, + { 32183930.0, 1464411153.0, 1022607788.0 }, + { 2824425944.0, 32183930.0, 2093834863.0 } + }; + + + +//------------------------------------------------------------------------- +// Return (a*s + c) MOD m; a, s, c and m must be < 2^35 +// +double MultModM (double a, double s, double c, double m) +{ + double v; + int32_t a1; + + v = a * s + c; + + if (v >= two53 || v <= -two53) { + a1 = static_cast (a / two17); a -= a1 * two17; + v = a1 * s; + a1 = static_cast (v / m); v -= a1 * m; + v = v * two17 + a * s + c; + } + + a1 = static_cast (v / m); + /* in case v < 0)*/ + if ((v -= a1 * m) < 0.0) return v += m; else return v; +} + + +//------------------------------------------------------------------------- +// Compute the vector v = A*s MOD m. Assume that -m < s[i] < m. +// Works also when v = s. +// +void MatVecModM (const double A[3][3], const double s[3], double v[3], + double m) +{ + int i; + double x[3]; // Necessary if v = s + + for (i = 0; i < 3; ++i) { + x[i] = MultModM (A[i][0], s[0], 0.0, m); + x[i] = MultModM (A[i][1], s[1], x[i], m); + x[i] = MultModM (A[i][2], s[2], x[i], m); + } + for (i = 0; i < 3; ++i) + v[i] = x[i]; +} + + +//------------------------------------------------------------------------- +// Compute the matrix C = A*B MOD m. Assume that -m < s[i] < m. +// Note: works also if A = C or B = C or A = B = C. +// +void MatMatModM (const double A[3][3], const double B[3][3], + double C[3][3], double m) +{ + int i, j; + double V[3], W[3][3]; + + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) + V[j] = B[j][i]; + MatVecModM (A, V, V, m); + for (j = 0; j < 3; ++j) + W[j][i] = V[j]; + } + for (i = 0; i < 3; ++i) + for (j = 0; j < 3; ++j) + C[i][j] = W[i][j]; +} + + +//------------------------------------------------------------------------- +// Compute the matrix B = (A^(2^e) Mod m); works also if A = B. +// +void MatTwoPowModM (const double A[3][3], double B[3][3], double m, int32_t e) +{ + int i, j; + + /* initialize: B = A */ + if (A != B) { + for (i = 0; i < 3; ++i) + for (j = 0; j < 3; ++j) + B[i][j] = A[i][j]; + } + /* Compute B = A^(2^e) mod m */ + for (i = 0; i < e; i++) + MatMatModM (B, B, B, m); +} + + +//------------------------------------------------------------------------- +// Compute the matrix B = (A^n Mod m); works even if A = B. +// +void MatPowModM (const double A[3][3], double B[3][3], double m, int32_t n) +{ + int i, j; + double W[3][3]; + + /* initialize: W = A; B = I */ + for (i = 0; i < 3; ++i) + for (j = 0; j < 3; ++j) { + W[i][j] = A[i][j]; + B[i][j] = 0.0; + } + for (j = 0; j < 3; ++j) + B[j][j] = 1.0; + + /* Compute B = A^n mod m using the binary decomposition of n */ + while (n > 0) { + if (n % 2) MatMatModM (W, B, B, m); + MatMatModM (W, W, W, m); + n /= 2; + } +} + + + +} // end of anonymous namespace + + +namespace ns3{ +//------------------------------------------------------------------------- +// Generate the next random number. +// +double RngStream::U01 () +{ + int32_t k; + double p1, p2, u; + + /* Component 1 */ + p1 = a12 * Cg[1] - a13n * Cg[0]; + k = static_cast (p1 / m1); + p1 -= k * m1; + if (p1 < 0.0) p1 += m1; + Cg[0] = Cg[1]; Cg[1] = Cg[2]; Cg[2] = p1; + + /* Component 2 */ + p2 = a21 * Cg[5] - a23n * Cg[3]; + k = static_cast (p2 / m2); + p2 -= k * m2; + if (p2 < 0.0) p2 += m2; + Cg[3] = Cg[4]; Cg[4] = Cg[5]; Cg[5] = p2; + + /* Combination */ + u = ((p1 > p2) ? (p1 - p2) * norm : (p1 - p2 + m1) * norm); + + return (anti == false) ? u : (1 - u); +} + + +//------------------------------------------------------------------------- +// Generate the next random number with extended (53 bits) precision. +// +double RngStream::U01d () +{ + double u; + u = U01(); + if (anti) { + // Don't forget that U01() returns 1 - u in the antithetic case + u += (U01() - 1.0) * fact; + return (u < 0.0) ? u + 1.0 : u; + } else { + u += U01() * fact; + return (u < 1.0) ? u : (u - 1.0); + } +} + +//------------------------------------------------------------------------- +// Check that the seeds are legitimate values. Returns true if legal seeds, +// false otherwise. +// +bool RngStream::CheckSeed (const uint32_t seed[6]) +{ + int i; + + for (i = 0; i < 3; ++i) { + if (seed[i] >= m1) { + cerr << "****************************************\n\n" + << "ERROR: Seed[" << i << "] >= 4294967087, Seed is not set." + << "\n\n****************************************\n\n"; + return (false); + } + } + for (i = 3; i < 6; ++i) { + if (seed[i] >= m2) { + cout << "Seed[" << i << "] = " << seed[i] << endl; + cerr << "*****************************************\n\n" + << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set." + << "\n\n*****************************************\n\n"; + return (false); + } + } + if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) { + cerr << "****************************\n\n" + << "ERROR: First 3 seeds = 0.\n\n" + << "****************************\n\n"; + return (false); + } + if (seed[3] == 0 && seed[4] == 0 && seed[5] == 0) { + cerr << "****************************\n\n" + << "ERROR: Last 3 seeds = 0.\n\n" + << "****************************\n\n"; + return (false); + } + return true; +} + + + +//************************************************************************* +// Public members of the class start here + + +//------------------------------------------------------------------------- +// The default seed of the package; will be the seed of the first +// declared RngStream, unless SetPackageSeed is called. +// +double RngStream::nextSeed[6] = +{ + 12345.0, 12345.0, 12345.0, 12345.0, 12345.0, 12345.0 +}; + +//------------------------------------------------------------------------- +// constructor +// +RngStream::RngStream () +{ + anti = false; + incPrec = false; + // Stream initialization moved to separate method. +} + +void RngStream::InitializeStream() +{ // Moved from the RngStream constructor above to allow seeding + // AFTER the global package seed has been set in the Random + // object constructor. + /* Information on a stream. The arrays {Cg, Bg, Ig} contain the current + state of the stream, the starting state of the current SubStream, and the + starting state of the stream. This stream generates antithetic variates + if anti = true. It also generates numbers with extended precision (53 + bits if machine follows IEEE 754 standard) if incPrec = true. nextSeed + will be the seed of the next declared RngStream. */ + + for (int i = 0; i < 6; ++i) { + Bg[i] = Cg[i] = Ig[i] = nextSeed[i]; + } + + MatVecModM (A1p127, nextSeed, nextSeed, m1); + MatVecModM (A2p127, &nextSeed[3], &nextSeed[3], m2); +} + +//------------------------------------------------------------------------- +// Reset Stream to beginning of Stream. +// +void RngStream::ResetStartStream () +{ + for (int i = 0; i < 6; ++i) + Cg[i] = Bg[i] = Ig[i]; +} + + +//------------------------------------------------------------------------- +// Reset Stream to beginning of SubStream. +// +void RngStream::ResetStartSubstream () +{ + for (int i = 0; i < 6; ++i) + Cg[i] = Bg[i]; +} + + +//------------------------------------------------------------------------- +// Reset Stream to NextSubStream. +// +void RngStream::ResetNextSubstream () +{ + MatVecModM(A1p76, Bg, Bg, m1); + MatVecModM(A2p76, &Bg[3], &Bg[3], m2); + for (int i = 0; i < 6; ++i) + Cg[i] = Bg[i]; +} + + +//------------------------------------------------------------------------- +bool RngStream::SetPackageSeed (const uint32_t seed[6]) +{ + if (!CheckSeed (seed)) return false; + for (int i = 0; i < 6; ++i) + nextSeed[i] = seed[i]; + return true; +} + + +//------------------------------------------------------------------------- +bool RngStream::SetSeeds (const uint32_t seed[6]) +{ + if (!CheckSeed (seed)) return false; + for (int i = 0; i < 6; ++i) + Cg[i] = Bg[i] = Ig[i] = seed[i]; + return true; +} + + +//------------------------------------------------------------------------- +// if e > 0, let n = 2^e + c; +// if e < 0, let n = -2^(-e) + c; +// if e = 0, let n = c. +// Jump n steps forward if n > 0, backwards if n < 0. +// +void RngStream::AdvanceState (int32_t e, int32_t c) +{ + double B1[3][3], C1[3][3], B2[3][3], C2[3][3]; + + if (e > 0) { + MatTwoPowModM (A1p0, B1, m1, e); + MatTwoPowModM (A2p0, B2, m2, e); + } else if (e < 0) { + MatTwoPowModM (InvA1, B1, m1, -e); + MatTwoPowModM (InvA2, B2, m2, -e); + } + + if (c >= 0) { + MatPowModM (A1p0, C1, m1, c); + MatPowModM (A2p0, C2, m2, c); + } else { + MatPowModM (InvA1, C1, m1, -c); + MatPowModM (InvA2, C2, m2, -c); + } + + if (e) { + MatMatModM (B1, C1, C1, m1); + MatMatModM (B2, C2, C2, m2); + } + + MatVecModM (C1, Cg, Cg, m1); + MatVecModM (C2, &Cg[3], &Cg[3], m2); +} + + +//------------------------------------------------------------------------- +void RngStream::GetState (uint32_t seed[6]) const +{ + for (int i = 0; i < 6; ++i) + seed[i] = static_cast (Cg[i]); +} + + +//------------------------------------------------------------------------- +void RngStream::IncreasedPrecis (bool incp) +{ + incPrec = incp; +} + + +//------------------------------------------------------------------------- +void RngStream::SetAntithetic (bool a) +{ + anti = a; +} + + +//------------------------------------------------------------------------- +// Generate the next random number. +// +double RngStream::RandU01 () +{ + if (incPrec) + return U01d(); + else + return U01(); +} + + +//------------------------------------------------------------------------- +// Generate the next random integer. +// +int32_t RngStream::RandInt (int32_t low, int32_t high) +{ + return low + static_cast ((high - low + 1) * RandU01 ()); +}; + +} //namespace ns3 diff --git a/src/core/rng-stream.h b/src/core/rng-stream.h new file mode 100644 index 000000000..e1670b085 --- /dev/null +++ b/src/core/rng-stream.h @@ -0,0 +1,60 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (C) 2001 Pierre L'Ecuyer (lecuyer@iro.umontreal.ca) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Modified for ns-3 by: Rajib Bhattacharjea + +#ifndef RNGSTREAM_H +#define RNGSTREAM_H +#include + +namespace ns3{ + +/** + * \brief RngStream by Pierre L'Ecuyer, University of Montreal + * Adapted to NS3 by Rajib Bhattacharjea, Georgia Tech. + */ +class RngStream { +public: //public api + RngStream (); + void InitializeStream(); // Separate initialization + void ResetStartStream (); + void ResetStartSubstream (); + void ResetNextSubstream (); + void SetAntithetic (bool a); + void IncreasedPrecis (bool incp); + bool SetSeeds (const uint32_t seed[6]); + void AdvanceState (int32_t e, int32_t c); + void GetState (uint32_t seed[6]) const; + double RandU01 (); + int32_t RandInt (int32_t i, int32_t j); +public: //public static api + static bool SetPackageSeed (const uint32_t seed[6]); + static bool CheckSeed(const uint32_t seed[6]); +private: //members + double Cg[6], Bg[6], Ig[6]; + bool anti, incPrec; + double U01 (); + double U01d (); +private: //static data + static double nextSeed[6]; +}; + +};//namespace ns3 + +#endif + + diff --git a/src/node/application.cc b/src/node/application.cc new file mode 100644 index 000000000..ffeebcaad --- /dev/null +++ b/src/node/application.cc @@ -0,0 +1,173 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 Georgia Tech Research Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: George F. Riley + */ + +// Implementation for ns3 Application base class. +// George F. Riley, Georgia Tech, Fall 2006 + +#include "application.h" +#include "node.h" +#include "node-reference.h" +#include "ns3/nstime.h" +#include "ns3/random-variable.h" +#include "ns3/simulator.h" + +using namespace std; + +namespace ns3 { + +#define nil 0 + +// Application Methods + +// \brief Application Constructor + Application::Application() : m_node(nil), m_startVar(nil), m_stopVar(nil), + m_start(false), m_stop(false) +{ +} + +Application::Application(const Application& o) + : m_node(nil), m_startVar(nil), m_stopVar(nil), + m_start(false), m_stop(false) +{ // Copy constructor + if (o.GetNode())m_node = new NodeReference(*o.GetNode()); + // Copy the start and stop random variables if they exist + if (o.m_startVar) m_startVar = o.m_startVar->Copy(); + if (o.m_stopVar) m_stopVar = o.m_stopVar->Copy(); + if (o.m_start) ScheduleStart(); + if (o.m_stop) ScheduleStop(); +} + + +// \brief Application Destructor +Application::~Application() +{ + delete m_node; + // Cancel the start/stop events if scheduled + if (m_start) Simulator::Cancel(m_startEvent); + if (m_stop) Simulator::Cancel(m_stopEvent); + // Delete the random variablse + delete m_startVar; + delete m_stopVar; +} + +Application& Application::operator=(const Application& rhs) +{ + if (this == &rhs) return *this; // Self assignment + delete m_node; + m_node = nil; + if (rhs.GetNode())m_node = new NodeReference(*rhs.GetNode()); + + delete m_startVar; + m_startVar = nil; + if (rhs.m_startVar) m_startVar = rhs.m_startVar->Copy(); + + delete m_stopVar; + m_stopVar = nil; + if (rhs.m_stopVar) m_stopVar = rhs.m_stopVar->Copy(); + + m_start = false; + if (rhs.m_start) ScheduleStart(); + if (rhs.m_stop) ScheduleStop(); + return *this; +} + + +// \brief Specify application start time +// The virtual method STartApp will be called at the time +// specified by startTime. +// \param Time to start application (absolute time, from start of simulation) +void Application::Start(const Time& startTime) +{ + delete m_startVar; + m_startVar = new ConstantVariable(startTime.GetSeconds()); + ScheduleStart(); +} + +void Application::Start(const RandomVariable& startVar) +{ // Start at random time + delete m_startVar; + m_startVar = startVar.Copy(); + ScheduleStart(); +} + + +// \brief Specify application stop time +// The virtual method StopApp will be called at the time +// specified by stopTime. +// \param Time to stop application (absolute time, from start of simulation) +void Application::Stop(const Time& stopTime) +{ + delete m_stopVar; + m_stopVar = new ConstantVariable(stopTime.GetSeconds()); + ScheduleStop(); +} + +void Application::Stop(const RandomVariable& stopVar) +{ // Stop at random time + delete m_stopVar; + m_stopVar = stopVar.Copy(); + ScheduleStop(); +} + +// \brief Assign this application to a given node +// Called by the application manager capability when adding +// an application to a node. +void Application::SetNode(const Node& n) +{ + delete m_node; + m_node = new NodeReference(n); +} + +Node* Application::GetNode() const +{ + return m_node->GetNode(); +} + +// Protected methods +// StartApp and StopApp will likely be overridden by application subclasses +void Application::StartApplication() +{ // Provide null functionality in case subclass is not interested +} + +void Application::StopApplication() +{ // Provide null functionality in case subclass is not interested +} + + +// Private helpers +void Application::ScheduleStart() +{ + m_startEvent = Simulator::Schedule(Seconds(m_startVar->GetValue()) - + Simulator::Now(), + &Application::StartApplication, this); + m_start = true; +} + +void Application::ScheduleStop() +{ + m_stopEvent = Simulator::Schedule(Seconds(m_stopVar->GetValue()) - + Simulator::Now(), + &Application::StopApplication, this); + m_stop = true; +} + +} //namespace ns3 + + diff --git a/src/node/application.h b/src/node/application.h new file mode 100644 index 000000000..834f0062e --- /dev/null +++ b/src/node/application.h @@ -0,0 +1,136 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006 Georgia Tech Research Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: George F. Riley + */ + +#ifndef __APPLICATION_H__ +#define __APPLICATION_H__ + +// +// \brief The base class for all ns3 applicationes +// +// Class Application is the base class for all ns3 applications. +// Applications are associated with individual nodes, and are created +// using the AddApplication method in the ApplicationManager capability. +// +// Conceptually, an application has zero or more Socket +// objects associated with it, that are created using the Socket +// creation API of the Kernel capability. The Socket object +// API is modeled after the +// well-known BSD sockets interface, although it is somewhat +// simplified for use with ns3. Further, any socket call that +// would normally "block" in normal sockets will return immediately +// in ns3. A set of "upcalls" are defined that will be called when +// the previous blocking call would normally exit. THis is documented +// in more detail Socket class in socket.h. +// +// There is a second application class in ns3, called "ThreadedApplication" +// that implements a true sockets interface, which should be used +// when porting existing sockets code to ns3. The true +// sockets approach is significantly +// less memory--efficient using private stacks for each defined application, +// so that approach should be used with care. The design and implementation +// of the ThreadedApplication are still being discussed. + +#include "ns3/event-id.h" +#include "ns3/nstime.h" + +namespace ns3 { + +class Node; +class NodeReference; +class RandomVariable; + +class Application { +public: + Application(); + Application(const Application&); // Copy constructor + Application& operator=(const Application&); // Assignment operator + virtual ~Application(); + + virtual Application* Copy() const = 0; // All applications must provide + + // \brief Specify application start time + // Applications start at various times in the simulation scenario. + // The Start method specifies when the application should be + // started. The application subclasses should override the + // private "StartApplication" method defined below, which is called at the + // time specified, to cause the application to begin. + // \param Start time for this application, relative to the + // current simulation time. + void Start(const Time&); + + // \brief Same as above, but uses a random variable for start time + // The random variable returns the desired start time in units of + // Seconds. + +void Start(const RandomVariable&); + + // \brief Specify application stop time + // Once an application has started, it is sometimes useful + // to stop the application. The Stop method specifies when an + // application is to stop. The application subclasses should override + // the private StopApplication method defined below, to cause the application + // to stop. + // \param Stop time for this application, relative to the + // current simulation time. + void Stop(const Time&); + + // \brief Same as above, but uses a random variable for stop time + // The random variable returns the desired stop time in units of + // Seconds. + void Stop(const RandomVariable&); + + // \brief Attaches an application to a specific node + // Specifies which node object this application is associated with. + // \param Node object to associate with this application. + void SetNode(const Node&); + + // \brief Returns the pointer to the attached node. + Node* GetNode() const; + + // Members + NodeReference* m_node; // All applications have an associated node + RandomVariable* m_startVar; // Random variable for start time + RandomVariable* m_stopVar; // Random variable for stop time + EventId m_startEvent;// Event identifier for start event + EventId m_stopEvent; // Event identifier for the stop event + bool m_start; // True if start event scheduled + bool m_stop; // True if stop event scheduled + +protected: + // \brief Application specific startup code + // The StartApplication method is called at the start time specifed by Start + // This method should be overridden by all or most application + // subclasses. + virtual void StartApplication(); + + // \brief Application specific shutdown code + // The StopApplication method is called at the stop time specifed by Stop + // This method should be overridden by all or most application + // subclasses. + virtual void StopApplication(); + +private: + // Helpers + void ScheduleStart(); + void ScheduleStop(); +}; + +} //namespace ns3 +#endif diff --git a/src/node/node-reference.h b/src/node/node-reference.h new file mode 100644 index 000000000..3ad5a1e0b --- /dev/null +++ b/src/node/node-reference.h @@ -0,0 +1,45 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +// +// Copyright (c) 2006 Georgia Tech Research Corporation +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation; +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Author: George F. Riley +// + +// Define a class that wraps a node pointer. This allows numerous ns3 +// objects to have access to a node, but without ambiguity of whether +// the owner should "delete" it. + +// George F. Riley, Georgia Tech, Spring 2007 + +#ifndef __NODE_REFERENCE_H__ +#define __NODE_REFERENCE_H__ + +namespace ns3 { + +class Node; + +class NodeReference { +public: + NodeReference(const Node& n) + : m_node(n) {} + Node* GetNode() const { return (Node*)&m_node;} +public: + const Node& m_node; +}; + +} // namespace ns3 + +#endif