ns-3-manual.pdf 随机值翻译
1.2 Random Variables
ns-3包含一个内置的伪随机数产生器(PRNG)。这对于仿真实验严格的用户来理解PRNG的功能,配置,用法和决定是否满足实验的要求是非常重要的。
1.2.1 Quick Overview
ns-3 random numbers are provided via instances of ns3::RandomVariableStream.
By default, ns-3 simulations use a fixed seed; if there is any randomness in the simulation, each run of the program will yield identical results unless the seed and/or run number is changed.
In ns-3.14 and earlier, ns-3 simulations used a different wrapper class called ns3::RandomVariable. This implementation is documented above under Legacy Random Variables. As of ns-3.15, this class has been replaced by ns3::RandomVariableStream; the underlying pseudo-random number generator has not changed.
To obtain randomness across multiple simulation runs, you must either set the seed differently or set the run number differently. To set a seed, call ns3::RngSeedManager::SetSeed() at the beginning of the program; to set a run number with the same seed, call ns3::RngSeedManager::SetRun() at the beginning of the program.
If you intend to perform multiple runs of the same scenario, with different random numbers, please be sure to read the manual section on how to perform independent replications.
ns-3的随机数是通过ns3::RandomVariableStream实例提供的。
默认情况下,ns-3仿真器使用固定的种子;如果仿真中有任何的随机性,每次程序运行将会产生相同的结果,除非改变种子和/或者运行次数。
在ns-3.3或者更早的版本中,ns-3仿真器使用默认的随机种子;从ns-3.4开始这一策略进行了改变。
在ns-3.14或者更早版本中,ns-3仿真器使用不同的称为ns3::RandomVariable包装类。这个实现是在传统随机变量上面记录。从ns-3.15,这个类被ns3::RandomVariableStream所代替;但是底层的伪随机数发生器没有发生改变。
为了通过多次仿真运行获得随机性,你必须要么设置不同的种子要么设置不同的运行次数。要设置种子的话,在程序的开始位置调用ns3::RngSeedManager::SetSeed();要设置运行次数,在程序的开始位置调用ns3::RngSeedManager::SetRun()。
在ns-3中所使用的每一个RandomVariableStream都有一个与之关联的伪随机数产生器;
所有的随机变量使用基于全局种子-要么是固定的要么是随机的种子。
如果你想要使用不同的随机数,测试相同情景下多次运行的性能,情一定阅读手册中how to perform independent replications章节。
1.2.2 Background
模拟过程使用大量的随机数; 研究[cite]表明大多数网络模拟花费多达 50%的
CPU 时间来生成随机数。用户需要关注(伪)随机数的质量以及不同随机数流
之间的独立性。
用户需要关注一些内容,比如:
- 随机数生成器的种子化以及某个模拟过程是否是确定性的,
- 如何获得彼此独立的随机数流,以及
- 随机数流循环一次的时间有多久
这里我们引入一些术语:RNG 提供很长的(伪)随机数序列。这个序列的长度
叫做 cycle length 或 period,在该循环长度或周期过后,RNG 将重复自身。该
序列可以被划分为互不关联的 streams。RNG 的流是 RNG 的一个连续的子集
或者块。例如,如果 RNG 周期的长度为 N,且这个 RNG 提供两个流,则第一
个流可能使用前 N/2 个值,第二个流可能产生后边的 N/2 个值。一个重要的性
质是:这两个流是互不关联的,同样,每个流可以被划分为互不关联的若干个
substreams。底层 RNG 希望能够产生有着非常长的循环长度的伪随机数序列,
并以有效地方式将序列划分为流和子流。
ns-3 使用与 ns-2 相同的底层随机数生成器:the MRG32k3a generator from
Pierre L’Ecuyer. 详细的描述可以再这里找到:
http://www.iro.umontreal.ca/~lecuyer/myftp/papers/streams00.pdf.
MRG32k3a 生成器提供 1.8×10^19 个独立的随机数流,其中每个流都由
2.3×10^15 个子流组成。每个子流的周期(i.e., the number of random numbers
before overlap)为 7.6×10^22。整个生成器的周期为 3.1×10^57。
类ns3::RandomVariableStream是底层随机数生成器的公共接口。当用户创建新的
RandomVariables(比如 ns3::UniformRandomVariable,ns3::ExponentialRandomVariable等)时,将创
建一个对象,该对象使用随机数生成器的彼此独立的流中的某一个流。因此,
每个具有类型ns3::RandomVariableStream的对象都在概念上有自己的“虚拟的”RNG. 另
外,每个ns3::RandomVariableStream都可以被设置为使用由main stream获得的
substreams中的某个子流。
另一个可选的实现是:允许每个RandomVariable拥有自己的(被不同的种子种
子化过的)RNG。但是,在这种情况下我们无法保证不同的序列将互不关联。
因此,我们选择使用单个的 RNG 以及由该RNG获得的流与子流。
1.2.3 Creating random variables
ns-3支持从基类RandomVariableStream派生的许多随机变量对象。这些对向从ns3::Object派生来的,可以使用智能指针处理。
正确的产生这些对象的模板方法是CreateObject<>,例如:
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable> ();
然后你就可以获取值,通过调用对象的下面的方法:
myRandomNo = x->GetInteger ();
如果你尝试使用下面的方式替换上面的方法:
myRandomNo = UniformRandomVariable().GetInteger ();
你的程序将遇到分割故障,因为上面的实现过程依赖于仅发生在调用CreateObject方法的属性构造器。
本章的其余大部分内容讨论产生自这样的对象的伪随机数流的属性,和如何控制这类对象的种子。
1.2.4 Seeding and independent replications
ns-3 的模拟过程可以被设置为来产生确定的或者随机的结果。如果模拟过程被
设置为使用固定的、确定的种子以及相同的运行次数,那么每次运行的输出都应
该是相同的。
在默认情况下,ns-3 的模拟过程使用固定的种子和运行次数。这些值存储在两
个 ns3::GlobalValue 实例中: g_rngSeed 和 g_rngRun。
典型的情况是对某个模拟过程进行多次独立试验。以便根据大量的独立运行来计
算统计信息。用户可以改变全局种子并再次运行该模拟过程,也可以推进 RNG
的子流的状态,这被称为增加运行次数。
类 ns3::SeedManager ()提供一个 API 来控制设置种子和运行次数的行为。这
个设置种子和子流状态的设置必须在创建任何随机变量之前被调用。例如:
SeedManager::SetSeed (3); // Changes seed from default of 1 to 3
SeedManager::SetRun (7); // Changes run number from default of 1 to 7
// Now, create random variables
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable> ();
Ptr<ExponentialRandomVariable> y = CreateObject<ExponentialRandomVarlable> ();
...
设置新的种子和推进子流的状态,哪一个更好?无法保证流产生的两个随机种子
不是互相重叠的(译者注:即有可能部分一致)。保证两个流不互相重叠的唯一
办法是使用由 RNG 的实现提供的子流功能。 因此,使用子流功能来实现同一
个模拟过程的多个彼此独立的运行。 换句话说,统计学上,设置独立的重复实
验更严格的方法应该是使用固定的种子并改变运行次数。这样的实现考虑到使用
子流时,独立的重复实验的最大值为 2.3×10^15。
为了方便使用,用户不必在程序中控制种子和运行次数,用户可以设置环境变量
NS_GLOBAL_VALUE像如下方式:
$ NS_GLOBAL_VALUE="RngRun=3" ./waf --run program-name
另一个控制的方法是传递一个命令行参数,因为是 ns3 的 GlobalValue,所以等
价于如下:
$ ./waf --command-template="%s --RngRun=3" --run program-name
或者,如果直接在 waf 之外运行程序:
$ ./build/optimized/scratch/program-name --RngRun=3
上述的各种命令行用法使得由 shell 脚本通过传递不同的 RngRun 系数来运行大
量不同的模拟变得很容易。
1.2.5 Class Random VariableStream
所有随机变量都应该派生自 类 RandomVariable。该基类提供了一些在全局层
面设置随机数生成器的行为的静态方法。派生类提供了刻画随机特性的 API,这
些随机特性由特殊的分布决定。
模拟过程中被创建的每一个 RandomVariableStream 都将被给予一个生成器,该生成器
是来自于底层 PRNG 的一个新的 RNGStream。按照这种方法来使用,the
L’Ecuyer implementation 考虑到了最多 1.8×10^19 个随机变量。每个随机变量
在某个单个的实验中可以在出现重叠前产生多达 7.6×10^22 个随机数。
1.2.6 Base class public API
以下摘录了一些类RandomVariable的访问在子流中的下一个值的公共方法。
/**
* \brief Returns a random double from the underlying distribution
* \return A floating point random value
*/
double GetValue (void) const;
/**
* \brief Returns a random integer from the underlying distribution
* \return Integer cast of ::GetValue()
*/
uint32_t GetInteger (void) const;
我们已经描述了种子配置。不同的RandomVariable子类可能有额外的API。
1.2.7 Types of RandomVariables
下面提供了随机变量的类型,并且已经在ns-3 Doxygen文档中了或者阅读src/core/model/random-variable-stream.h。用户可以通过继承基类RandomVariableStream创建自定义的随机变量。
• class UniformRandomVariable
• class ConstantRandomVariable
• class SequentialRandomVariable
• class ExponentialRandomVariable
• class ParetoRandomVariable
• class WeibullRandomVariable
• class NormalRandomVariable
• class LogNormalRandomVariable
• class GammaRandomVariable
• class ErlangRandomVariable
• class TriangularRandomVariable
• class ZipfRandomVariable
• class ZetaRandomVariable
• class DeterministicRandomVariable
• class EmpiricalRandomVariable
1.2.8 Semantics(语义) of RandomVariableStream objects
RandomVariableStream对象派生自ns3::Object,并可以使用智能指针进行处理。
RandomVariable 对象还可以被 ns-3 的 attributes 使用,这表示可以通过 ns-3
的 attribute system 来给 RandomVariable 对象赋值。以下是一个关于
WifiNetDevice 的 propagation 模型的例子:
TypeId
RandomPropagationDelayModel::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::RandomPropagationDelayModel")
.SetParent<PropagationDelayModel> ()
.SetGroupName ("Propagation")
.AddConstructor<RandomPropagationDelayModel> ()
.AddAttribute ("Variable",
"The random variable which generates random delays (s).",
StringValue ("ns3::UniformRandomVariable"),
MakePointerAccessor (&RandomPropagationDelayModel::m_variable),
MakePointerChecker<RandomVariableStream> ())
;
return tid;
}
这里,ns-3 的用户可以通过 attribute system 改变这个延迟模型的默认随机变
量(which is a UniformVariable ranging from 0 to 1)。
1.2.9 Using other PRNG
目前没有关于替换底层随机数生成器的支持(例如:the GNU Scientific Library
or the Akaroa package),欢迎提供程序包。
1.2.10 Setting the stream number
底层的MRG32k3a产生器提供了2^64个独立的流。在ns-3中,这些流被数序分配,开始于新的RandomVariableStream实例第一次调用GetValue()的第一个流。
作为这些RandomVariableStream对象如何被分配到底层的流的结果,这种分配对仿真配置的扰动是敏感的。后果就是,任何仿真配置的方面改变了,RandomVariables的对应关系可能改变,也可能不变。
作为一个具体的例子,一个用户运行了相对应的研究实验,在两个路由协议中,可能存在这样的事实,改变一个路由协议,另一个路由协议可能注意到底层的变化模式而改变。
从ns-3.15开始,提供了一些控制方法给用户,用户可选择的用RandomVariableStream对象到底层流来优化配置。这就是Stream属性,它是基类RandomVariableStream的一部分。
通过从之前流中存在的序列分区成相等大小的两部分:
<-------------------------------------------------------------------------->
stream 0 stream (2^64 - 1)
<-------------------------------------------------------------------------->
^ ^^ ^
| || |
stream 0 stream (2^63 - 1) stream 2^63 stream (2^64 - 1)
<- automatically assigned -----------><- assigned by user ----------------->
前面的263流仍然是自动分配的,而最后的所给定的263从0上升到2^63-1.
The assignment of streams to a fixed stream number is optional; instances of RandomVariableStream that do not have
a stream value assigned will be assigned the next one from the pool of automatic streams.
To fix a RandomVariableStream to a particular underlying stream, assign its Stream attribute to a non-negative
integer (the default value of -1 means that a value will be automatically allocated).
1.2.11 Publishing your results
当发布模拟结果时,你需要陈述的一个关键配置信息是你是如何使用随机数生成
器的。
• 你使用了什么样的种子,what seeds you used,
• 如果没有使用默认的 RNG,那么你使用的 RNG 是什么,
• 彼此独立的运行时如何执行的,
• 对于大规模的模拟,你如何检验没有发生循环。
研究者应该对发布的结果提供足够的信息以使得别人能够再现他的结果,这一点
是责无旁贷的。研究者还应该充分弄明白所使用的随机数是统计学上合法的,并
在文章中陈述为什么做出这样的假定,这一点也是责无旁贷的。
1.2.12 Summary
让我们回顾一下在创建模拟过程时应该做些什么。
• 决定使用固定的种子还是随机的种子,默认情况使用随机的种子,
• 决定如何处理独立的重复实验,
• 对于长时间的模拟,如果可行的话,确认自己没有产生多于循环长度的随机值,
• 当发布结果时,按照上述的指导来对随机数生成器的使用书写文档。
网友评论