extern crate byteorder;
extern crate num_traits;
extern crate rand;
extern crate rand_core;
#[cfg(feature = "serde1")]
extern crate serde;
use rand_core::{RngCore, SeedableRng};
use std::num::Wrapping;
pub mod extension;
pub mod multiplier;
pub mod numops;
pub mod outputmix;
pub mod seeds;
pub mod stream;
#[cfg(feature = "serde1")]
pub mod serialization;
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
use multiplier::{DefaultMultiplier, McgMultiplier, Multiplier};
use num_traits::{One, Zero};
use numops::*;
use outputmix::{DXsMMixin, OutputMixin, XshRrMixin, XshRsMixin};
use seeds::PcgSeeder;
use stream::{NoSeqStream, OneSeqStream, SpecificSeqStream, Stream, UniqueSeqStream};
use std::marker::PhantomData;
pub struct PcgEngine<
Itype,
Xtype,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
> {
state: Itype,
stream_mix: StreamMix,
mul_mix: PhantomData<MulMix>,
out_mix: PhantomData<OutMix>,
phantom: PhantomData<Xtype>,
}
impl<Itype, Xtype, StreamMix, MulMix, OutMix> PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>
where
Itype: Zero,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>: SeedableRng,
{
pub fn new_unseeded() -> Self {
PcgEngine::from_seed(Default::default())
}
}
impl<Itype, Xtype, StreamMix, MulMix, OutMix> PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>
where
Itype: Copy + BitSize,
Xtype: BitSize,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
{
pub fn get_state(&self) -> PCGStateInfo<Itype> {
PCGStateInfo {
state: self.state,
increment: self.stream_mix.increment(),
multiplier: MulMix::multiplier(),
internal_width: Itype::BITS,
output_width: Xtype::BITS,
output_mixin: OutMix::SERIALIZER_ID.into(),
}
}
pub fn restore_state_with_no_verification(state: PCGStateInfo<Itype>) -> Self {
PcgEngine {
state: state.state,
stream_mix: StreamMix::build(Some(state.increment)),
mul_mix: PhantomData,
out_mix: PhantomData,
phantom: PhantomData,
}
}
}
impl<Itype, Xtype, MulMix, OutMix> PcgEngine<Itype, Xtype, SpecificSeqStream<Itype>, MulMix, OutMix>
where
Itype: Copy + Eq + Zero + BitSize,
SpecificSeqStream<Itype>: Stream<Itype>,
Xtype: BitSize,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
{
pub fn restore_state(state: PCGStateInfo<Itype>) -> Result<Self, String> {
if OutMix::SERIALIZER_ID != state.output_mixin {
return Err("Output Mixin type does not match recorded state".into());
}
if MulMix::multiplier() != state.multiplier {
return Err("PCG using different multiplier than recorded state".into());
}
if Xtype::BITS != state.output_width {
return Err("PCG uses different output size than recorded state".into());
}
if Itype::BITS != state.internal_width {
return Err("PCG uses different internal size than recorded state".into());
}
let mut stream = SpecificSeqStream::new();
stream.set_stream(state.increment);
Ok(PcgEngine {
state: state.state,
stream_mix: stream,
mul_mix: PhantomData,
out_mix: PhantomData,
phantom: PhantomData,
})
}
}
impl<Itype, StreamMix, MulMix, OutMix> RngCore for PcgEngine<Itype, u32, StreamMix, MulMix, OutMix>
where
Itype: PcgOps + Clone,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, u32>,
{
fn next_u32(&mut self) -> u32 {
let oldstate = self.state.clone();
self.state = self
.stream_mix
.increment()
.wrap_add(oldstate.wrap_mul(MulMix::multiplier()));
OutMix::output(oldstate, self.stream_mix.increment(), MulMix::multiplier())
}
fn next_u64(&mut self) -> u64 {
rand_core::impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand_core::impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl<Itype, StreamMix, MulMix, OutMix> RngCore for PcgEngine<Itype, u64, StreamMix, MulMix, OutMix>
where
Itype: PcgOps + Clone,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, u64>,
{
fn next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
fn next_u64(&mut self) -> u64 {
let oldstate = self.state.clone();
self.state = self
.stream_mix
.increment()
.wrap_add(oldstate.wrap_mul(MulMix::multiplier()));
OutMix::output(oldstate, self.stream_mix.increment(), MulMix::multiplier())
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand_core::impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl<Itype, Xtype, StreamMix, MulMix, OutMix> PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>
where
Itype: PcgOps
+ Copy
+ One
+ Zero
+ Ord
+ Eq
+ std::ops::BitAnd<Itype, Output = Itype>
+ std::ops::ShrAssign,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
{
pub fn advance(&mut self, delta: Itype) {
let mut cur_mult = MulMix::multiplier();
let mut cur_plus = self.stream_mix.increment();
let mut delta = delta;
let mut acc_mult = Itype::one();
let mut acc_plus = Itype::zero();
while delta > Itype::zero() {
if (delta & Itype::one()) != Itype::zero() {
acc_mult = acc_mult.wrap_mul(cur_mult);
acc_plus = acc_plus.wrap_mul(cur_mult).wrap_add(cur_plus);
}
cur_plus = cur_mult.wrap_add(Itype::one()).wrap_mul(cur_plus);
cur_mult = cur_mult.wrap_mul(cur_mult);
delta >>= Itype::one();
}
self.state = acc_mult.wrap_mul(self.state).wrap_add(acc_plus);
}
}
pub type OneseqXshRs6432 = PcgEngine<u64, u32, OneSeqStream, DefaultMultiplier, XshRsMixin>;
pub type OneseqXshRr6432 = PcgEngine<u64, u32, OneSeqStream, DefaultMultiplier, XshRrMixin>;
pub type OneseqDXsM6432 = PcgEngine<u64, u32, OneSeqStream, DefaultMultiplier, DXsMMixin>;
pub type UniqueXshRs6432 = PcgEngine<u64, u32, UniqueSeqStream, DefaultMultiplier, XshRsMixin>;
pub type UniqueXshRr6432 = PcgEngine<u64, u32, UniqueSeqStream, DefaultMultiplier, XshRrMixin>;
pub type UniqueDXsM6432 = PcgEngine<u64, u32, UniqueSeqStream, DefaultMultiplier, DXsMMixin>;
pub type SetseqXshRs6432 =
PcgEngine<u64, u32, SpecificSeqStream<u64>, DefaultMultiplier, XshRsMixin>;
pub type SetseqXshRr6432 =
PcgEngine<u64, u32, SpecificSeqStream<u64>, DefaultMultiplier, XshRrMixin>;
pub type SetseqDXsM6432 = PcgEngine<u64, u32, SpecificSeqStream<u64>, DefaultMultiplier, DXsMMixin>;
pub type McgXshRs6432 = PcgEngine<u64, u32, NoSeqStream, McgMultiplier, XshRsMixin>;
pub type McgXshRr6432 = PcgEngine<u64, u32, NoSeqStream, McgMultiplier, XshRrMixin>;
pub type McgDXsM6432 = PcgEngine<u64, u32, NoSeqStream, McgMultiplier, DXsMMixin>;
pub type Pcg32 = SetseqDXsM6432;
pub type Pcg32Oneseq = OneseqDXsM6432;
pub type Pcg32Unique = UniqueDXsM6432;
pub type Pcg32Fast = McgXshRs6432;
#[cfg(feature = "u128")]
pub type OneseqXshRs12832 = PcgEngine<u128, u32, OneSeqStream, DefaultMultiplier, XshRsMixin>;
#[cfg(feature = "u128")]
pub type OneseqXshRr12832 = PcgEngine<u128, u32, OneSeqStream, DefaultMultiplier, XshRrMixin>;
#[cfg(feature = "u128")]
pub type OneseqDXsM12832 = PcgEngine<u128, u32, OneSeqStream, DefaultMultiplier, DXsMMixin>;
#[cfg(feature = "u128")]
pub type UniqueXshRs12832 = PcgEngine<u128, u32, UniqueSeqStream, DefaultMultiplier, XshRsMixin>;
#[cfg(feature = "u128")]
pub type UniqueXshRr12832 = PcgEngine<u128, u32, UniqueSeqStream, DefaultMultiplier, XshRrMixin>;
#[cfg(feature = "u128")]
pub type UniqueDXsM12832 = PcgEngine<u128, u32, UniqueSeqStream, DefaultMultiplier, DXsMMixin>;
#[cfg(feature = "u128")]
pub type SetseqXshRs12832 =
PcgEngine<u128, u32, SpecificSeqStream<u128>, DefaultMultiplier, XshRsMixin>;
#[cfg(feature = "u128")]
pub type SetseqXshRr12832 =
PcgEngine<u128, u32, SpecificSeqStream<u128>, DefaultMultiplier, XshRrMixin>;
#[cfg(feature = "u128")]
pub type SetseqDXsM12832 =
PcgEngine<u128, u32, SpecificSeqStream<u128>, DefaultMultiplier, DXsMMixin>;
#[cfg(feature = "u128")]
pub type McgXshRs12832 = PcgEngine<u128, u32, NoSeqStream, McgMultiplier, XshRsMixin>;
#[cfg(feature = "u128")]
pub type McgXshRr12832 = PcgEngine<u128, u32, NoSeqStream, McgMultiplier, XshRrMixin>;
#[cfg(feature = "u128")]
pub type McgDXsM12832 = PcgEngine<u128, u32, NoSeqStream, McgMultiplier, DXsMMixin>;
#[cfg(feature = "u128")]
pub type Pcg32L = SetseqDXsM12832;
#[cfg(feature = "u128")]
pub type Pcg32LOneseq = OneseqDXsM12832;
#[cfg(feature = "u128")]
pub type Pcg32LUnique = UniqueDXsM12832;
#[cfg(feature = "u128")]
pub type Pcg32LFast = McgXshRs12832;
#[cfg(feature = "u128")]
pub type OneseqXshRs12864 = PcgEngine<u128, u64, OneSeqStream, DefaultMultiplier, XshRsMixin>;
#[cfg(feature = "u128")]
pub type OneseqXshRr12864 = PcgEngine<u128, u64, OneSeqStream, DefaultMultiplier, XshRrMixin>;
#[cfg(feature = "u128")]
pub type OneseqDXsM12864 = PcgEngine<u128, u64, OneSeqStream, DefaultMultiplier, DXsMMixin>;
#[cfg(feature = "u128")]
pub type UniqueXshRs12864 = PcgEngine<u128, u64, UniqueSeqStream, DefaultMultiplier, XshRsMixin>;
#[cfg(feature = "u128")]
pub type UniqueXshRr12864 = PcgEngine<u128, u64, UniqueSeqStream, DefaultMultiplier, XshRrMixin>;
#[cfg(feature = "u128")]
pub type UniqueDXsM12864 = PcgEngine<u128, u64, UniqueSeqStream, DefaultMultiplier, DXsMMixin>;
#[cfg(feature = "u128")]
pub type SetseqXshRs12864 =
PcgEngine<u128, u64, SpecificSeqStream<u128>, DefaultMultiplier, XshRsMixin>;
#[cfg(feature = "u128")]
pub type SetseqXshRr12864 =
PcgEngine<u128, u64, SpecificSeqStream<u128>, DefaultMultiplier, XshRrMixin>;
#[cfg(feature = "u128")]
pub type SetseqDXsM12864 =
PcgEngine<u128, u64, SpecificSeqStream<u128>, DefaultMultiplier, DXsMMixin>;
#[cfg(feature = "u128")]
pub type McgXshRs12864 = PcgEngine<u128, u64, NoSeqStream, McgMultiplier, XshRsMixin>;
#[cfg(feature = "u128")]
pub type McgXshRr12864 = PcgEngine<u128, u64, NoSeqStream, McgMultiplier, XshRrMixin>;
#[cfg(feature = "u128")]
pub type McgDXsM12864 = PcgEngine<u128, u64, NoSeqStream, McgMultiplier, DXsMMixin>;
#[cfg(feature = "u128")]
pub type Pcg64 = SetseqDXsM12864;
#[cfg(feature = "u128")]
pub type Pcg64Oneseq = OneseqDXsM12864;
#[cfg(feature = "u128")]
pub type Pcg64Unique = UniqueDXsM12864;
#[cfg(feature = "u128")]
pub type Pcg64Fast = McgXshRs12864;
impl<Itype, Xtype, StreamMix, MulMix, OutMix> SeedableRng
for PcgEngine<Itype, Xtype, StreamMix, MulMix, OutMix>
where
Itype: Sized + seeds::ReadByteOrder + Zero + One,
StreamMix: Stream<Itype>,
MulMix: Multiplier<Itype>,
OutMix: OutputMixin<Itype, Xtype>,
PcgSeeder<Itype>: Default,
{
type Seed = PcgSeeder<Itype>;
fn from_seed(mut seed: Self::Seed) -> Self {
PcgEngine {
state: seed.get(),
stream_mix: StreamMix::build(Some(seed.get())),
mul_mix: PhantomData::<MulMix>,
out_mix: PhantomData::<OutMix>,
phantom: PhantomData::<Xtype>,
}
}
}
pub struct Pcg32Basic {
state: u64,
inc: u64,
}
impl Pcg32Basic {
pub fn new_unseeded() -> Pcg32Basic {
Pcg32Basic::from_seed(Default::default())
}
}
impl RngCore for Pcg32Basic {
fn next_u32(&mut self) -> u32 {
let oldstate = Wrapping(self.state);
self.state = (oldstate * Wrapping(6_364_136_223_846_793_005u64) + Wrapping(self.inc | 1)).0;
let xorshifted: u32 = (((oldstate >> 18usize) ^ oldstate) >> 27usize).0 as u32;
let rot: u32 = (oldstate >> 59usize).0 as u32;
(xorshifted >> rot) | (xorshifted << ((-(rot as i32)) & 31))
}
fn next_u64(&mut self) -> u64 {
rand_core::impls::next_u64_via_u32(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand_core::impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl SeedableRng for Pcg32Basic {
type Seed = PcgSeeder<u64>;
fn from_seed(mut seed: Self::Seed) -> Pcg32Basic {
Pcg32Basic {
state: seed.get(),
inc: seed.get(),
}
}
}
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct PCGStateInfo<Itype> {
pub state: Itype,
pub increment: Itype,
pub multiplier: Itype,
pub internal_width: usize,
pub output_width: usize,
pub output_mixin: String,
}