【问题标题】:Initialize multiple distributions using the same seed or same random stream?使用相同的种子或相同的随机流初始化多个分布?
【发布时间】:2017-04-04 22:18:06
【问题描述】:

我有一个 Java 模拟,我需要在其中使用 UniformExponentialPoissonGamma 分布 - 我需要初始化随机流和/或这些分布中的每一个种子(这样我就可以精确地再现轨迹给定一个固定的种子)。

我正在使用Parallel Colt(这是 Colt 的多线程版本)。

对于Uniform,我可以正确地将DoubleUniform 对象(从cern.jet.random.tdouble.DoubleUniform 导入后)作为:

int fixedSeed = 12345;
doubleUniformDist = new DoubleUniform (0.0, 1.0, fixedSeed);

但是,对于 ExponentialPoissonGamma 分布(都在 cern.jet.random.tdouble),我不能通过传递 fixedSeed 来做同样的事情 - 因为他们希望传递 DoubleRandomEngine 对象:

构造函数总结

Exponential(double lambda, DoubleRandomEngine randomGenerator)
构造负指数分布。

Poisson(double mean, DoubleRandomEngine randomGenerator)
构造泊松分布。

Gamma(double alpha, double lambda, DoubleRandomEngine randomGenerator)
构造 Gamma 分布。

有没有办法像使用Uniform 一样初始化这些(ExponentialPoissonGamma)?或者我应该在cern.jet.random.tdouble 中实例化一个父类/基类(如果是,如何?),所有这些类都从该类扩展而来?

注意事项:

  1. 再次,我想要一个随机流(这样我所有的 分布可以使用该流中的随机数) - 这是 对于重现性非常重要。
  2. 一个示例模拟可能需要对这些分布进行数百万次(总共)采样 - 因此性能/速度始终是一个问题。

【问题讨论】:

    标签: java random simulation colt


    【解决方案1】:

    它看起来像 DoubleMersenneTwister,它扩展了 DoubleRandomEngine,允许您在其构造函数中设置种子。

    【讨论】:

    • 是的,MersenneTwister64 也是。但是这些似乎都没有指数、泊松和伽马分布——所以没有办法用我可以用来播种 DoubleMersenneTwister 的相同种子来播种。
    • 呃,我相信您使用已知种子播种 DoubleMersenneTwister,然后使用 那个 来构建指数、泊松和伽玛数生成器。还是我误解了你需要什么?
    • 是的,我可以使用已知种子为DoubleMersenneTwister 播种,但不能使用它来构造Exponential - 因为Exponential constructor 需要一个RandomEngine 对象,如果我通过@ 987654328@,Exponential 似乎没有正确播种(我用相同的种子得到不同的结果 - 这是错误的)。
    • 我认为您完全理解我的问题 - 只是我这样做得到了意想不到的结果 - 所以想知道我做错了什么?
    【解决方案2】:

    各种随机变量的生成都以 Uniform(0,1) 随机数开始。 ExponentialPoissonGamma 的构造函数中的最后一个参数是为您提供 Uniform(0,1) 的源,它扩展了 DoubleRandomEngine 抽象类。它看起来像Parallel Colt provides half a dozen such implementations。您需要选择其中一个,为要生成的每个分发创建一个单独但种子相同的实例,然后使用您创建的 DoubleRandomEngine 实例之一构造每个分发对象。这样,底层的统一价值流将是相同的,并且可以适当地转换为您想要的分布。

    这是一个相当简约的实现:

    import cern.jet.random.tdouble.*;
    import cern.jet.random.tdouble.engine.*;
    
    public class RNG {
      public static void main(String[] args) {
        // create two instances of Mersenne Twister, seeded identically
        DoubleRandomEngine twister1 = new DoubleMersenneTwister(42);
        DoubleRandomEngine twister2 = new DoubleMersenneTwister(42);
        // print ten values from each, to show they produce identical U(0,1)'s'
        for(int i = 0; i < 10; ++i) {
          System.out.println(twister1.nextDouble() + ", " + twister2.nextDouble());
        }
        System.out.println("\nNow for some exponentials...\n");
        // instantiate two exponentials using our two twisters as the
        // underlying random engine
        Exponential exp1 = new Exponential(3, twister1);
        Exponential exp2 = new Exponential(3, twister2);
        // and print 10 of 'em to show they're synchronized.
        for(int i = 0; i < 10; ++i) {
          System.out.println(exp1.nextDouble() + ", " + exp2.nextDouble());
        }
      }
    }
    

    由于Exponential 类将提供的由“引擎”生成的制服流转换为指数 RV,并且制服是相同的种子,因此指数实际上是相同的种子。

    【讨论】:

    • 我试过这个...选择 MersenneTwister64:MersenneTwister64 myMT = new MersenneTwister64 (seed); 然后创建一个指数为:Exponential expDist = new Exponential (0.5, myMT);希望上面会为指数创建一个“独立但种子相同的实例”......
    • 但是,我无法重现相同的随机数流。我的猜测是 Exponential 构造函数中的最后一个参数需要一个 RandomEngine 对象,但我传递的是一个 MersenneTwister64 对象
    • ,派生自 RandomEngine。在将 MersenneTwister64 (myMT) 传递给 Exponential 构造函数之前,不确定如何正确地将其转换为 RandomEngine 对象?你能提供一个最小的例子吗?
    • 那么这对你不起作用是有什么原因吗?
    • 再次感谢您 - 我已经解决了。看起来不同的数字是由于我使用了staticNextDouble() 方法 - 这不适合我的目的,因为staticNextDouble() 使用 rng 的内部/默认种子,绕过了我提供的种子。 @pjs
    【解决方案3】:

    所有,谢谢 - 我已经解决了。看起来我之前得到的不同数字是由于我使用了staticNextDouble() 方法——这不适合我的目的,因为staticNextDouble() 使用随机数生成器的内部/默认种子,绕过了我提供的固定外部种子.

    在用 nextDouble() 替换 staticNextDouble() 调用后,我现在可以准确地再现给定外部种子的轨迹。

    【讨论】:

      猜你喜欢
      • 2018-03-05
      • 2015-10-12
      • 2020-11-03
      • 1970-01-01
      • 2012-08-30
      • 1970-01-01
      • 1970-01-01
      • 2012-11-03
      • 2011-06-13
      相关资源
      最近更新 更多