Add random number files, base class Application

This commit is contained in:
Tom Henderson
2007-03-17 22:32:08 -07:00
parent c6bb8b9b64
commit 7868600d6b
8 changed files with 2047 additions and 1 deletions

View File

@@ -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',

574
src/core/random-variable.cc Normal file
View File

@@ -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<raj.b@gatech.edu>
//
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <sys/time.h> // for gettimeofday
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#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<ValueCDF>::size_type bottom = 0;
std::vector<ValueCDF>::size_type top = emp.size() - 1;
while(1)
{
std::vector<ValueCDF>::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<ValueCDF>::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

584
src/core/random-variable.h Normal file
View File

@@ -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<raj.b@gatech.edu>
//
#ifndef __random_variable_h__
#define __random_variable_h__
#include <vector>
#include <algorithm>
#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<ValueCDF> 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

468
src/core/rng-stream.cc Normal file
View File

@@ -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<raj.b@gatech.edu>
//
#include <cstdlib>
#include <iostream>
#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<int32_t> (a / two17); a -= a1 * two17;
v = a1 * s;
a1 = static_cast<int32_t> (v / m); v -= a1 * m;
v = v * two17 + a * s + c;
}
a1 = static_cast<int32_t> (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<int32_t> (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<int32_t> (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<uint32_t> (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<int32_t> ((high - low + 1) * RandU01 ());
};
} //namespace ns3

60
src/core/rng-stream.h Normal file
View File

@@ -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<raj.b@gatech.edu>
#ifndef RNGSTREAM_H
#define RNGSTREAM_H
#include <string>
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

173
src/node/application.cc Normal file
View File

@@ -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<riley@ece.gatech.edu>
*/
// 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

136
src/node/application.h Normal file
View File

@@ -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<riley@ece.gatech.edu>
*/
#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

45
src/node/node-reference.h Normal file
View File

@@ -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<riley@ece.gatech.edu>
//
// 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