haskell / random

Random number library
Other
53 stars 50 forks source link

Save generator state #131

Closed dschrempf closed 2 years ago

dschrempf commented 2 years ago

Hello,

I was having trouble saving the random number generator state (seed). Do you think it is possible/feasable to provide a save(Gen) function that extracts the seed such that, for example, for StdGen, we have mkStdGen . save(Gen) = id? The save(Gen) function could be part of the type class. If this is impossible in general, I think it would be useful to at least have this function available for StdGen and all monadic wrappers thereof.

At the moment, for example, saving an IOGenM StdGen is a bit tedious:

import System.Random.Internal
import System.Random.SplitMix
import System.Random.Stateful

saveGen' :: IOGenM StdGen -> IO (Word64, Word64)
saveGen' (IOGenM r) = do
  (StdGen g) <- readIORef r
  pure $ unseedSMGen g

It is also not clear to me how freezeGen and thawGen are supposed to be used. I think, we should improve on the documentation on Hackage, and provide examples!

For reference, please see a discussion on Haskell Discourse: https://discourse.haskell.org/t/save-and-restore-random-number-generator-freeze-thaw/4751.

lehins commented 2 years ago

There is no general way to save the seed of a generator yet. If you'd like to do it for the StdGen you can achieve it using Internal module and splitmix package directly:

toSeedStdGen :: StdGen -> (Word64, Word64)
toSeedStdGen = unseedSMGen . unStdGen

fromSeedStdGen :: (Word64, Word64) -> StdGen
fromSeedStdGen = StdGen . seedSMGen'

I am sure you have a way of storing two Word64s on disk.

However, it is a bit trickier to deal with this problem in a general fashion, because it is unknown how big the internal state is and what the most efficient representation for such state is). There is already a ticket about this, so I am gonna close this one as a duplicate of #123

With respect to FrozenGen interface it was mostly designed for generators that rely on a large mutable state, such as mwc-random and solves an orthogonal issue to the ability to seed and unseed a generator. Besides haddock documentation that we already have here is a little more explanation on the topic of FrozenGen: New random interface - StatefulGen and FrozenGen explained

If I misunderstood your feature request, please, feel free to reopen this ticket.

dschrempf commented 2 years ago

Thank you for your reply. As you may have seen from the issue, I already have figured out how to store the seed of StdGen, and, of course, I also have a way of storing two Word64s on disk. I was suggesting to make this easier for future users of random, and I was suggesting to make such a possibility available for more/all generators.

I see that this is discussed in #123, thank you for posting the link. Now we have three words for doing very similar (orthogonal? the same? ) things: save, freeze, serialize to disk. Sorry for being so zynical, but it seems to me that some things are just overcomplicated in our otherwise truly amazing Haskell programming language.

EDIT: I still think we should improve the documentation of the FrozenGen type class.

EDIT2: Because I got interested: Typing "Save random number generator state PROGRAMMING LANGUAGE" into Google gives the following results:

This took me now 10 minutes. I am just trying to make a point.

lehins commented 2 years ago

I am just trying to make a point.

@dschrempf I think I get your point. We need a way to convert StdGen to a serializable seed and back. That is what #123 ticket is about and this ticket albeit valid, to me it seems like a duplicate. If that is still not your point, then please elaborate and make your point more clear.

I still think we should improve the documentation of the FrozenGen type class.

Feel free to open a PR if you feel like documentation can be improved, contributions are very much welcomed.

it seems to me that some things are just overcomplicated in our otherwise truly amazing Haskell programming language.

I agree, it is truly an amazing language, but none of these concepts are complicated or even unique to Haskell. Also things are only complicated when they are not understood. Once you learn the concepts they usually become simple:

dschrempf commented 2 years ago

I agree with you, and still I feel bad about how unnecessary difficult some really simple things in Haskell are. Of course, that is not your fault at all. I think we, as a Haskell community, should take care of this discrepancy (for our own benefit).

With respect to the vocabulary: I am aware of the nomenclature used by vector. I do not think it is particularly general. Actually, I think it is pretty Haskell specific. I did not look for, and use serializing/deserializing because the same computation (saving the state or serializing the state) is known as save (respectively restore) in mwc-random.

Thanks for your replies!