Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eigen matrix library filling a matrix with random float values in a given range

Tags:

c++

eigen

eigen3

The setRandom function in the Eigen matrix library fills a given matrix with random numbers in the range [-1,1]. How can I extend this to generate numbers within any given range? I require floating point numbers and I am okay with pseudo-randomness.

I have tried doing the following:

B = LO + A.cast<double>().array()/(static_cast <double>(RAND_MAX)/(HI-LO));

Here A is the matrix in question and [LO,HI] is the range I am looking to fill it in. The problem is that the value of RAND_MAX for me is 2147483647 and this is messing up the entire calculation.

Any help is much appreciated.

like image 305
pincir Avatar asked Mar 06 '16 14:03

pincir


4 Answers

This might help:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main()
{
  double HI = 12345.67; // set HI and LO according to your problem.
  double LO = 879.01;
  double range= HI-LO;
  MatrixXd m = MatrixXd::Random(3,3); // 3x3 Matrix filled with random numbers between (-1,1)
  m = (m + MatrixXd::Constant(3,3,1.))*range/2.; // add 1 to the matrix to have values between 0 and 2; multiply with range/2
  m = (m + MatrixXd::Constant(3,3,LO)); //set LO as the lower bound (offset)
  cout << "m =\n" << m << endl;
}

Output:

m =
10513.2 10034.5  4722.9
5401.26 11332.6 9688.04
9858.54 3144.26 4064.16

The resulting matrix will contain pseudo-random elements of the type double in the range between LO and HI.

like image 85
RHertel Avatar answered Oct 22 '22 08:10

RHertel


Combine the c++11 random number generators with a nullary expression from Eigen:

std::random_device rd;
std::mt19937 gen(rd());  //here you could also set a seed
std::uniform_real_distribution<double> dis(LO, HI);

//generate a 3x3 matrix expression
Eigen::MatrixXd::NullaryExpr random_matrix(3,3,[&](){return dis(gen);});

//store the random_number in a matrix M
Eigen::MatrixXd M = random_matrix;

Note that you get a new random number each time you call random_matrix(0,0). That's ok for matrix operations which access the element once. If you need a random matrix that is used in more than one place, you can save it into an Eigen matrix M as shown in the last line.

like image 33
davidhigh Avatar answered Oct 22 '22 08:10

davidhigh


If you can use C++ 11/14 , the following works.

#include <random>
std::default_random_engine generator;
std::uniform_real_distribution<double> distribution(0.0,1.0);
double number = distribution(generator)

This will generate random float values between the range L and R for distribution(L,R)

like image 1
Mutating Algorithm Avatar answered Oct 22 '22 09:10

Mutating Algorithm


How about this way?

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



int main(){

  std::random_device rd;
  std::mt19937 gen(rd());  
  std::uniform_real_distribution<float> dis(0, 1);

  Eigen::MatrixXf m = Eigen::MatrixXf::Zero(10,10).unaryExpr([&](float dummy){return dis(gen);});
  cout<<"Uniform random matrix:\n"<<m<<endl;
  cout<<"Mean: "<<m.mean()<<endl;

  return 0;
}

Here I replaced NullaryExpr which was used in @davidhigh with unaryExpr. Reason for this is that I got some weird errors when I tried @davidhigh answer.

Edit: based on @arprice #if EIGEN_VERSION_AT_LEAST(3, 3, 0) auto rand_fn = [&](){return uni(gen);}; #else auto rand_fn = [&](float){return uni(gen);}; #endif Eigen::Vector3d::NullaryExpr(rand_fn);

like image 1
GPrathap Avatar answered Oct 22 '22 08:10

GPrathap