Установите коэффициенты Eigen::Matrix в соответствии с произвольным распределением

Eigen::Matrix имеет метод setRandom(), который установит все коэффициенты матрицы в случайные значения. Однако существует ли встроенный способ установки всех матричных коэффициентов в случайные значения при указании используемого распределения.

Есть ли способ добиться чего-то вроде следующего:

Eigen::Matrix3f myMatrix;
std::tr1::mt19937 gen;
std::tr1::uniform_int<int> dist(0,MT_MAX);
myMatrix.setRandom(dist(gen));

person gutkha    schedule 13.06.2012    source источник


Ответы (4)


Вы можете делать то, что хотите, используя Boost и unaryExpr. Функция, которую вы передаете unaryExpr, должна принимать фиктивный ввод, который вы можете просто игнорировать.

#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>
#include <iostream>
#include <Eigen/Dense>

using namespace std;
using namespace boost;
using namespace Eigen;

double sample(double dummy)
{
  static mt19937 rng;
  static normal_distribution<> nd(3.0,1.0);
  return nd(rng);
}

int main()
{
  MatrixXd m =MatrixXd::Zero(2,3).unaryExpr(ptr_fun(sample));
  cout << m << endl;
  return 0;
}
person daknowles    schedule 27.07.2013

Помимо равномерного распределения, я не знаю никаких других типов распределения, которые можно было бы использовать непосредственно на матрице. Что вы можете сделать, так это сопоставить унифицированный дистрибутив, предоставленный Eigen, непосредственно с вашим настраиваемым дистрибутивом (если сопоставление существует).

Предположим, что ваше распределение является сигмовидным. Вы можете сопоставить равномерное распределение с сигмовидным распределением, используя функцию y = a / (b + c exp(x)).

Путем временного преобразования вашей матрицы в массив вы можете работать поэлементно со всеми значениями вашей матрицы :

Matrix3f uniformM;
uniformM.setRandom();

Matrix3f sigmoidM;
sigmoidM.array() = a * ((0.5*uniformM+0.5).array().exp() * c + b).inv();
person Pierluigi    schedule 28.03.2013

Если кто-то сталкивается с этой веткой, я публикую более простой ответ, который возможен в настоящее время и не требует повышения. Я нашел это в старом отчете Eigen Bugzilla. Все заслуги принадлежат автору Гаэлю Геннебо за предложение следующего простого метода:

#include <Eigen/Sparse>
#include <iostream>
#include <random>

using namespace Eigen;

int main() {
  std::default_random_engine generator;
  std::poisson_distribution<int> distribution(4.1);
  auto poisson = [&] (int) {return distribution(generator);};

  RowVectorXi v = RowVectorXi::NullaryExpr(10, poisson );
  std::cout << v << "\n";
}

Обратите внимание, что подпись с аргументом int лямбда-функции требуется для Eigen NullaryExpr, несмотря на то, что она не используется здесь в примере.

person Jan Ca    schedule 22.01.2020

У меня была проблема с похожей проблемой, и я попытался решить ее с помощью NullaryExpr. Но проблема с NullaryExpr заключается в том, что его нельзя явно векторизовать. Таким образом, решение с NullaryExpr работает достаточно медленно.

Поэтому я разработал EigenRand, надстройку случайного распределения для Eigen. Я думаю, это поможет тем, кто хочет быстро и легко сгенерировать случайное число.

#include <Eigen/Dense>
#include <EigenRand/EigenRand>
#include <iostream>

using namespace Eigen;

int main() {
  Rand::Vmt19937_64 generator;

  // poisson distribution with rate = 4.1
  MatrixXi v = Rand::poisson<MatrixXi>(4, 4, generator, 4.1);
  std::cout << v << std::endl;

  // normal distribution with mean = 3.0, stdev = 1.0
  MatrixXf u = Rand::normal<MatrixXf>(4, 4, generator, 3.0, 1.0);
  std::cout << u << std::endl;

  return 0;
}
person bab2min    schedule 04.07.2020