/*
 *  librandom.sli
 *
 *  This file is part of NEST.
 *
 *  Copyright (C) 2004 The NEST Initiative
 *
 *  NEST is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  NEST is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
 *
 */


/librandom ($Revision: 10100 $) provide
/oosupport (5774) require


%  added function Random, MD 2006-03-16
%
%  type tries and wrappers for backward compatibility for 
%  librandom 2.0
%
%  HEP 2002-07-10
%

%% RNG tries: HEP 2002-07-09 --- see sli/rangen.cc

/*BeginDocumentation
Name: rngdict - dictionary with random generator types
Description: 
  rngdict contains the random generator types available.
  They can be used as arguments to CreateRNG.
  <ul>
  <li> To see which RNGs are available in rngdict use:
    rngdict info
  <li> To extract one specific rng from the dictionary use:
    rngdict /rngname get
  <li> To make all models permanetly available type
  <pre>
  rngdict begin
  </pre>
  </ul>
SeeAlso:  CreateRNG
References: GNU Scientific Library, http://www.gnu.org/software/gsl
Remarks: See librandom/random_numbers.cpp for implementation.    
*/

/*BeginDocumentation
Name: rdevdict - dictionary with random deviate generator types
Description: 
  rdevdict contains the random deviate generators available.
  Deviate generators can be used to draw random numbers with,
  e.g., normal or binomial distributions.
  <ul>
  <li> To see which RDVs are available in rdevdict use:
    rdevdict info
  <li> To extract one specific rdv from the dictionary use:
    rdevdict /rdvname get
  <li> To make all deviates permanetly available type
  <pre>
  rdevdict begin
  </pre>
  </ul>
SeeAlso: CreateRDV, Random, RandomArray
References: GNU Scientific Library, http://www.gnu.org/software/gsl
Remarks: See librandom/random_numbers.cpp for implementation.    
*/


/* BeginDocumentation
Name:CreateRNG - Create a new random generator 
Synopsis:GeneratorType int CreateRNG -> rangen
Description:Create a new random generator of a given type and seed 
it.  See rngdict for the available generators, and the GNU Scientific
Library documentation for details on the generators.  All random generators 
produce numbers uniformly distributed on [0, 1).
Parameters:GeneratorType - any generator type found in rngdict
int - seed, a positive integer
Examples:SLI ] rngdict /knuthran get 3456 CreateRNG /krng Set
SLI ] krng drand =
0.23456
References:GNU Scienctific Library, http://www.gnu.org/software/gsl
SeeAlso:rngdict, rdevdict, CreateRDV, seed, drand, irand
*/
/CreateRNG trie
  [/rngfactorytype /integertype] /CreateRNG_gt_i load addtotrie
def

/* BeginDocumentation
Name:CreateRDV - Create a new random deviate generator 
Synopsis:
rngtype rdvfacttype CreateRDV -> rdvtype
rngtype dict1                 -> dict2
Description:Create a new random deviate generator for a given distribution.
See rdevdict for the available distributions, and the documentation for the 
individual deviates (under rdevdict::*). The distribution instance can either be
generated from a distribution implemented in C++ represented by rdvfactype or
a SLI implementation of a distribution represented by a dictionary. In the former
case the return value is of rdvtype in the latter case a dictionary. See normal_clipped
for an example on how to define a distribution by a SLI dictionary.
Distribution parameters can be inspected and changed with 
GetStatus/SetStatus where applicable. 
Parameters:rngtype - random generator as source of random numbers
rdvfacttype - distribution to draw from, from rdevdict
rdvtype     - the initialized C++ object representing the distribution
dict1       - dictionary used as a template to create the distribution
dict2       - the cloned and initalized dictionary representing the distribution
Examples:Create a generator for binomial numbers based on a Knuth LFG random 
number generator, set parameters to p=0.2 and n=10, and draw five numbers:

SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set
SLI ] rng rdevdict /binomial get CreateRDV /bino Set
SLI ] bino << /p 0.2 /n 10 >> SetStatus
SLI ] bino 5 RandomArray ==
[2 3 2 2 1]

References:GNU Scienctific Library, http://www.gnu.org/software/gsl
SeeAlso:rdevdict, rdevdict::normal_clipped, Random, RandomArray, CreateRNG
*/
/CreateRDV trie
  [/rngtype /rdvfactorytype] /CreateRDV_g_vf load addtotrie
  [/rngtype /dictionarytype] {clonedict exch pop dup rollu /init call} addtotrie
