bab2min / EigenRand

Fastest Random Distribution Generator for Eigen
https://bab2min.github.io/eigenrand/
MIT License
92 stars 12 forks source link

generates real vectors on a LOG multivariate normal distribution #38

Closed JohnPekl closed 2 years ago

JohnPekl commented 2 years ago

It seems your package does not support generating a vector log norm, Isn't it? I have checked, it can only generate a number following log-normal distribution Eigen::Rand::LognormalGen.

bab2min commented 2 years ago

Hello @JohnPekl, Sorry, I'm not sure exactly what the vector log norm that you asked. Could you clarify that? Is that different from log-normal distribution?

JohnPekl commented 2 years ago

@bab2min Thanks for replying to my question.

(1) If I have a mean and standard deviation is a scalar (double, or float number), I can use your package to generate a matrix following normal distribution and log-normal distribution (below code).

    Rand::P8_mt19937_64 urng{ 42 };
    // constructs generator for normal distribution with mean=1.0, stdev=2.0
    Rand::NormalGen<float> norm_gen{ 1.0, 2.0 };
    // Generator classes have a template function `generate`.
    // 10 by 10 random matrix will be assigned to `mat`.
    MatrixXf mat = norm_gen.template generate<MatrixXf>(10, 10, urng);
    std::cout << mat << std::endl;
    // Generator classes also have `generateLike`.
    mat = norm_gen.generateLike(mat, urng);
    std::cout << mat << std::endl;

    // constructs generator for normal distribution with mean=1.0, stdev=2.0
    Rand::LognormalGen<float> lognorm_gen{ 1.0, 2.0 };
    // Generator classes have a template function `generate`.
    // 10 by 10 random matrix will be assigned to `mat`.
    mat = norm_gen.template generate<MatrixXf>(10, 10, urng);
    std::cout << mat << std::endl;
    // Generator classes also have `generateLike`.
    mat = norm_gen.generateLike(mat, urng);
    std::cout << mat << std::endl;

(2) But if my input of mean is a vector and covariance is a matrix, I can generate a matrix that follows a multivariate normal distribution (below code)

    Eigen::Vector3d mu{ 1, 2, 3};
    Eigen::Matrix3d cov{
            {1, 1, 0},
            {0, 2, 0},
            {0, 0, 1},
    };
    Eigen::Matrix<double, 3, -1> samples;
    Eigen::Rand::MvNormalGen<double, 3> gen_init{ mu, cov };
    std::random_device rd;
    std::mt19937_64 genn(rd());
    samples = gen_init.generate(genn, 5);
    cout<<samples<<endl;

How can I generate a matrix that follows a multivariate log-normal distribution with mean is a vector and covariance is a matrix (similar (2))?

bab2min commented 2 years ago

@JohnPekl , I see! Thank you for your detail explanation! Mathematically, the log-normal distribution is equivalent to taking the exp of the normal distribution. If you want to sample from multivariate log-normal distribution, there is no simple generator for it. So you should sample from multivariate normal distribution first, and put its result to exp function elementwise. (https://en.wikipedia.org/wiki/Log-normal_distribution#Multivariate_log-normal)

    Eigen::Vector3d mu{ 1, 2, 3};
    Eigen::Matrix3d cov{
            {1, 1, 0},
            {0, 2, 0},
            {0, 0, 1},
    };
    Eigen::Matrix<double, 3, -1> samples;
    Eigen::Rand::MvNormalGen<double, 3> gen_init{ mu, cov };
    std::random_device rd;
    std::mt19937_64 genn(rd());
    samples = gen_init.generate(genn, 5);
    samples = samples.array().exp().matrix(); // applying exp to samples elementwise