Print

Print


Sean thanks so much! You hit on exactly the concerns I was trying to
understand. I did implement Joey's solution  as he said  (but I also read
the doc so I implemented a burn for each RNG) and it worked but I was also
concerned about memory. Thanks for also pointing out that MT is not
designed for this scenario. Turns out to do the forking I had to pass in
the State anyway and was wondering if I should just use it instead. Thanks
for confirming my suspicion. No need to look at my code - I just put it
there in case it helped someone me diagnose my issue.

Again, thanks!

On Mon, Sep 5, 2016 at 4:11 PM, Sean Luke <[log in to unmask]> wrote:

> Allow me to jump in on this conversation very late, and without having
> read very well.  :-)
>
> It sounds like your original concern was that the agents seem to be
> behaving strangely in the first step, and then work fine from then on.  But
> the conversation seems to have morphed into a discussion of proper use of
> random number generators.  I won't be able to look into your code regarding
> the original concern for a few days probably.  But let me weigh in on the
> random number generation discussion.
>
> The rule of thumb with random number generators is as follows: unless you
> know exactly what you are doing, you should:
>
> 1. Seed a single random number generator
>
> 2. Only use that random number generator throughout your run
>
> 3. If you have multiple threads active, and ONLY if this is the case
> (because it is somewhat slow), then code in each thread should lock on
> SOMETHING before accesing the random number generator.  In MASON, that
> something is by convention the random number generator itself, that is,
>      synchronized (state.random) { return state.random.nextInt(n); }  etc.
>
> And that's it.  Your agents are welcome to have pointers to the SimState
> RNG, but they should NOT have their own independent RNGs.  This is not
> because it's not possible to write perfectly cromulent code with agents
> having their own independent RNGs.  It's because with a high probability
> you will not write it correctly, and because there's absolutely no reason
> to do this in the first place.
>
> Problem 1: seeding.  You have to seed each generator separately.  How are
> you going to do this?  You can't do it based on wall-clock time: they'll
> likely be synchronized.  You could seed them based on increasing steps
> beyond wall-clock time and that will PROBABLY work okay, but it's a major
> potential source of hard-to-debug errors.  For example, I'm guessing that
> you probably didn't pulse each of the Mersenne Twister RNGs about 1500
> times to get rid of initial bad randomness in your seeding.  No one thinks
> of stuff like this.  You could also (as Joey said) seed them based on a
> random number generation from a master RNG.  This is called "forking" an
> RNG. Note that Mersenne Twister is NOT DESIGNED FOR FORKING.  It's not
> going to have statistically guarantees.
>
> Problem 2: memory.  Each of your agents now is holding onto an object that
> contains about 3K of RAM for no good reason.  If you have 1000 agents,
> that's 3 megs just for unneccessary RNGs.
>
> This stuff has to be done delicately and in ways you probably didn't think
> of.  For example, the GUI has its own separate RNG to assign random colors
> etc. for GUI purposes so as not to pollute the underlying model RNG.
>
> So here's what you should do.  Each of your agents should be given a
> pointer to the SimState (state), or to state.random, and just call
> SimState's RNG directly if they're all in the same thread.  And that's it.
> You'll save memory, it'll be just as fast, and you'll dramatically reduce
> the chances that you've introduced RNG bugs.
>
> Sean
>