Home > Net >  Get the state (seed) of a distribution of random numbers
Get the state (seed) of a distribution of random numbers

Time:11-22

See the following program for g .

#define seed1 0
#include <iostream>
#include <random>


int main()
{
    double mean = 0.0;
    double stddev  = 1.0;

    std::mt19937 generator1 (seed1);

    std::normal_distribution<double> normal(mean, stddev);
    std::cerr << "Normal: " << normal(generator1) << std::endl;
}

I want to get the state of generator1 (as a seed) and remove generator1 for later instantiate again the distribution with the new seed and go on in the place I left I want to put this code in a function and call it to generate Gaussian points in the start state I want. And at the end of the function save the state as a seed.

CodePudding user response:

save the state as a seed

That will never happen, the state of a generator is much more than its seed.

However, generators (and distributions, which you ignored in your question) do provide functionality to store and retrieve their state through the << / >> operators respectively on streams:

stream << generator1 << normal;

And later:

mt19937 generator;
stream >> generator;

normal_distribution<double> distribution;
stream >> distribution;

CodePudding user response:

Let me also add, that generators and distributions are also constructible and copyable from itself, if there is a need to reuse it later.

#define seed1 0
#include <iostream>
#include <random>


int main()
{
    double mean = 0.0;
    double stddev  = 1.0;

    std::mt19937 generator1 (seed1);
    std::normal_distribution<double> normal(mean, stddev);

    std::cerr << "Normal: " << normal(generator1) << std::endl;

    std::mt19937 generator2 = generator1;
    std::normal_distribution<double> normal2 = normal;

    std::cerr << "Normal: " << normal(generator1) << std::endl;
    std::cerr << "Normal2: " << normal2(generator2) << std::endl;


// I want to get the state of generator1 (as a seed) and remove generator1 for later 
 //instantiate again the distribution with the new seed and go on in the place I left  
 // I want to put this code in a function and call it to generate Gaussian points in 
// the start state I want. And at the end of the function save the state as a seed.
}

So last lines print the same result, as states were initialized to equal values.

CodePudding user response:

There is one way you could try. This involves saving the original seed, and counting how many times the generator is called. To restore the state, seed with the original seed and then call std::mt19937::discard()

Example:
#define seed1 0
#include <cassert>
#include <iostream>
#include <random>

// spoof a generator that counts the number of calls

class my_mt19937 : public std::mt19937 {
   public:
    result_type operator()() {
          call_count_;
        return std::mt19937::operator()();
    }

    void seed(result_type value = default_seed) {
        original_seed_ = value;
        std::mt19937::seed(value);
    }

    void discard(unsigned long long z) {
        call_count_  = z;
        std::mt19937::discard(z);
    }

    unsigned long long call_count() const noexcept { return call_count_; }

    result_type original_seed() const noexcept { return original_seed_; }

   private:
    result_type original_seed_ = default_seed;
    unsigned long long call_count_ = 0;
};

int main() {
    double mean = 0.0;
    double stddev = 1.0;

    my_mt19937 gen1;
    gen1.seed(seed1);

    const size_t N = 10'000;

    for (size_t i = 0; i < N;   i) {
        my_mt19937 gen2;
        gen2.seed(gen1.original_seed());
        gen2.discard(gen1.call_count());

        if (gen2() != gen1()) {
            std::cout << "failed for i = " << i << "\n";
            return 1;
        }
    }

    // this extneds to distribution objects that 
    // use the generators

    std::normal_distribution<double> normal1;
    std::normal_distribution<double> normal2;

    for (size_t i = 0; i < N;   i) {
        my_mt19937 gen2;
        gen2.seed(gen1.original_seed());
        gen2.discard(gen1.call_count());

        if (normal1(gen1) != normal2(gen2)) {
            std::cout << "failed for i = " << i << "\n";
            return 1;
        }
    }

    std::cout << "Success! Tested " << N << " values\n";

    return 0;
}

You can play further with the code on godbolt: https://godbolt.org/z/8j9onsezs

  • Related