use num_traits::{Float, Num, NumCast, identities};
use rand::{RngCore, distr::Distribution};
use std::ops;
pub trait Scalar:
Copy
+ Num
+ NumCast
+ PartialOrd
+ ops::AddAssign
+ ops::SubAssign
+ ops::DivAssign
+ ops::MulAssign
{
fn zero() -> Self {
identities::zero()
}
fn one() -> Self {
identities::one()
}
const MIN: Self;
const MAX: Self;
}
impl Scalar for f32 {
const MIN: Self = Self::NEG_INFINITY;
const MAX: Self = Self::INFINITY;
}
impl Scalar for f64 {
const MIN: Self = Self::NEG_INFINITY;
const MAX: Self = Self::INFINITY;
}
impl Scalar for u8 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for i8 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for u16 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for i16 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for u32 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for i32 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for u64 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for i64 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for u128 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for i128 {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for usize {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
impl Scalar for isize {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}
pub trait ScalarFloat: Scalar + Float {}
impl<T: Scalar + Float> ScalarFloat for T {}
pub struct Interval<S: Scalar>(pub S, pub S);
impl<S: Scalar> Interval<S> {
pub fn empty() -> Self {
Self(S::MAX, S::MIN)
}
pub fn maximal() -> Self {
Self(S::MIN, S::MAX)
}
pub fn unit() -> Self {
Self(<S as Scalar>::zero(), <S as Scalar>::one())
}
pub fn contains(&self, value: S) -> bool {
self.0 <= value && value < self.1
}
pub fn open_contains(&self, value: S) -> bool {
self.0 < value && value < self.1
}
pub fn closed_contains(&self, value: S) -> bool {
self.0 <= value && value <= self.1
}
pub fn openclosed_contains(&self, value: S) -> bool {
self.0 < value && value <= self.1
}
}
impl<S: RandFloat> Interval<S> {
pub fn random<R: RngCore + ?Sized>(&self, r: &mut R) -> S {
S::sample_ab(r, self.0, self.1)
}
pub fn random_open<R: RngCore + ?Sized>(&self, r: &mut R) -> S {
S::sample_ab_open(r, self.0, self.1)
}
pub fn random_closed<R: RngCore + ?Sized>(&self, r: &mut R) -> S {
S::sample_ab_closed(r, self.0, self.1)
}
pub fn random_openclosed<R: RngCore + ?Sized>(&self, r: &mut R) -> S {
S::sample_ab_openclosed(r, self.0, self.1)
}
}
pub trait RandFloat: ScalarFloat {
fn sample_from<R: RngCore + ?Sized>(r: &mut R, d: &impl Distribution<Self>) -> Self {
Self::from(d.sample(r)).unwrap()
}
fn sample01<R: RngCore + ?Sized>(r: &mut R) -> Self;
fn sample01_open<R: RngCore + ?Sized>(r: &mut R) -> Self;
fn sample01_closed<R: RngCore + ?Sized>(r: &mut R) -> Self;
fn sample01_openclosed<R: RngCore + ?Sized>(r: &mut R) -> Self {
<Self as Scalar>::one() - Self::sample01(r)
}
fn sample_ab<R: RngCore + ?Sized>(r: &mut R, a: Self, b: Self) -> Self {
(b - a) * (a + Self::sample01(r))
}
fn sample_ab_open<R: RngCore + ?Sized>(r: &mut R, a: Self, b: Self) -> Self {
(b - a) * (a + Self::sample01_open(r))
}
fn sample_ab_closed<R: RngCore + ?Sized>(r: &mut R, a: Self, b: Self) -> Self {
(b - a) * (a + Self::sample01_closed(r))
}
fn sample_ab_openclosed<R: RngCore + ?Sized>(r: &mut R, a: Self, b: Self) -> Self {
(b - a) * (a + Self::sample01_openclosed(r))
}
}
impl RandFloat for f32 {
fn sample_from<R: RngCore + ?Sized>(r: &mut R, d: &impl Distribution<Self>) -> Self {
d.sample(r) as Self
}
fn sample01<R: RngCore + ?Sized>(r: &mut R) -> Self {
Self::sample_from(r, &rand::distr::StandardUniform {})
}
fn sample01_open<R: RngCore + ?Sized>(r: &mut R) -> Self {
Self::sample_from(r, &rand::distr::Open01 {})
}
fn sample01_closed<R: RngCore + ?Sized>(r: &mut R) -> Self {
let d =
rand::distr::Uniform::new_inclusive(<Self as Scalar>::zero(), <Self as Scalar>::one())
.unwrap();
Self::sample_from(r, &d)
}
}
impl RandFloat for f64 {
fn sample_from<R: RngCore + ?Sized>(r: &mut R, d: &impl Distribution<Self>) -> Self {
d.sample(r) as Self
}
fn sample01<R: RngCore + ?Sized>(r: &mut R) -> Self {
Self::sample_from(r, &rand::distr::StandardUniform {})
}
fn sample01_open<R: RngCore + ?Sized>(r: &mut R) -> Self {
Self::sample_from(r, &rand::distr::Open01 {})
}
fn sample01_closed<R: RngCore + ?Sized>(r: &mut R) -> Self {
let d =
rand::distr::Uniform::new_inclusive(<Self as Scalar>::zero(), <Self as Scalar>::one())
.unwrap();
Self::sample_from(r, &d)
}
}
#[cfg(test)]
mod tests {
use super::*;
pub fn mock_rng() -> rand::rngs::mock::StepRng {
rand::rngs::mock::StepRng::new(1, 1)
}
#[test]
pub fn convert_f64_to_f32() {
let max_f = std::f64::MAX;
<f32 as NumCast>::from(max_f).unwrap();
let small_f = std::f64::EPSILON;
<f32 as NumCast>::from(small_f).unwrap();
}
#[test]
pub fn test_uniform_01_sampling_f64() {
let mut r = mock_rng();
for _ in 0..500 {
let value = f64::sample01(&mut r);
assert!(0.0 <= value && value < 1.0);
let value = f64::sample01_open(&mut r);
assert!(0.0 < value && value < 1.0);
let value = f64::sample01_closed(&mut r);
assert!(0.0 <= value && value <= 1.0);
let value = f64::sample01_openclosed(&mut r);
assert!(0.0 < value && value <= 1.0);
}
}
}