SML# - Resources/ProgrammingExamples/MT Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

If your random number generator is not the Mersenne Twister,
may I suggest to replace it with the Mersenne Twister of Makoto
Matsumoto and Takuji Nishimura.
This would significantly  and instantly enhance the quality of your ML
code that uses random numbers.

In SML#, this is done by the following trivial 15 minute process;
no stub or data conversion is necessary.

!!Download Mersenne Twister
Go to the [[inventor's page|http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html]],
download the file
[[mt19937ar.tgz|http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.tgz]],
and un-tar it as follows:
  $ tar xvfz mt19937ar.tgz
  ./
  ./mt19937ar.c
  ./mt19937ar.out
  ./readme-mt.txt
""(Comments) A faster and enhanced version
""[[SFMT|http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html]]
""has also been released. Using this should
""equally be simple (if your ML compiler is SML#).
""So I recommend to try using this version by yourself.
!!Compile Mersenne Twister as a dynamically linked library
In Linux OS, the following one line will do:
$ gcc -shared -o mt19937ar.so mt19937ar.c
The resulting file '''mt19937ar.so''' contains the following 8 functions.
void init_genrand(unsigned long s)
void init_by_array(unsigned long init_key[], int key_length)
unsigned long genrand_int32(void)
long genrand_int31(void)
double genrand_real1(void)
double genrand_real2(void)
double genrand_real3(void)
double genrand_res53(void)
int main(void)

!!Write an SML# structure.
To open the library mt19937ar.so, use the following FFI library functions:
# DynamicLink.dlopen;
val it = fn : string  -> unit ptr
# DynamicLink.dlsym;
val it = fn : unit ptr * string  -> unit ptr
'''dlopen'''(path) opens the file path '''path''' of a dynamically
linked library.
'''dlsym(ptr, s)''' searches the function name '''s''' in the
library pointed by the handle '''ptr''', and returns a pointer to the
function.

The returned C function pointer is imported to SML# name space by the
following SML#  special construct:
exp _import : (t1,...,tn) -> t
It assumes ''exp'' to be a C pointer to the function that
takes n arguments of types '''t1,...,tn''' and returns a value of type
'''t''',  and converts it to an SML# function of the corresponding type
t1 * ... * tn -> t
So, you can simply write the following declaration that corresponds to
the headers of 8 C functions in mt19937ar.
structure MT = struct
local
   val mtLib = DynamicLink.dlopen "./mt19937ar.so"
   fun find s = DynamicLink.dlsym (mtLib,s)
in
   val init_genrand = find "init_genrand" : _import (int) -> void
   val init_by_array = find "init_by_array"
                       : _import (int array,int) -> void
   val genrand_int32 = find "genrand_int32" : _import () -> int
   val genrand_int31 = find "genrand_int31" : _import () -> int
   val genrand_real1 = find "genrand_real1" : _import () -> real
   val genrand_real2 = find "genrand_real2" : _import () -> real
   val genrand_real3 = find "genrand_real3" : _import () -> real
   val genrand_res53 = find "genrand_res53" : _import () -> real
   val main = find "main" : _import () -> int
end
end  
When this is evaluated, SML# print the following.
# use "mt.sml";
structure MT
: sig
     val genrand_int31 : unit -> int
     val genrand_int32 : unit -> int
     val genrand_real1 : unit -> real
     val genrand_real2 : unit -> real
     val genrand_real3 : unit -> real
     val genrand_res53 : unit -> real
     val init_by_array : int Array.array * int -> unit
     val init_genrand : int -> unit
     val main : unit -> int
   end
#
That's all.  You are ready to use the Mersenne Twister by using these
8 functions with your favorite higher-order functions.

To test, try invoking the ''main'' function, which is the test program
provided in the original package.
  # MT.main();
  1000 outputs of genrand_int32()
  1067595299  955945823  477289528 4107218783 4228976476
  ...