используя генератор случайных чисел в броненосце - PullRequest
0 голосов
/ 29 января 2019

Я пишу некоторый код на C ++ для научных вычислительных целей.Библиотека линейной алгебры, которую я выбрал, - это Armadillo.Моя проблема в том, что Armadillo использует либо простую функцию rand (), либо Mersenne Twister rng, тогда как мне нужны более качественные числа, например ranlux.GSL обеспечивает реализацию ranulx, а Armadillo позволяет использовать внешний rng, определив макрос препроцессора ARMA_RNG_ALT и записав соответствующий заголовочный файл, который мы назовем arma_rng_alt.hpp.

Теперь я не волшебник 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, randi_val вызывается для фактического экземпляра calss arma_rng_cxx11 (локальная переменная потока, объявленная ранее в заголовке).Мне нужно что-то похожее на 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 ++ откровенно растянуты до предела.

Спасибо

...