def



/*BeginDocumentation
Name: seed - Set the seed of a random number generator.
Synopsis: rangen int seed -> -
Description: Seeds random number generator with a new seed.
SeeAlso: CreateRNG
*/
/seed trie
  [/rngtype /integertype] /seed_g_i load addtotrie
def

/*BeginDocumentation
Name: irand - Generate a random positive integer number.
Synopsis: rangen n irand -> int
Description: irand uses the supplied random number generator to generate
a random number between 0 and n-1.
Examples:
<pre>
SLI ] rngdict /knuthran get 1234567 CreateRNG /rng Set
SLI ] [ 10 ] { pop rng 100 irand } Table ==
[16 87 84 66 81 27 64 57 42 59]
</pre>
SeeAlso: drand, CreateRNG, seed
*/
/irand trie
  [/rngtype /integertype] /irand_g_i load addtotrie
def

/*BeginDocumentation
Name: drand - Generate a random double number.
Synopsis: rangen drand -> double
Description: drand uses the supplied random number generator to generate
a random number in [0, 1).
Examples:
<pre>
SLI ] rngdict /knuthran get 1234567 CreateRNG /rng Set
SLI ] [ 4 ] { pop rng drand } Table ==
[6.922545e-01 1.587092e-01 8.004862e-01 5.062180e-01]
</pre>
SeeAlso: irand, CreateRNG, seed
*/
/drand trie
  [/rngtype] /drand_g load addtotrie
def


/*BeginDocumentation
Name: SetStatus_v - modify the properties of a random deviate generator
Synopsis:
rdvtype dict  SetStatus -> -
Description:  
  Sets the parameters of the given random deviate generator to the values 
  given in the status dictionary.  The parameters depend on the particular
  generator.

  The random deviate can be a deviate implemented in C++ represented by 
  rdvtype or a SLI level deviate represented by a dictionary. For the 
  latter case SetStatus is overloaded with function SetStatus_d.
 
Examples:
SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set
SLI ] rng rdevdict /binomial get CreateRDV /bino Set
SLI ] bino << /p 0.2 /n 10 >> SetStatus
SLI ] bino 10 RandomArray ==
[3 0 5 2 0 2 2 0 2 1]
SLI ] bino << /p 0.8  >> SetStatus
SLI ] bino 10 RandomArray ==
[8 8 8 8 10 7 7 9 6 8]
SeeAlso: GetStatus_v, SetStatus_dict, CreateRDV, rdevdict, Random, RandomArray
*/

% add new functions to trie if it exists, else create new
/SetStatus [/rdvtype /dictionarytype] /SetStatus_v load def




/*BeginDocumentation
Name: GetStatus_v - return the property dictionary of a random deviate generator
Synopsis:rdvtype  GetStatus -> dict
Description:  
  GetStatus returns a dictionary with the status information 
  of the random deviate generator given as argument.  The information 
  contained in the property dictionary depends on the particular
  generator.

  The random deviate can be a deviate implemented in C++ represented
  by rdvtype or a SLI level deviate represented by a dictionary. For 
  the Latter case GetStatus is overloaded with GetStatus_d.
SeeAlso: SetStatus_v, GetStatus_dict, CreateRDV, rdevdict
*/
    % add new functions to trie if it exists, else create new
/GetStatus [/rdvtype] /GetStatus_v load def

/get [/rdvtype /literaltype] { exch GetStatus exch get } def
/get [/rdvtype /arraytype] { exch GetStatus exch get_d_a } def


/* BeginDocumentation
Name: RandomArray - Returns array with random numbers.
Synopsis:
rdvtype  n RandomArray -> [r1 .. rn]
dict     n             -> [r1 .. rn]
Description: Returns an array with n random numbers drawn from a random
deviate generator.  The random deviate can be a deviate
implemented  in C++ represented by rdvtype or a SLI level deviate
represented by a dictionary.
SeeAlso: Random, CreateRDV, rdevdict
*/
/RandomArray trie
  [/rdvtype /integertype] /RandomArray_v_i load addtotrie
  [/dictionarytype /integertype] { [ ] rollu  {dup rollu /rand call  append exch } repeat pop} addtotrie
