(* :Title: JRandomArray *) (* :Author: Mark Fisher *) (* :Version: 1.0 December 2004 *) (* :Mathematica Version: 5.0 *) (* :Requirements: This package requires colt.jar and JRandomArray.class. *) (* :Summary: JRandomArray uses JLink to implement a variety of pseudo random number generators from the Java colt distribution (see http://hoschek.home.cern.ch/hoschek/colt/index.htm). By computing arrays of random numbers directly in (a small amount of) Java code itself, the overall speed is competitive with Mathematica itself. (See RandomArray.java for the requisite Java.) One should be aware that with the exception of MersenneTwister64, the random number engines compute only 32 bits. (The remaining bits are filled in as zeros.) MersenneTwister64 returns about 54 bits (equivalent to about 16 decimals). I suspect this truncation is produced by the Java implementation of the random engine running under Windows: Returning the random doubles as BigDecimals leaves the number of significant bits unchanged. By the way, Mathematica's Random[] does not pad with zeros beyond 54 bits but instead returns some sort of noise out to about 62 bits. *) SeedRandomEngine::usage = "SeedRandomEngine[randomEngineClass] returns a random engine object from the specified class using JavaNew[\"java.util.Date\"] as the default seed. Alternatively, one can specify the seed explicitly using JavaNew[randomEngineClass, seed], where seed is a positive integer or Java date object. See the usage notes for RandomEngineClass for a list of valid random engine class names. Example:\n\n engineObj = SeedRandomEngineClass[\"MersenneTwister64\"]." InitializeDistribution::usage = "InitializeDistribution[distributionClass, randomEngineObject][pars] returns a distribution object from the specified class driven by the given random engine object and using the specified parameters. For example,\n\n normalObj = InitializeDistribution[\"Normal\", engineObj][0,1],\n\n where mersenneTwister64 is a seeded random engine object. To reseed a distribution object, one must first reseed the random engine and then reinitialize the distribution. Each distribution has a method to change the parameter values. For example, to change the standard deviation of the normal distribution from 1 to 3, use\n\n normalObj@setState[0, 3].\n\n See the usage notes for DistributionClass for a list of valid distribution class names and parameter reset methods." JRandomArray::usage = "JRandomArray[distributionObject, n] returns a vector of n pseudo random numbers generated according to the distribution object. JRandomArray[distributionObject, {n1, n2, ...}] returns a higher dimensional array of random numbers. JRandomArray[distributionObject] returns a single element." (* setup JLink *) Needs["JLink`"] InstallJava[] (* To generate 10^7 random variables, increase available memory: to allocate 50MB to start (not necessary) and allocate 200MB. This has the side effect (on Windows) of opening a cmd window which remains until UninstallJava[] is executed or the kernel is quit. InstallJava[CommandLine -> "java -Xms50m -Xmx200m"] *) (* make the classes accessable: colt.jar and RandomArray.class *) (**** you should modify this path to suit your directory structure ****) AddToClassPath["d:/data/packages/java"] (* JRandomArray class implements the static method jRandomArray that fills a vector with random numbers and returns it *) randomArrayClass = LoadJavaClass["JRandomArray"] SeedRandomEngine[randomEngineClass_String] := JavaBlock[ JavaNew[ RandomEngineClass[randomEngineClass], JavaNew["java.util.Date"]] ] InitializeDistribution[distributionClass_String, randomEngineObj_?JavaObjectQ][pars__?NumberQ] := JavaNew[ DistributionClass[distributionClass], pars, randomEngineObj] JRandomArray[distributionObject_?JavaObjectQ, n_Integer?Positive] := JRandomArray`jRandomArray[distributionObject, n] JRandomArray[distributionObject_?JavaObjectQ, n:{__Integer?Positive}] := With[{array = JRandomArray[distributionObject, Times @@ n]}, If[Length[n] == 1, (* then *) Partition[array, 1], (* else *) Fold[Partition, array, Drop[Reverse[n], -1]] ] ] JRandomArray[distributionObject_?JavaObjectQ] := JRandomArray[distributionObject, 1][[1]] (* helpful lists *) shortRandomEngineClassNames = { "DRand", "MersenneTwister", "MersenneTwister64", "Ranecu", "Ranlux", "Ranmar"} MapThread[Set, { RandomEngineClass /@ shortRandomEngineClassNames, LoadJavaClass /@ { "cern.jet.random.engine.DRand", "cern.jet.random.engine.MersenneTwister", "cern.jet.random.engine.MersenneTwister64", "edu.cornell.lassp.houle.RngPack.Ranecu", "edu.cornell.lassp.houle.RngPack.Ranlux", "edu.cornell.lassp.houle.RngPack.Ranmar" } }] (* need to provide documentation regarding valid parameter values *) shortDistributionClassNames = { "Beta", "Binomial", "ChiSquare", "Exponential", "Gamma", "HyperGeometric", "Logarithmic", "NegativeBinomial", "Normal", "Poisson", "StudentT", "Uniform"} MapThread[Set, { DistributionClass /@ shortDistributionClassNames, LoadJavaClass["cern.jet.random." <> #]& /@ shortDistributionClassNames }] parstable = ToString @ TableForm[Transpose[{ shortDistributionClassNames, StringDrop[Select[Methods[DistributionClass[#], Inherited -> False][[1]], StringMatchQ[#, "*set*"] &][[1]], 5] & /@ shortDistributionClassNames}], TableSpacing -> {0, 3}] DistributionClass::usage = "DistributionClass[className] returns the JLink object that represents the named distribution class. Valid distribution classes are the strings given in first column of the following list:\n" <> parstable <> "\nThe second column provides the name of the method used to reset the parameter values and also gives the number and type of parameters for each class." RandomEngineClass::usage = "RandomEngineClass[className] returns the JLink object that represents the named random engine class. Valid class names are the strings\n" <> ToString[TableForm[shortRandomEngineClassNames, TableSpacing -> {0}]] (* :Example: *) (* use 64 bit twister engine; returns only about 54 significant bits *) engineObj = SeedRandomEngine["MersenneTwister64"] (* for uniform (0,1) and normal (0,1) distributions *) uniformObj = InitializeDistribution["Uniform", engineObj][0, 1] normalObj = InitializeDistribution["Normal", engineObj][0, 1] Null; (* don't return anything *)