在犰狳中使用gsl随机数生成器

时间:2019-01-29 16:39:28

标签: c++ random armadillo gsl

我正在用C ++编写一些代码,用于科学计算。我选择使用的线性代数库是Armadillo。我的问题是Armadillo使用简单的rand()函数或Mersenne Twister rng,而我需要更好的质量数字,例如ranlux。 GSL提供了ranulx的实现,而Armadillo通过定义预处理器宏ARMA_RNG_ALT并编写适当的头文件(称为arma_rng_alt.hpp)来允许外部rng。

现在,我不是C ++向导,但是我设法通过复制或粘贴现有标头arma_rng_cxx98.hpp和arma_rng_cxx11.hpp来做到这一点。我的解决方案可能不是最漂亮的,但我认为它可以正常工作。这是我的标头的一部分:

#if defined(ARMA_RNG_ALT)
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#define RNG_TYPE gsl_rng_ranlxd1

class arma_rng_alt
{
    public:

    typedef unsigned long int seed_type;

    inline void set_seed(const seed_type val);

    arma_inline int    randi_val();
    arma_inline double randu_val();
    arma_inline double randn_val();


    private:

    gsl_rng* engine;
};

inline
void
arma_rng_alt::set_seed(const arma_rng_alt::seed_type val)
{
    engine = gsl_rng_alloc(RNG_TYPE);
    gsl_rng_set(engine, val);
}

arma_inline
int
arma_rng_alt::randi_val()
{
    return gsl_rng_get(engine);
}

arma_inline
double
arma_rng_alt::randu_val()
{
    return gsl_rng_uniform(engine);
}

arma_inline
double
arma_rng_alt::randn_val()
{
    return gsl_ran_gaussian_ziggurat(engine, 1.);
}

#endif

现在,如果该外部rng被armadillo视为没有私有变量的类(例如,在arma_rng_cxx98.hpp标头中,使用rand()且不需要分配引擎),那将是可以的。相反,我需要分配引擎并每次都调用它,因此我需要实例化该类,否则会出现“没有对象就无法调用成员函数”错误。因此,我实际上需要修改Armadillo库本身的标头,即arma_rng.hpp。 为了使事情更清楚,这是原始arma_rng.hpp中用于生成随机整数的典型块的样子:

template<typename eT>
struct arma_rng::randi
  {
  arma_inline
  operator eT ()
    {
    #if   defined(ARMA_RNG_ALT)
      {
      return eT( arma_rng_alt::randi_val() );
      }
    #elif defined(ARMA_USE_EXTERN_CXX11_RNG)
      {
      return eT( arma_rng_cxx11_instance.randi_val() );
      }
    #else
      {
      return eT( arma_rng_cxx98::randi_val() );
      }
    #endif
    }

如您所见,如果使用cxx98或alt,则仅调用randi_val函数,而如果使用cxx11,则在calss arma_rng_cxx11(在标头中较早声明的线程局部变量)的实际实例上调用randi_val。 。我需要的是类似于cxx11的东西,因此这是我修改此特定示例的库标头arma_rng.hpp的方式:

template<typename eT>
struct arma_rng::randi
  {
  arma_inline
  operator eT ()
    {
    #if   defined(ARMA_RNG_ALT)
      {
      return eT( arma_rng_alt_instance.randi_val() );
      }
    #elif defined(ARMA_USE_EXTERN_CXX11_RNG)
      {
      return eT( arma_rng_cxx11_instance.randi_val() );
      }
    #else
      {
      return eT( arma_rng_cxx98::randi_val() );
      }
    #endif
    }

在声明我自己创建的类arma_rng_alt的线程本地实例之后。

运作起来很吸引人,但是要注意的是,现在我需要在HPC集群上运行代码,并且虽然可以创建自己的arma_rng_alt.hpp,但不能修改库头文件arma_rng.hpp本身。因此,我需要一种使原始标头正常工作的方法(因此无需实例化该类)。您对此有任何想法吗?坦率地说,我的C ++专业知识已达到极限。

谢谢

0 个答案:

没有答案