def


/* BeginDocumentation
Name: Random - Returns a  random number.
Synopsis:
rdvtype  Random -> r
dict     Random -> r
Description: Returns a single random numbers drawn from a random
deviate generator. The random deviate can be a deviate
implemented  in C++ represented rdvtype or a SLI level deviate
represented by a dictionary.
Examples: Create a generator for binomial numbers based on a Knuth LFG random 
number generator, set parameters to p=0.2 and n=10, and draw a number:

SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set
SLI ] rng rdevdict /binomial get CreateRDV /bino Set
SLI ] bino << /p 0.2 /n 10 >> SetStatus
SLI ] bino Random ==
3
Author: Diesmann
FirstVersion: 2006-03-16
References: "The Mathematica Book"
SeeAlso: RandomArray, CreateRDV, rdevdict
*/
/Random trie
  [/rdvtype ] /Random_i load addtotrie
  [/dictionarytype] {/rand call} addtotrie
def


/* BeginDocumentation
  Name: RandomSubset - random subset of an array without repetitions 
  Synopsis: rng array int RandomSubset -> array 
                   
  Description:
   rng a n RandomSubset returns an array of size
   n with elements randomly select from array a.
   Selection is made without repetitions. 
   Therefore, 
              a length n geq 
   is required.
  Parameters: 
    rng, random number generator    
  Examples: 
    rng [5 7 2 9 1 6 8] 3 RandomSubset --> [2 7 5] 
    rng [5 7 2 9 1 6 8] 3 RandomSubset -->  [6 8 7]   
    rng [5 7 2 ] 3 RandomSubset --> [7 2 5]  
    rng [5 7 2 ] 3 RandomSubset --> [5 2 7]  

  Bugs: 
   not yet protected by trie
  Author: Diesmann
  FirstVersion: 4.5.2001
  References:  
    Skiena, Steven S. (1990)
    Implementing discrete Mathematics: combinatorics and
    graph theory with Mathematica. 
    Addison-Wesley, Redwood City.
  SeeAlso: drand, Part, Select
*/ 
/RandomSubset
{
 exch size rolld  
 exch dup rolld sub 1 add
 -1 
 3 arraystore
 Range
 {2 pick drand mul floor cvi} Map 
 {
  dup
  rolld dup       % i i a a 
  rolld get       % i a v
  rollu           % v i a
  exch 1 erase
  
  exch
 } Map
 rollu pop pop

} bind def




/* BeginDocumentation
Name:rdevdict::normal_clipped - clipped gaussian random number distribution
Synopsis:normal_clipped -> dict
Parameters:normal_clipped does not take any arguments but the default values
can be inspected by
   normal_clipped GetStatus info
The parameters of a particular corresponding random number distribution object
created by CreateRDV can be modified as shown below
Description:normal_clipped is defined in rdevdict and returns
a dictionary representing a clipped gaussian random number distribution.
The dictionary can be used to create an instance of a corresponding random
number distribution using CreateRDV as in the example below. Here, it
exploited that dictionaries can be used to implement aspects of object oriented
programming in SLI, see function call for more details. Any random number
distribution specified by a dictionary is required to provide at least to
members: The literal /init provides a procedure taking a random number generator
as an argument. The literal /rand provides a procedure returning a random number. Both
procedures should be called using the standard syntax for call. Usually only the
implementer uses these functions and the user accesses the random number distribution
via general functions like CreateRDV and Random. 
Examples:
SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set
SLI ] rng rdevdict /normal_clipped get CreateRDV /nc Set
SLI ] nc << /mu 10.0 /std 3.0 /min 1.0 /max 15.0 >> SetStatus
SLI ] nc Random ==
1.215086e+01
Author:Helias, Diesmann
FirstVersion: 2006-06-26
SeeAlso: Random, CreateRDV, rdevdict::normal_clipped_left, rdevdict::normal_clipped_right, rdevdict, call
*/
rdevdict
/normal_clipped
<<
 /mu   0.0
 /std  1.0
 /min  -1.0
 /max   1.0

 /init
 { % This is the constructor used by CreateRDV to create
   % an instance of this distribution. The corresponding variant
   % of CreateRDV is called with: rng <<this dict>> CreateRDV and
   % uses <<clone of this dict>> /init call to execute init in the proper
   % context.
  rdevdict /normal get CreateRDV
  /dv Set  % not defined in template normal_clipped
  
 }    
 
 /rand 
 {
   { 
    dv Random std mul mu add 
    dup dup
    min gt exch
    max lt and
    { exit } { pop } ifelse
   } loop
 }
