alea v.0.3.0alpha
Alea
Alea is a collection of utilities to work with most known probability distributions, written in pure Crystal.
Note: This project is in development state and many distributions are still missing, as well as cumulative distribution functions, so keep in mind that breaking changes may occur frequently.
Why Crystal?
Crystal compiles to really fast native code without sacrificing any of the modern programming languages standards providing a nice and clean interface.
Index
Features
Currently Available
 PRNGs implementations
 Random sampling (single/double precision)
 Cumulative Distribution Functions (single/double precision)
Supported Distributions
Distribution  Sampling (32 / 64)  CDF (32 / 64) 

Beta  Y Y  N N 
ChiSquare  Y Y  Y Y 
Exponential  Y Y  Y Y 
FSnedecor  Y Y  N N 
Gamma  Y Y  Y Y 
Laplace  Y Y  Y Y 
LogNormal  Y Y  Y Y 
Normal  Y Y  Y Y 
Poisson  N Y  N Y 
TStudent  Y Y  N N 
Uniform  Y Y  Y Y 
Projects
 Distribution and empirical data statistical properties
 Quantile Functions
Installation
 Add the dependency to your
shard.yml
:
dependencies:
alea:
github: nin93/alea

Run
shards install

Import the library:
require "alea"
Usage
Sampling
Random
is the interface provided to perform sampling:
random = Alea::Random.new
random.normal # => 0.36790519967553736 : Float64
# Append '32' to call the singleprecision version
random.normal32 # => 0.19756398 : Float32
It also accepts an initial seed to reproduce the same seemingly random events across runs:
seed = 9377
random = Alea::Random.new(seed)
random.exp # => 0.10203669577353723 : Float64
Unsafe Methods
Plain sampling methods (such as #normal
, #gamma32
) performs checks over arguments passed to prevent bad data generation or inner exceptions. In order to avoid checks (might be slow in a large data generation) you must use their unsafe version by prepending next_
to them:
random = Alea::Random.new
random.normal(loc: 0, sigma: 0) # raises Alea::UndefinedError: sigma is 0 or negative.
random.next_normal(loc: 0, sigma: 0) # these might raise internal exceptions.
Timings are definitely comparable, though: see the benchmarks for direct comparisons between these methods.
PRNGs
Random
is actually a wrapper over a well defined pseudorandom number generator. The basic generation of integers and floats comes from the underlying engine, more specifically from: #next_u32
, returning a random UInt32
, and #next_u64
, returning a random UInt64
. Floats are obtained by ldexp
(load exponent) operations upon generated unsigned integers; signed integers are obtained by raw cast.
Currently implemented engines:
XSR128
backed by xoroshiro128++ (32/64 bit)XSR256
backed by xoshiro256++ (32/64 bit)
The digits in the class name stand for the storage of their state in bits. Their period is 2^128 1
for XSR128
and 2^256 1
for XSR256
.
These engines are from the xoshiro (XOR/shift/rotate) collection, designed by Sebastiano Vigna and David Blackman: really fast generators promising exquisite statistical properties as well.
By default, the PRNG in use by Random
is XSR128
. You can, though, pass the desired engine as an argument to the constructor. Here is an example using XSR256
:
random = Alea::Random.new(Alea::XSR256)
random.float # => 0.6533582874035311 : Float64
random.prng # => Alea::XSR256
# Or seeded as well
random = Alea::Random.new(193, Alea::XSR256)
random.float # => 0.4507930323670787 : Float64
Custom PRNG
All PRNGs in this library inherit from PRNG
. You are allowed to build your own custom PRNG by inheriting the above parent class and defining the methods needed by Alea::Random
to ensure proper repeatability and sampling, as described in this example.
It is worth noting that in these implementations #next_u32
and #next_u64
depend on different states and thus they are independent from each other, as well as #next_f32
and #next_f64
or #next_i32
and #next_i64
. It is still fine, though, if both #next_u32
and #next_u64
rely on the same state, if you want. I choose not to, as it makes state advancements unpredictable.
Cumulative Distribution Functions
CDF
is the interface used to calculate the Cumulative Distribution Functions. Given X ~ D and a fixed quantile x, CDFs are defined as the functions that associate x to the probability that the realvalued random X from the distribution D will take a value less or equal to x.
Arguments passed to CDF
methods to shape the distributions are analogous to those used for sampling:
Alea::CDF.normal(0.0) # => 0.5 : Float64
Alea::CDF.normal(2.0, loc: 1.0, sigma: 0.5) # => 0.9772498680518208 : Float64
Alea::CDF.chisq(5.279, df: 5.0) # => 0.6172121213841358 : Float64
Alea::CDF.chisq32(5.279, df: 5.0) # => 0.61721206 : Float32
Documentation
Documentation is hosted on GitHub Pages.
References
Fully listed in LICENSE.md:
 Crystal
Random
module for uniform sampling  NumPy
random
module for pseudorandom sampling methods  JuliaLang
random
module for ziggurat methods  IncGammaBeta.jl for incomplete gamma functions
Contributing
 Fork it (https://github.com/nin93/alea/fork)
 Create your feature branch (
git checkout b mynewfeature
)  Commit your changes (
git commit am 'Add some feature'
)  Push to the branch (
git push origin mynewfeature
)  Create a new Pull Request
Contributors
 Elia Franzella  creator and maintainer
 9
 1
 0
 0
 2 months ago
 April 20, 2020
Other
Sat, 28 Nov 2020 22:19:27 GMT