Get/set state in Mersenne Twister

In order to serialize, it would be helpful to add an interface to mersenne_twister to get/set the state. I don't think there is any I/F to get the state.

Neal D. Becker wrote:
In order to serialize, it would be helpful to add an interface to mersenne_twister to get/set the state. I don't think there is any I/F to get the state.
Possible patch: Index: mersenne_twister.hpp =================================================================== RCS file: /cvsroot/boost/boost/boost/random/mersenne_twister.hpp,v retrieving revision 1.16 diff -c -r1.16 mersenne_twister.hpp *** mersenne_twister.hpp 27 Jul 2004 03:43:32 -0000 1.16 --- mersenne_twister.hpp 1 Sep 2004 20:05:31 -0000 *************** *** 171,176 **** --- 171,183 ---- { return !(*this == rhs); } #endif + template<typename cont_t> + void getstate (cont_t& c) const { + if (c.size() < stat_size) + throw std::invalid_argument("mersenne_twister::getstate"); + std::copy (&x[0], &x[state_size], c.begin()); + } + private: // returns x(i-n+index), where index is in 0..n-1 UIntType compute(unsigned int index) const

There is already a func that can be used to set the state, but it has a strange signature that makes it a bit awkward: template<class It> void seed(It& first, It last) Is it really intended that first arg is reference, but last is not? According to g++, this common call would not match: seed (cont.begin(), cont.end())

Neal D. Becker wrote:
There is already a func that can be used to set the state, but it has a strange signature that makes it a bit awkward:
template<class It> void seed(It& first, It last)
Is it really intended that first arg is reference, but last is not?
Yes, it is. The motivation is to be able to seed two engines from the same range: e1.seed( first, last ); // consumes input and increments first e2.seed( first, last ); // use the rest

On Sep 1, 2004, at 9:54 PM, Neal D. Becker wrote:
In order to serialize, it would be helpful to add an interface to mersenne_twister to get/set the state. I don't think there is any I/F to get the state.
When we need to serialize RNGs we currently use the possibility to convert the state to a string using operator <<(std::ostream&, const RNG&) and operator >>(std::istream&, RNG&). A better serialization mechanism should, in my opinion directly use the serialization library and not go over some get_state/set_state functions, since the state might be described by more than just a container. Matthias

Matthias Troyer wrote:
On Sep 1, 2004, at 9:54 PM, Neal D. Becker wrote:
In order to serialize, it would be helpful to add an interface to mersenne_twister to get/set the state. I don't think there is any I/F to get the state.
When we need to serialize RNGs we currently use the possibility to convert the state to a string using operator <<(std::ostream&, const RNG&) and operator >>(std::istream&, RNG&). A better serialization mechanism should, in my opinion directly use the serialization library and not go over some get_state/set_state functions, since the state might be described by more than just a container.
I'm trying to interface with boost::python pickle. I don't know if boost::serialization would be useful in this case. I wonder if anyone has tried to make boost::python pickle work via boost:serialization?

Matthias Troyer wrote:
On Sep 1, 2004, at 9:54 PM, Neal D. Becker wrote:
In order to serialize, it would be helpful to add an interface to mersenne_twister to get/set the state. I don't think there is any I/F to get the state.
When we need to serialize RNGs we currently use the possibility to convert the state to a string using operator <<(std::ostream&, const RNG&) and operator >>(std::istream&, RNG&). A better serialization mechanism should, in my opinion directly use the serialization library and not go over some get_state/set_state functions, since the state might be described by more than just a container.
Maybe this is generic enough for any use? It's not hard to make this work for boost::python pickle: *** mersenne_twister.hpp 2004-09-01 22:25:34.271533876 -0400 --- mersenne_twister.hpp.new 2004-09-01 22:10:43.674599123 -0400 *************** *** 133,138 **** --- 133,147 ---- return os; } + template<class Archive> + Archive& + getstate(Archive& ar) const + { + for(int j = 0; j < state_size; ++j) + ar << compute(j); + return ar; + } + template<class CharT, class Traits> friend std::basic_istream<CharT,Traits>& operator>>(std::basic_istream<CharT,Traits>& is, mersenne_twister& mt) *************** *** 145,150 **** --- 154,172 ---- mt.i = mt.state_size; return is; } + + template<class Archive> + Archive& + setstate(Archive& ar) + { + for(int j = 0; j < state_size; ++j) + ar >> x[j]; + // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template + // value parameter "n" available from the class template scope, so use + // the static constant with the same value + i = state_size; + return ar; + } #endif friend bool operator==(const mersenne_twister& x, const mersenne_twister& y)

On Sep 2, 2004, at 4:27 AM, Neal Becker wrote:
Matthias Troyer wrote:
On Sep 1, 2004, at 9:54 PM, Neal D. Becker wrote:
In order to serialize, it would be helpful to add an interface to mersenne_twister to get/set the state. I don't think there is any I/F to get the state.
When we need to serialize RNGs we currently use the possibility to convert the state to a string using operator <<(std::ostream&, const RNG&) and operator >>(std::istream&, RNG&). A better serialization mechanism should, in my opinion directly use the serialization library and not go over some get_state/set_state functions, since the state might be described by more than just a container.
Maybe this is generic enough for any use? It's not hard to make this work for boost::python pickle:
*** mersenne_twister.hpp 2004-09-01 22:25:34.271533876 -0400 --- mersenne_twister.hpp.new 2004-09-01 22:10:43.674599123 -0400 *************** *** 133,138 **** --- 133,147 ---- return os; }
+ template<class Archive> + Archive& + getstate(Archive& ar) const + { + for(int j = 0; j < state_size; ++j) + ar << compute(j); + return ar; + } + template<class CharT, class Traits> friend std::basic_istream<CharT,Traits>& operator>>(std::basic_istream<CharT,Traits>& is, mersenne_twister& mt) *************** *** 145,150 **** --- 154,172 ---- mt.i = mt.state_size; return is; } + + template<class Archive> + Archive& + setstate(Archive& ar) + { + for(int j = 0; j < state_size; ++j) + ar >> x[j]; + // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template + // value parameter "n" available from the class template scope, so use + // the static constant with the same value + i = state_size; + return ar; + } #endif
friend bool operator==(const mersenne_twister& x, const mersenne_twister& y)
I see a problem also with this approach. Note that the state of the RNG at time of serialization (time of call to get_state()) should be the same as after deserialization (after call to set_state()). The fact that the state was stored somewhere, and then set again should not make a difference in the state, i.e. the next random number should be the same in both cases. To be more concrete, the following two (pseudo-) codes should print the same number: version 1: std::cout << rng(); version 2: rng.get_state(archive); rng.set_state(archive); std::cout << rng(); This means that in addition to the state of the buffer, also the state of the index i needs to be stored. This can be done without any problem in the serialization approach but is harder to implement generically when the state should be stored in a container. Matthias
participants (4)
-
Matthias Troyer
-
Neal Becker
-
Neal D. Becker
-
Peter Dimov