>> cvo put

/* BeginDocumentation
Name:rdevdict::normal_clipped_left - left clipped gaussian random number distribution
Synopsis:normal_clipped_left -> dict
Parameters:normal_clipped_left does not take any arguments but the default values
can be inspected by
   normal_clipped_left GetStatus info
The parameters of a particular corresponding random number distribution object
created by CreateRDV can be modified as shown below
Description:normal_clipped_left is defined in rdevdict and returns
a dictionary representing a left clipped gaussian random number distribution.
The dictionary can be used to create an instance of a corresponding random
number distribution using CreateRDV as in the example below. For more information
on the implementation of random number distributions using dictionaries see
normal_clipped.
Examples:
SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set
SLI ] rng rdevdict /normal_clipped_left get CreateRDV /nc Set
SLI ] nc << /mu 10.0 /std 3.0 /min 14.0  >> SetStatus
SLI ] nc Random ==
1.549122e+01
Author:Helias
FirstVersion: 2006-06-27
SeeAlso: Random, CreateRDV, rdevdict::normal_clipped, rdevdict::normal_clipped_right, rdevdict, call
*/
rdevdict
/normal_clipped_left
<<
 /mu   0.0
 /std  1.0
 /min  -1.0
 
 /init
 { % This is the constructor used by CreateRDV to create
   % an instance of this distribution. The corresponding variant
   % of CreateRDV is called with: rng <<this dict>> CreateRDV and
   % uses <<this dict>> /init call to execute init in the proper
   % context.
  rdevdict /normal get CreateRDV
  /dv Set  % not defined in template normal_clipped
  
 }    
 
 /rand 
 {
   { 
    dv Random std mul mu add 
    dup
    min gt
    { exit } { pop } ifelse
   } loop
 }
>> cvo put

/* BeginDocumentation
Name:rdevdict::normal_clipped_right - right clipped gaussian random number distribution
Synopsis:normal_clipped_right -> dict
Parameters:normal_clipped_right does not take any arguments but the default values
can be inspected by
   normal_clipped_right GetStatus info
The parameters of a particular corresponding random number distribution object
created by CreateRDV can be modified as shown below
Description:normal_clipped_right is defined in rdevdict and returns
a dictionary representing a right clipped gaussian random number distribution.
The dictionary can be used to create an instance of a corresponding random
number distribution using CreateRDV as in the example below. For more information
on the implementation of random number distributions using dictionaries see
normal_clipped.
Examples:
SLI ] rngdict /MT19937 get 123456789 CreateRNG /rng Set
SLI ] rng rdevdict /normal_clipped_right get CreateRDV /nc Set
SLI ] nc << /mu 10.0 /std 3.0 /max 14.0  >> SetStatus
SLI ] nc Random ==
4.618916e+00
Author:Diesmann
FirstVersion: 2008-09-17
SeeAlso: Random, CreateRDV, rdevdict::normal_clipped, rdevdict::normal_clipped_left, rdevdict, call
*/
rdevdict
/normal_clipped_right
<<
 /mu   0.0
 /std  1.0
 /max  -1.0
 
 /init
 { % This is the constructor used by CreateRDV to create
   % an instance of this distribution. The corresponding variant
   % of CreateRDV is called with: rng <<this dict>> CreateRDV and
   % uses <<this dict>> /init call to execute init in the proper
   % context.
  rdevdict /normal get CreateRDV
  /dv Set  % not defined in template normal_clipped
  
 }    
 
 /rand 
 {
   { 
    dv Random std mul mu add 
    dup
    max lt
    { exit } { pop } ifelse
   } loop
 }
>> cvo put