Report a bug
If you spot a problem with this page, click here to create a GitHub issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

mir.random.engine.pcg

Permuted Congruential Generator (PCG)
Implemented as per the C++ version of PCG, pcg-random.org.
Paper available pcg-random.org/paper.html

Author Melissa O'Neill (C++). D translation Nicholas Wilson.

PCG Random Number Generation for C++
Copyright 2014 Melissa O'Neill
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
For additional information about the PCG random number generation scheme, including its license and other licensing options, visit
pcg-random.org

alias pcg32 = PermutedCongruentialEngine!(xsh_rr, cast(stream_t)3, true).PermutedCongruentialEngine;

alias pcg32_unique = PermutedCongruentialEngine!(xsh_rr, cast(stream_t)0, true).PermutedCongruentialEngine;

alias pcg32_oneseq = PermutedCongruentialEngine!(xsh_rr, cast(stream_t)2, true).PermutedCongruentialEngine;

alias pcg32_fast = PermutedCongruentialEngine!(xsh_rr, cast(stream_t)1, true).PermutedCongruentialEngine;
32-bit output PCGs with 64 bits of state.
alias pcg8_once_insecure = PermutedCongruentialEngine!(rxs_m_xs_forward, cast(stream_t)3, true).PermutedCongruentialEngine;

alias pcg16_once_insecure = PermutedCongruentialEngine!(rxs_m_xs_forward, cast(stream_t)3, true).PermutedCongruentialEngine;

alias pcg32_once_insecure = PermutedCongruentialEngine!(rxs_m_xs_forward, cast(stream_t)3, true).PermutedCongruentialEngine;

alias pcg64_once_insecure = PermutedCongruentialEngine!(rxs_m_xs_forward, cast(stream_t)3, true).PermutedCongruentialEngine;
PCGs with n bits output and n bits of state.
alias pcg8_oneseq_once_insecure = PermutedCongruentialEngine!(rxs_m_xs_forward, cast(stream_t)2, true).PermutedCongruentialEngine;

alias pcg16_oneseq_once_insecure = PermutedCongruentialEngine!(rxs_m_xs_forward, cast(stream_t)2, true).PermutedCongruentialEngine;

alias pcg32_oneseq_once_insecure = PermutedCongruentialEngine!(rxs_m_xs_forward, cast(stream_t)2, true).PermutedCongruentialEngine;

alias pcg64_oneseq_once_insecure = PermutedCongruentialEngine!(rxs_m_xs_forward, cast(stream_t)2, true).PermutedCongruentialEngine;
As above but the increment is not dynamically setable.
struct PermutedCongruentialEngine(alias output, stream_t streamType, bool output_previous, mult_...) if (mult_.length <= 1);
The PermutedCongruentialEngine:
Parameters:
output should be one of the above functions. Controls the output permutation of the state.
streamType one of unique, none, oneseq, specific. Controls the Increment of the LCG portion of the PCG.
output_previous if true then the pre-advance version (increasing instruction-level parallelism) if false then use the post-advance version (reducing register pressure)
mult_ optionally set the multiplier for the LCG.
enum auto isRandomEngine;
alias Uint = TemplateArgsOf!output[1];
Uint state;
enum auto period_pow2;
enum auto max;
this()(Uint seed, Uint stream_ = default_increment_unset_stream!Uint);
ReturnType!output opCall()();
void skip()(Uint delta);
Skip forward in the random sequence in Ο(log n) time. Even though delta is an unsigned integer, we can pass a signed integer to go backwards, it just goes "the long way round".
enum bool isUniformRandom;

enum ReturnType!output min;

enum bool empty;

const @property ReturnType!output front()();

void popFront()();

void seed()(Uint seed);

const @property typeof(this) save()();
Compatibility with Phobos library methods. Presents this RNG as an InputRange. Only available if output_previous == true.
The reason that this is enabled when output_previous == true is because front can be implemented without additional cost.
save is implemented if streamType is not [stream_t.unique].
This struct disables its default copy constructor and so will only work with Phobos functions that "do the right thing" and take RNGs by reference and do not accidentally make implicit copies.
template unique_stream(Uint)
Increment for LCG portion of the PCG is the address of the RNG
enum auto is_mcg;
const @property @trusted Uint increment()();
Uint stream()();
enum auto can_specify_stream;
enum size_t streams_pow2;
template no_stream(Uint)
Increment is 0. The LCG portion of the PCG is an MCG.
enum auto is_mcg;
enum Uint increment;
enum auto can_specify_stream;
enum size_t streams_pow2;
template oneseq_stream(Uint)
Increment of the LCG portion of the PCG is default_increment.
enum auto is_mcg;
enum Uint increment;
enum auto can_specify_stream;
enum size_t streams_pow2;
template specific_stream(Uint)
The increment is dynamically settable and defaults to default_increment!T.
enum auto is_mcg;
Uint inc_;
alias increment = inc_;
enum auto can_specify_stream;
void set_stream()(Uint u);
enum size_t streams_pow2;
enum stream_t: int;
Select the above mixin templates.
unique
Increment is cast(size_t) &RNG.
none
Increment is 0.
oneseq
Increment is the default increment.
specific
Increment is runtime setable and defaults to the default (same as oneseq)
Uint unxorshift(Uint)(Uint x, size_t bits, size_t shift);
XorShifts are invertible, but they are someting of a pain to invert. This function backs them out. It's used by the whacky "inside out" generator defined later.
O xsh_rs(O, Uint)(Uint state);
OUTPUT FUNCTIONS.
These are the core of the PCG generation scheme. They specify how to turn the base LCG's internal state into the output value of the final generator.
All of the classes have code that is written to allow it to be applied at *arbitrary* bit sizes.
XSH RS -- high xorshift, followed by a random shift
Fast. A good performer.
O xsh_rr(O, Uint)(Uint state);
XSH RR -- high xorshift, followed by a random rotate
Fast. A good performer. Slightly better statistically than XSH RS.
O rxs(O, Uint)(Uint state);
RXS -- random xorshift
O rxs_m_xs_forward(O, Uint)(Uint state)
if (is(O == Uint));

O rxs_m_xs_reverse(O, Uint)(Uint state)
if (is(O == Uint));
RXS M XS -- random xorshift, mcg multiply, fixed xorshift
The most statistically powerful generator, but all those steps make it slower than some of the others. We give it the rottenest jobs.
Because it's usually used in contexts where the state type and the result type are the same, it is a permutation and is thus invertible. We thus provide a function to invert it. This function is used to for the "inside out" generator used by the extended generator.
O xsl_rr(O, Uint)(Uint state);
XSL RR -- fixed xorshift (to low bits), random rotate
Useful for 128-bit types that are split across two CPU registers.
O xsl_rr_rr(O, Uint)(Uint state)
if (is(O == Uint));
XSL RR RR -- fixed xorshift (to low bits), random rotate (both parts)
Useful for 128-bit types that are split across two CPU registers. If you really want an invertible 128-bit RNG, I guess this is the one.
O xsh(O, Uint)(Uint state)
if (Uint.sizeof > 8);
XSH -- fixed xorshift (to high bits)
Not available at 64-bits or less.
O xsl(O, Uint)(Uint state)
if (Uint.sizeof > 8);
XSL -- fixed xorshift (to low bits)
Not available at 64-bits or less.