Альтернативная ошибка: «Неверное измерение для аргумента 0» - PullRequest
1 голос
/ 23 декабря 2019

При преобразовании приведенного ниже примера в цикл gfor. Я обнаружил ошибку типа «Неверное измерение для аргумента 0», полное сообщение об ошибке ниже. Однако возникает ошибка, затем функция запускается, затем та же ошибка. Этот шаблон повторяется. Я сбит с толку, и мне интересно, если эта ошибка каким-то образом зависит от системы.

Полное сообщение об ошибке:

 Error in random_shuffle(theta, 5, 1) : 
 ArrayFire Exception (Invalid input size:203):
In function af_err af_assign_seq(af_array *, const af_array, const unsigned int, const af_seq *, const af_array)
In file src/api/c/assign.cpp:168
Invalid dimension for argument 0
Expected: (outDims.ndims() >= inDims.ndims())

Вторая проблема, семя не может измениться с входным параметром, при использованиицикл gfor.

#include "RcppArrayFire.h"

using namespace Rcpp;
using namespace RcppArrayFire;

// [[Rcpp::export]]
af::array random_shuffle(const RcppArrayFire::typed_array<f64> theta, int counts, int seed){

  const int theta_size = theta.dims()[0];
  af::array out(counts, theta_size, f64);
  af::array seed_seq = af::seq(seed, seed+counts);

// for(int f = 0; f < counts; f++){
gfor ( af::seq f, counts-1 ){

  af::randomEngine engine;
  engine.setSeed(af::sum<double>(seed_seq(f)));

  af::array index_shuffle(1, u16);

  af::array temp_rand(1, f64);
  af::array temp_end(1, f64);

  af::array shuffled = theta;

// implementation of the Knuth-Fisher-Yates shuffle algo
  for(int i = theta_size-1; i > 1; i --){

    index_shuffle = af::round(af::randu(1, u16, engine)/(65536/(i+1)));
    temp_rand = shuffled(index_shuffle);
    temp_end = shuffled(i);
    shuffled(index_shuffle) = temp_end;
    shuffled(i) = temp_rand;
    }

  out(f, af::span) = shuffled;
  }
  return out;
}


/*** R
theta <- 10:20
random_shuffle(theta, 5, 1)
random_shuffle(theta, 5, 2)
*/

Обновлен с помощью решения Ральфа Штунбера, но «перемешал» сэмплы в пространстве столбцов.

    // [[Rcpp::export]]
af::array random_shuffle2(const RcppArrayFire::typed_array<f64> theta, int counts, int seed) {
  int len = theta.dims(0);
  af::setSeed(seed);
  af::array tmp = af::randu(len, counts, 1);
  af::array val, idx;
  af::sort(val, idx, tmp, 1);
  af::array shuffled = theta(idx);
  return af::moddims(shuffled, len, counts);
}
/*** R
random_shuffle2(theta, 5, 1)
*/

Вот изображение вывода, сэмплирование с заменой: enter image description here

Во второй части из 50 повторений образцы движутся к анергодическому исходу.

1 Ответ

2 голосов
/ 23 декабря 2019

Почему вы хотите использовать несколько двигателей RNG параллельно? Там действительно нет необходимости в этом. В общем, должно быть достаточно использовать только глобальный двигатель ГСЧ. Также должно быть достаточно установить семя этого двигателя только один раз. Вы можете сделать это из R с помощью RcppArrayFire::arrayfire_set_seed. Кроме того, генерация случайных чисел в цикле gfor работает не так, как можно было бы ожидать, ср http://arrayfire.org/docs/page_gfor.htm.

В любом случае, я не являюсь экспертом в написании эффективных алгоритмов графического процессора, поэтому мне нравится использовать методыреализовано в библиотеках, таких как ArrayFire. К сожалению, ArrayFire не имеет алгоритма перемешивания, но соответствующая проблема имеет хорошую реализацию , которую можно обобщить для вашего случая с несколькими перемешиваниями:

// [[Rcpp::depends(RcppArrayFire)]]
#include "RcppArrayFire.h"

// [[Rcpp::export]]
af::array random_shuffle(const RcppArrayFire::typed_array<f64> theta, int counts, int seed) {
    int len = theta.dims(0);
    af::setSeed(seed);
    af::array tmp = af::randu(counts, len, 1);
    af::array val, idx;
    af::sort(val, idx, tmp, 1);
    af::array shuffled = theta(idx);
    return af::moddims(shuffled, counts, len);
}

Кстати, в зависимости от более поздней версии. использование может иметь больше смысла, чтобы расположить различные выборки в столбцах, а не в строках, поскольку как R, так и AF используют основную разметку столбцов.

...