#![warn(missing_docs)]
pub mod error;
pub use crate::error::{rerror, RanError, Re};
use core::{cell::Cell, ops::RangeInclusive};
use std::fmt::Write;
use std::time::{SystemTime, UNIX_EPOCH};
const MANTISSA_MAX: f64 = (1u64 << f64::MANTISSA_DIGITS) as f64;
pub fn stringv<T>(x: &[T]) -> String
where
T: std::fmt::Display,
{
match x.len() {
0 => "[]".to_string(),
1 => format!("[{}]", x[0]),
_ => {
x.iter().skip(1).fold(format!("[{}",x[0]), |mut s, item| {
write!(s, ",{}", item).ok();
s
}) + "]"
}
}
}
pub fn stringvv<T>(x: &[Vec<T>]) -> String
where
T: std::fmt::Display,
{
if x.is_empty() {
return "[]".to_string();
};
x.iter().fold("\n[\n".to_string(), |mut s, item| {
writeln!(s, " {},", stringv(item)).ok();
s
}) + "]"
}
thread_local!(
static SEED: Cell<u64> = (UNIX_EPOCH.elapsed().unwrap().as_nanos() as u64).into();
static X0: Cell<u64> = splitmix().into();
static X1: Cell<u64> = splitmix().into();
static X2: Cell<u64> = splitmix().into();
static X3: Cell<u64> = splitmix().into();
);
#[inline]
pub fn get_seed() -> u64 {
SEED.get()
}
pub fn set_seeds(mut seed: u64) {
let then = SystemTime::now();
if seed == 0 {
seed = then.elapsed().unwrap().as_nanos() as u64
};
SEED.set(seed);
put_xoshi(&[splitmix(), splitmix(), splitmix(), splitmix()])
}
fn splitmix() -> u64 {
let mut z = SEED.get().overflowing_add(0x9e3779b97f4a7c15).0;
SEED.set(z);
z = (z ^ (z >> 30)).overflowing_mul(0xbf58476d1ce4e5b9).0;
z = (z ^ (z >> 27)).overflowing_mul(0x94d049bb133111eb).0;
z ^ (z >> 31)
}
#[inline]
fn get_xoshi() -> [u64; 4] {
[X0.get(), X1.get(), X2.get(), X3.get()]
}
#[inline]
fn put_xoshi(seeds: &[u64; 4]) {
X0.set(seeds[0]);
X1.set(seeds[1]);
X2.set(seeds[2]);
X3.set(seeds[3]);
}
#[inline]
fn xoshi_step(s: &mut [u64; 4]) {
let t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = s[3].rotate_left(45);
}
pub fn ran_u64() -> u64 {
let mut s = get_xoshi(); let result = s[1]
.overflowing_mul(5)
.0
.rotate_left(7)
.overflowing_mul(9)
.0;
xoshi_step(&mut s); put_xoshi(&s); result
}
pub fn ran_ubits(bits: u8) -> u64 {
ran_u64() >> (64 - bits)
}
pub fn ran_u8() -> u8 {
ran_ubits(8) as u8
}
pub fn ran_u16() -> u16 {
ran_ubits(16) as u16
}
pub fn ran_i64() -> i64 {
ran_u64() as i64
}
#[inline]
pub fn ran_fast_f64() -> f64 {
let mut seed = SEED.get(); seed ^= seed << 13;
seed ^= seed >> 7;
seed ^= seed << 17;
SEED.set(seed); (seed >> 11) as f64 / MANTISSA_MAX
}
pub fn ran_f64() -> f64 {
let mut s = get_xoshi();
let result = ((s[0].overflowing_add(s[3])).0 >> 11) as f64 / MANTISSA_MAX;
xoshi_step(&mut s);
put_xoshi(&s);
result
}
pub fn ran_u64_range(r: RangeInclusive<u64>) -> u64 {
(ran_u64() % (1 + r.end() - r.start())) + r.start()
}
pub fn ran_i64_range(r: RangeInclusive<i64>) -> i64 {
(ran_u64() % (1 + r.end() - r.start()) as u64) as i64 + r.start()
}
pub fn ran_f64_range(r: RangeInclusive<f64>) -> f64 {
(r.end() - r.start()) * ran_f64() + r.start()
}
pub fn ranv_u64(d: usize) -> Result<Vec<u64>, Re> {
if d == 0 {
rerror("dimensions", "ranv_u64: zero size")?
} else {
Ok((0..d).map(|_| ran_u64()).collect::<Vec<u64>>())
}
}
pub fn ranv_u16(d: usize) -> Result<Vec<u16>, Re> {
if d == 0 {
rerror("dimensions", "ranv_u16: zero size")?
} else {
Ok((0..d).map(|_| ran_ubits(16) as u16).collect::<Vec<u16>>())
}
}
pub fn ranv_u8(d: usize) -> Result<Vec<u8>, Re> {
if d == 0 {
rerror("dimensions", "ranv_u8: zero size")?
} else {
Ok((0..d).map(|_| ran_ubits(8) as u8).collect::<Vec<u8>>())
}
}
pub fn ranv_i64(d: usize) -> Result<Vec<i64>, Re> {
if d == 0 {
rerror("dimensions", "ranv_i64: zero size")?
} else {
Ok((0..d).map(|_| ran_u64() as i64).collect::<Vec<i64>>())
}
}
pub fn ranv_f64(d: usize) -> Result<Vec<f64>, Re> {
if d == 0 {
rerror("dimensions", "ranvf64: zero size")?
} else {
Ok((0..d).map(|_| ran_f64()).collect::<Vec<f64>>())
}
}
pub fn ranv_u64_range(d: usize, r: RangeInclusive<u64>) -> Result<Vec<u64>, Re> {
if d == 0 {
rerror("dimensions", "ranv_urange: zero size")?
} else if r.is_empty() {
rerror("range", "ranv_urange: range is empty")?
} else {
Ok((0..d).map(|_| ran_u64_range(r.clone())).collect::<Vec<u64>>())
}
}
pub fn ranv_i64_range(d: usize, r: RangeInclusive<i64>) -> Result<Vec<i64>, Re> {
if d == 0 {
rerror("dimensions", "ranv_irange: zero size")?
} else if r.is_empty() {
rerror("range", "ranv_irange: range is empty")?
} else {
Ok((0..d).map(|_| ran_i64_range(r.clone())).collect::<Vec<i64>>())
}
}
pub fn ranv_f64_range(d: usize, r: RangeInclusive<f64>) -> Result<Vec<f64>, Re> {
if d == 0 {
rerror("dimensions", "ranv_frange: zero size")?
} else if r.is_empty() {
rerror("range", "ranv_frange: range is empty")?
} else {
Ok((0..d).map(|_| ran_f64_range(r.clone())).collect::<Vec<f64>>())
}
}
pub fn ranvv_u64(n: usize, d: usize) -> Result<Vec<Vec<u64>>, Re> {
if n * d <= 1 {
rerror("dimensions", format!("ranvv_u64: {d} {n}"))?
} else {
(0..n)
.map(|_| ranv_u64(d))
.collect::<Result<Vec<Vec<u64>>, Re>>()
}
}
pub fn ranvv_u16(n: usize, d: usize) -> Result<Vec<Vec<u16>>, Re> {
if n * d <= 1 {
rerror("dimensions", format!("ranvv_u16: {d} {n}"))?
} else {
(0..n)
.map(|_| ranv_u16(d))
.collect::<Result<Vec<Vec<u16>>, Re>>()
}
}
pub fn ranvv_u8(n: usize, d: usize) -> Result<Vec<Vec<u8>>, Re> {
if n * d <= 1 {
rerror("dimensions", format!("ranvv_u8: {d} {n}"))?
} else {
(0..n)
.map(|_| ranv_u8(d))
.collect::<Result<Vec<Vec<u8>>, Re>>()
}
}
pub fn ranvv_i64(n: usize, d: usize) -> Result<Vec<Vec<i64>>, Re> {
if n * d <= 1 {
rerror("dimensions", format!("ranvv_i64: {d} {n}"))?
} else {
(0..n)
.map(|_| ranv_i64(d))
.collect::<Result<Vec<Vec<i64>>, Re>>()
}
}
pub fn ranvv_f64(n: usize, d: usize) -> Result<Vec<Vec<f64>>, Re> {
if n * d <= 1 {
rerror("dimensions", format!("ranvvf64_xoshi: {d} {n}"))?
} else {
(0..n).map(|_| ranv_f64(d)).collect()
}
}
pub fn ranvv_u64_range(n: usize, d: usize, r: RangeInclusive<u64>) -> Result<Vec<Vec<u64>>, Re> {
if n * d <= 1 {
rerror("dimensions", format!("ranvv_urange: {d} {n}"))?
} else if r.is_empty() {
rerror("range", "ranvv_urange: range is empty")?
} else {
(0..n)
.map(|_| ranv_u64_range(d, r.clone()))
.collect::<Result<Vec<Vec<u64>>, Re>>()
}
}
pub fn ranvv_i64_range(n: usize, d: usize, r: RangeInclusive<i64>) -> Result<Vec<Vec<i64>>, Re> {
if n * d <= 1 {
rerror("dimensions", format!("ranvv_irange: {d} {n}"))?
} else if r.is_empty() {
rerror("range", "ranvv_irange: range is empty")?
} else {
(0..n)
.map(|_| ranv_i64_range(d, r.clone()))
.collect::<Result<Vec<Vec<i64>>, Re>>()
}
}
pub fn ranvv_f64_range(n: usize, d: usize, r: RangeInclusive<f64>) -> Result<Vec<Vec<f64>>, Re> {
if n * d <= 1 {
rerror("dimensions", format!("ranvv_frange: {d} {n}"))?
} else if r.is_empty() {
rerror("range", "ranvv_frange: range is empty")?
} else {
(0..n)
.map(|_| ranv_f64_range(d, r.clone()))
.collect::<Result<Vec<Vec<f64>>, Re>>()
}
}