Add random number files, base class Application
This commit is contained in:
@@ -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
574
src/core/random-variable.cc
Normal 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
584
src/core/random-variable.h
Normal 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
468
src/core/rng-stream.cc
Normal 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
60
src/core/rng-stream.h
Normal 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
173
src/node/application.cc
Normal 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
136
src/node/application.h
Normal 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
45
src/node/node-reference.h
Normal 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
|
||||
Reference in New Issue
Block a user