MatrixXf::Random always returning same matrices - c++

I just played around with Eigen a bit and noticed that MatrixXf::Random(3,3) always returns the same matrices, first one is always this for example:
0.680375 0.59688 -0.329554
-0.211234 0.823295 0.536459
0.566198 -0.604897 -0.444451
Is that intended behaviour or am i just overseeing something really simple? (My experience with mathematic libraries is close to zero)
Code i used:
for(int i = 0; i < 5; i++) {
MatrixXf A = MatrixXf::Random(3, 3);
cout << A <<endl;
}

Instead of srand you can also use a nullary expression together with modern C++11 random number generation:
//see https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution
std::random_device rd;
std::mt19937 gen(rd()); //here you could set the seed, but std::random_device already does that
std::uniform_real_distribution<float> dis(-1.0, 1.0);
Eigen::MatrixXf A = Eigen::MatrixXf::NullaryExpr(3,3,[&](){return dis(gen);});
This also allows to use more complex distributions such as a normal distribution.

Yes, that's the intended behaviour. Matrix::Random uses the random number generator of the standard library, so you can initialize the random number sequence with srand(unsigned int seed), for instance:
srand((unsigned int) time(0));

#orian:
std::srand(unsigned seed) is not an Eigen function. The complete code should work like that:
std::srand((unsigned int) time(0));
for(int i = 0; i < 5; i++) {
MatrixXf A = MatrixXf::Random(3, 3);
cout << A <<endl;
}

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

Related

Using std::random_device can I set a range of floating point numbers but not include certain numbers?

As mentioned in the title I want to generate a random floating-point number between -10 and 10 but I want to make it so that it can't generate a number between -1.99 and 1.99.
My code for randomly generating numbers:
std::random_device random;
std::mt19937 gen(random());
std::uniform_real_distribution<float> dis(-10.0f, 10.0f);
for (int n = 0; n < 10; ++n)
{
std::cout << dis(gen); << std::endl;
}
you can use std::piecewise_constant_distribution:
#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
// 50% of the time, generate a random number between -10.0f and -1.99f
// 50% of the time, generate a random number between 1.99f and 10.0f
std::vector<float> i{-10.0f, -1.99f, 1.99, 10.0f};
std::vector<float> w{1, 0, 1};
std::piecewise_constant_distribution<float> dis(i.begin(), i.end(), w.begin());
for (int n = 0; n < 10; ++n)
std::cout << dis(gen) << std::endl;
}
Demo.

Using distributions in c++

I would like to use built-in distribution, but add some constraints to it. I tried something like this, but i get same number when using function. How can i avoid this? Can i use distribution as a argument to the function?
double Cauchy(double Fm){
std::default_random_engine generator;
std::cauchy_distribution<double> distribution(Fm, 0.1);
double number=distribution(generator);
while(number<0)
number=distribution(generator);
if (number>1)
number = 1;
return number;
}
Now i changed function and it looks like this
double Cauchy_1(double Fm, std::random_device &rd){
std::default_random_engine generator(rd());
std::cauchy_distribution<double> distribution(Fm, 0.1);
double number=distribution(generator);
while(number<0)
number=distribution(generator);
if (number>1)
number =1;
return number;
}
std::random_device rd;
int i=15;
double Crm=0.1, num;
while (i>0){
num=Cauchy_1(0.1, rd);
cout<<num<<endl;
i--;
}
It gives me different values, but values are the same on new run.
You initialize std::default_random_engine generator; with the same default seed. You need to seed it to get different outputs if you instantiate it anew. There is std::random_device class you can use to get a new random seed.
Also, std::default_random_engine is slow class to instantiate/create so you are using it wrong.
Functions in the standard library like std::shuffle take a random number generator by a forwarding reference, not a distribution. You can do the same:
template<class URBG>
double cauchy_1(double fm, URBG&& gen) {
std::cauchy_distribution<double> distribution(fm, 0.1);
double number;
do
number = distribution(gen);
while (number < 0);
return std::min(number, 1.0);
}
int main() {
std::random_device rd;
std::default_random_engine gen(rd());
for (int i = 0; i < 10; ++i) {
auto num = cauchy_1(0.1, gen);
std::cout << num << std::endl;
}
}
It still has same set of numbers if i rerun this code.
This is not the problem of this code, but the problem of std::random_device. As explained here, std::random_device may be implemented in terms of a pseudo-random number engine. Possible solutions can be found here.
For example:
std::default_random_engine gen(
std::chrono::system_clock::now().time_since_epoch().count());

How can I generate a random number after every millisecond without closing the program in c++?

I want to generate a new random every time in a while loop until the loop breaks when it meets the condition in the while loop like 10 random numbers.
you could find something on https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
int main()
{
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> dis(1, 6);
for (int n=0; n<10; ++n)
//Use dis to transform the random unsigned int generated by gen into an int in [1, 6]
std::cout << dis(gen) << ' ';
std::cout << '\n';
}
where the for loop can obviously be replaced by a while

How to generate random integers 0 to 0x7FFFFFFF?

This doesn't work:
for (int p = 0; p < 10; p++) {
random_device rd;
mt19937 gen(rd);
uniform_real_distribution<int> dis(0, INT_MAX);
printf("%i\n", dis(gen));
}
Any advice would be appreciated.
You have few mistakes in your code.
You should move creation of random_device and seeding mt19937 outside the for loop. I'll also suggest the same for uniform_real_distribution<int>
mt19937 takes in the constructor value of seed not random_device so you have to call it to get seed(rd())
You should use uniform_int_distribution<int> if you are generating integers
If your intention is to generate number to 0x7FFFFFFF you should put this number explicitly but if you want to get numbers to max int value i'll suggest using more C++ style std::numeric_limits<int>::max()
Here is working example:
#include <cstdio>
#include <random>
#include <limits>
using namespace std;
int main(){
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dis(0, std::numeric_limits<int>::max());
for (int p = 0; p < 10; p++) {
printf("%i\n", dis(gen));
}
return 0;
}

generating random numbers in c++

I need to generate a random number between 1 and n where n is unsigned int.
If n were int I would simply write 1 + rand()% n. But unfortunately n is unsigned int. What do you suggest?
rand() should be avoided whenever possible*.
Use http://en.cppreference.com/w/cpp/numeric/random
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 engine(rd());
std::uniform_int_distribution<unsigned> dist(1, 77);
for (int i = 0; i != 5; ++i)
std::cout << dist(engine) << '\n';
}
* Because it shares a global state, gets often implemented as a linear congruential engine which has a few drawbacks and it's range is often only 0-2^16. Also, % n where n is not an exact multiple of the range does not produce an uniform distribution.
Edit: This might seem like overkill, but technically one would want something like this, since mt19937 needs a bit of "warm up":
std::mt19937 create_seeded_rng()
{
std::random_device rd;
std::array<std::mt19937::result_type, std::mt19937::state_size> seed_data;
std::generate(seed_data.begin(), seed_data.end(), std::ref(rd));
std::seed_seq seq(seed_data.begin(), seed_data.end());
return std::mt19937(seq);
}
int main()
{
std::mt19937 rng = create_seeded_rng();
std::uniform_int_distribution<int> dist(0, 100);
for (unsigned i = 0; i != 100; ++i)
std::cout << dist(rng) << '\n';
}