Set coefficients of an Eigen::Matrix according an arbitrary distribution
Asked Answered
K

4

5

Eigen::Matrix has a setRandom() method which will set all coefficients of the matrix to random values. However, is there a built in way to set all the matrix coefficients to random values while specifying the distribution to use.

Is there a way to achieve something like the following:

Eigen::Matrix3f myMatrix;
std::tr1::mt19937 gen;
std::tr1::uniform_int<int> dist(0,MT_MAX);
myMatrix.setRandom(dist(gen));
Kelliekellina answered 13/6, 2012 at 23:31 Comment(0)
M
3

You can do what you want using Boost and unaryExpr. The function you pass to unaryExpr needs to accept a dummy input which you can just ignore.

#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;
}
Mcclung answered 27/7, 2013 at 0:50 Comment(0)
J
2

If anyone is coming across this thread, I'm posting an easier answer that is possible nowadays and does not require boost. I found this in an old Eigen Bugzilla Report. All credits go to the author Gael Guennebaud for proposing the following simple method:

#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";
}

Note that the signature with an int argument of the lambda function is required of Eigen NullaryExpr, despite not being used here in the example.

Jennie answered 22/1, 2020 at 2:9 Comment(0)
C
2

I had a problem with a similar problem and tried to solve it by using NullaryExpr. But a problem with NullaryExpr is that it cannot be vectorized explicitly. Thus, the solution with NullaryExpr runs quite slowly.

Because of this, I developed EigenRand, an add-on of random distribution for Eigen. I think it will help ones who want to generate random number fast and easily.

#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;
}
Cand answered 4/7, 2020 at 6:51 Comment(0)
E
1

Apart the uniform distribution I am not aware of any other types of distribution that can be used directly on a matrix. What you could do is to map the uniform distribution provided by Eigen directly to your custom distribution (if the mapping exists).

Suppose that your distribution is a sigmoid. You can map an uniform distribution to the sigmoid distribution using the function y = a / ( b + c exp(x) ).

By temporary converting your matrix to array you can operate element-wise on all values of your matrix:

Matrix3f uniformM;
uniformM.setRandom();

Matrix3f sigmoidM;
sigmoidM.array() = a * ((0.5*uniformM+0.5).array().exp() * c + b).inv();
Eileen answered 28/3, 2013 at 14:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.