DEF RS_RNG_NAME = u'pcg32'
DEF RS_RNG_ADVANCEABLE = 1
DEF RS_RNG_SEED = 2

cdef extern from "distributions.h":
    ctypedef struct pcg_state_setseq_64:
        uint64_t state
        uint64_t inc

    ctypedef pcg_state_setseq_64 pcg32_random_t

    cdef struct s_aug_state:
        pcg32_random_t *rng
        binomial_t *binomial

        int has_gauss, shift_zig_random_int, has_uint32, has_gauss_float
        float gauss_float
        double gauss
        uint64_t zig_random_int
        uint32_t uinteger

    ctypedef s_aug_state aug_state

    cdef void set_seed(aug_state* state, uint64_t seed, uint64_t inc)

    cdef void advance_state(aug_state* state, uint64_t delta)

ctypedef uint64_t rng_state_t

ctypedef pcg32_random_t rng_t

cdef object _get_state(aug_state state):
    return (state.rng.state, state.rng.inc)

cdef object _set_state(aug_state *state, object state_info):
    state.rng.state = state_info[0]
    state.rng.inc = state_info[1]

DEF CLASS_DOCSTRING = u"""
RandomState(seed=None)

Container for the PCG-32 pseudo-random number generator.

PCG-32 is a 64-bit implementation of O'Neill's permutation congruential 
generator ([1]_, [2]_). PCG-32 has a period of :math:`2^{64}` and supports advancing
an arbitrary number of steps as well as :math:`2^{63}` streams.

``pcg32.RandomState`` exposes a number of methods for generating random
numbers drawn from a variety of probability distributions. In addition to the
distribution-specific arguments, each method takes a keyword argument
`size` that defaults to ``None``. If `size` is ``None``, then a single
value is generated and returned. If `size` is an integer, then a 1-D
array filled with generated values is returned. If `size` is a tuple,
then an array with that shape is filled and returned.

**No Compatibility Guarantee**

``pcg32.RandomState`` does not make a guarantee that a fixed seed and a
fixed series of calls to ``pcg32.RandomState`` methods using the same
parameters will always produce the same results. This is different from
``numpy.random.RandomState`` guarantee. This is done to simplify improving
random number generators.  To ensure identical results, you must use the
same release version.

Parameters
----------
seed : {None, long}, optional
    Random seed initializing the pseudo-random number generator.
    Can be an integer in [0, 2**64] or ``None`` (the default).
    If `seed` is ``None``, then ``pcg32.RandomState`` will try to read data
    from ``/dev/urandom`` (or the Windows analog) if available. If
    unavailable, a 64-bit hash of the time and process ID is used.
inc : {None, int}, optional
    Stream to return.  
    Can be an integer in [0, 2**64] or ``None`` (the default).  If `inc` is 
    ``None``, then 1 is used.  Can be used with the same seed to 
    produce multiple streams using other values of inc.
    
Notes
-----
Supports the method advance to advance the PRNG an arbitrary number of steps. 
The state of the PCG-32 PRNG is represented by 2 64-bit unsigned integers.

See pcg64 for a similar implementation with a larger period.

**Parallel Features**

``pcg32.RandomState`` can be used in parallel applications in one of two ways.
The preferable method is to use sub-streams, which are generated by using the
same value of ``seed`` and incrementing the second value, ``inc``.

>>> import randomstate.prng.pcg32 as rnd
>>> rs = [rng.RandomState(1234, i + 1) for i in range(10)]

The alternative method is to call ``advance`` on a single RandomState to
produce non-overlapping sequences.

>>> import randomstate.prng.pcg32 as rnd
>>> rs = [rng.RandomState(1234, 1) for _ in range(10)]
>>> for i in range(10):
        rs[i].advance(i * :math:`2^{32}`)

*Note*: Due to the limited period of ``pcg32.RandomState``  using ``advance``
in parallel applications is not recommended.

**State and Seeding**

The ``pcg32.RandomState`` state vector consists of 2 unsigned 64-bit values.
``pcg32.RandomState``  is seeded using a single 64-bit unsigned integer.
In addition, a second 64-bit unsigned integer is used to set the stream.

References
----------
.. [1] "PCG, A Family of Better Random Number Generators",
       http://www.pcg-random.org/
.. [2] O'Neill, Melissa E. "PCG: A Family of Simple Fast Space-Efficient 
       Statistically Good Algorithms for Random Number Generation"
"""