Keep in mind that there could be accuracy reasons why you might want to use 
multiple random number generators (aka multiple streams). See the section 
"Single Versus Multiple Streams" here:

http://www.cse.msu.edu/~cse808/CSIM_Notes03/cse808/html_c/16random.htm

Also, the built in java random number generator is ok, but not 
state-of-the-art in terms of quality. A more popular high quality generator 
is the Mersenne twister. There are several java implementations available. 


On Friday, June 6, 2014 11:33:04 PM UTC-4, Mars0i wrote:
>
> Wow.  Linus, thanks for the very detailed answer.
>
> It sounds as your view is that there's no problem with the logic of my 
> proposed solution, but it seems wasteful to create 100 RNGs, when I don't 
> actually need to have so many of them.  Your solutions provide ways to get 
> the same result without maintaining so many RNG objects in a simulation 
> run.  Is that roughly correct?
>
> On Friday, June 6, 2014 2:26:25 PM UTC-5, Linus Ericsson wrote:
>>
>> (I think your stepwise problem is better to be solved without agents, see 
>> below.)
>>
>> I realized that the *rng* actually is conflated, it keeps both the state 
>> for the random number generator AND the algorithm used for the random 
>> number generation. This is usually not a problem, since the state-size and 
>> usage is dependent on the particular random number generator, but it 
>> becomes a problem when we need to separate and multithread things 
>>
>
> Interesting point.  OK.  But seem my comment below about sharing of code 
> between RNG objects.
>  
>
>> One solution would be to either re-implement the algorithm (by Knuth) 
>> used in the original Sun Java random implementation, or use the 
>> experimental library Four [1] by Gary Fredericks that does exactly this.
>>
>
> Four looks very nice.  Its stateless RNGs return a new RNG, rather than an 
> RNG state, btw:
> (class (rs/java-random 1001))
> ;==>  four.stateless.JavaRandom
> (map class (rs/next-long (rs/java-random 1001)))
> ;==> (java.lang.Long four.stateless.JavaRandom)
>  I can see how this might be useful, though.
>
> What you would like to do is to be able to feed the rng-algorithm with the 
>> state (it is just a 64 bit long), and simply take the random-result 
>> generated from it, and store the state in the agent together with the rest 
>> of the simulation state.
>>
>> Dubious Speculations:
>> This makes it necessary to know that the agents are called in the same 
>> order (if the influence on each other). 
>>
>
>  
>
>> Given the non-guarantee of ordering in the nature of Java Threads and how 
>> agents rely on them I don't think you can expect your result to be 
>> reproducible. 
>>
>
> Right.  I can guarantee the order in which the random numbers are used 
> when I use map to cause each person to do its work, but I assume that I 
> can't guarantee this order when I use pmap.
>  
>
>> Here I assume that the incoming calls to agents aren't guaranteed to 
>> strictly ordered among different agents, even though the agents reside in 
>> one of two thread-pools (the send- vs. send-off pools). If two agents sent 
>> messages that arrived a third agent in different order, the rng-state would 
>> differ between the runs). Please correct me if I'm wrong on this one. 
>>
>
> No, there's no issue about the order in which messages are received, I 
> believe.  Communication is effectively simultaneous, because all sending 
> happens in one step, and all receiving happens in another step.
>  
> (Here are the details, if you're interested:  Each Person random chooses 
> other Persons to send a message to, and then randomly chooses a message to 
> send.  The pmap over the Persons ends, and all of the messages are 
> collected into a single hashmap.  Then a separate pmap goes through each 
> Person, applying the messages in the hashmap that are supposed to be sent 
> to that Person.  Thus, although Persons perform their work in some order, 
> the sending and the receiving of the messages are separated, so that 
> message sending and receipt occurs as if all messages were sent 
> simultaneously.  In the next timestep, the messages received by a Person 
> affect the probabilities that various messages will be chosen to send to 
> another Person.)
>  
>
>> A possible clever way around this could be to send the rng state together 
>> with the message arriving at the agent, to make the agent at least react to 
>> the state in a similar way. 
>>
>
> Interesting idea.  I don't think I'll need this, though.
>  
>
>> If you have some kind of continous magnitudes in the simulation - like 
>> pheromones - the simulation would maybe converge to similar results since 
>> the interaction effects would be reproducible but this is indeed a very 
>> far-fetched hypothesis.
>>
>
> The simulation converges, but the same parameters can allow convergence to 
> different outcomes.  I usually have to run the simulation many times with 
> the same parameters so that I can get a frequency distribution over 
> outcomes.
>  
>
>> So only if your Person transform functions are commutative (ie gives the 
>> same result whichever order they was called in every timestep) the 
>> simulation could be reproducible by storing the local random generator seed 
>> in each Person.
>>
>
> I see.  I think I understand now.  If I store the state and not the RNG 
> code, but I am able to pass the state into the RNG code, that's all that I 
> need to store in each Person.  I think the idea is that this would do the 
> same work as in my proposal, but with less storage.
>
> But wouldn't the RNG code be shared between RNG objects anyway?  For 
> example, don't all java.util.Random objects share the same code, differing 
> only in that they store different state?  
>  
>
>> If it's just speed you are after, do use either the java 1.7 
>> ThreadLocalRandom (at least try out if this really gives any performance 
>> boost).
>>
>
> You're right.  I should try it.  (There are some special steps necessary 
> to install 1.7 on my version of OS X, but it can be done.)
>  
>
>>
>> A naive ThreadLocalImplementation implementation of clojure.core/rand 
>> would be:
>>
>> (defn rand
>>   "Returns a random floating point number between 0 (inclusive) and
>>   n (default 1) (exclusive)."
>>   {:added "1.0"
>>    :static true}
>> *  ([] (.nextDouble (java.util.concurrent.ThreadLocalRandom/current)))*
>>   ([n] (* n (rand))))
>>
>
> Thanks--this is very helpful given that much of my Java knowledge fallen 
> away through lack of use.
>  
>
>> but as you can see in the source code, random integers are generated 
>> using a call to (rand), multiplied with the integer and floored (when 
>> converting to int), so there are ways to get an limited range int more 
>> efficiently (check the source code for java.util.Random, which makes 
>> various tricks for getting just enough random bits out.
>>
>
> OK, good.
>  
>
>> As always, measure performance (Hugo Duncans Criterium, 
>> criterium.core/bench is a really good start). 
>>
>
> Yes, I always use Criterium.
>  
>
>> Numerical double operations are cheap, memory accesses - in this case to 
>> resulting data structures or other agents and likely context switches - 
>> could as well be the more expensive part.
>>
>> BTW: It looks like the problem you want to solve would benefit much from 
>> being formulated as a two-step problem, one where you applied all the 
>> incoming calls to each Person, and another where you sorted the messages to 
>> each Person in some reproducible order, like
>>
>
> Thanks.  I think that what you have in mind is roughly what I've already 
> implemented, described above.  (Your example was fun.)
>  
>
>> If you makes the message passing explicit instead of 
>> Java-thread-call-uncertain-implicit (which IS possible and parallelizeable 
>> in a stepwise simulation!) you can still parallelize it in many ways (for 
>> example with reducers) and at the same time make simulations reproducible, 
>> and you'll avoid a lot (N²) of potentially expensive context switching.
>>
>
> I may use reducers in the future.  Still learning about them. 
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to