use std::ops::{Range, RangeInclusive};
use crate::error::Error;
pub trait Value:
nalgebra::Scalar
+ nalgebra::ComplexField<RealField = Self>
+ nalgebra::RealField
+ num_traits::float::FloatCore
+ std::fmt::LowerExp
{
#[must_use]
fn two() -> Self {
Self::one() + Self::one()
}
#[must_use]
fn half() -> Self {
Self::one() / Self::two()
}
fn try_cast<U: num_traits::NumCast>(n: U) -> Result<Self, Error> {
num_traits::cast(n).ok_or(Error::CastFailed)
}
fn as_usize(&self) -> Option<usize> {
num_traits::cast(*self)
}
#[must_use]
fn powi(self, n: i32) -> Self {
nalgebra::ComplexField::powi(self, n)
}
#[must_use]
fn abs(self) -> Self {
nalgebra::ComplexField::abs(self)
}
#[must_use]
fn abs_sub(self, other: Self) -> Self {
nalgebra::ComplexField::abs(self - other)
}
fn is_sign_negative(&self) -> bool {
self < &Self::zero()
}
#[must_use]
fn clamp(self, min: Self, max: Self) -> Self {
nalgebra::RealField::clamp(self, min, max)
}
#[must_use]
fn min(self, other: Self) -> Self {
nalgebra::RealField::min(self, other)
}
#[must_use]
fn max(self, other: Self) -> Self {
nalgebra::RealField::max(self, other)
}
#[must_use]
fn ceil(self) -> Self {
num_traits::float::FloatCore::ceil(self)
}
#[must_use]
fn floor(self) -> Self {
num_traits::float::FloatCore::floor(self)
}
#[must_use]
fn is_near_zero(&self) -> bool {
self.abs() < Self::epsilon()
}
#[must_use]
fn is_finite(value: Self) -> bool {
num_traits::float::FloatCore::is_finite(value)
}
#[must_use]
fn f_signum(&self) -> Self {
match self {
_ if self.is_nan() => Self::nan(),
_ if nalgebra::RealField::is_sign_negative(self) => -Self::one(),
_ => Self::one(),
}
}
#[must_use]
fn factorial(n: usize) -> Self {
if n == 0 || n == 1 {
Self::one()
} else {
let mut result = Self::one();
for i in 2..=n {
let i = Self::try_cast(i).unwrap_or(Self::infinity());
result *= i;
}
result
}
}
#[must_use]
fn integer_binomial(n: usize, k: usize) -> Self {
if k > n {
return Self::zero();
}
let mut result = Self::one();
for i in 0..k {
let ni = Self::from_positive_int(n - i);
let ki = Self::from_positive_int(i + 1);
result *= ni / ki;
}
result
}
#[must_use]
fn binomial(n: Self, k: Self) -> Self {
if k < Self::zero() || k > n {
return Self::zero();
}
if k == Self::zero() || k == n {
return Self::one();
}
let k = nalgebra::RealField::min(k, n - k);
let mut result = Self::one();
for i in 0..k.as_usize().unwrap_or(0) {
let ni = n - Self::from_positive_int(i);
let ki = Self::from_positive_int(i + 1);
result *= ni / ki;
}
result
}
#[must_use]
fn from_positive_int(n: usize) -> Self {
Self::try_cast(n).unwrap_or(Self::infinity())
}
}
impl<T> Value for T where
T: nalgebra::Scalar
+ nalgebra::ComplexField<RealField = Self>
+ nalgebra::RealField
+ num_traits::float::FloatCore
+ std::fmt::LowerExp
{
}
pub struct SteppedValues<T: Value> {
range: RangeInclusive<T>,
step: T,
index: T,
}
impl<T: Value> SteppedValues<T> {
pub fn new(range: RangeInclusive<T>, step: T) -> Self {
Self {
range,
step,
index: T::zero(),
}
}
pub fn new_unit(range: RangeInclusive<T>) -> Self {
Self::new(range, T::one())
}
pub fn len(&self) -> usize {
let value = *self.range.start() + self.index * self.step;
let remaining = *self.range.end() - value;
let steps = remaining / self.step;
steps.as_usize().unwrap_or(0)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<T: Value> Iterator for SteppedValues<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let value = *self.range.start() + self.index * self.step;
if value <= *self.range.end() {
self.index += T::one();
Some(value)
} else {
None
}
}
}
pub trait CoordExt<T: Value> {
fn x_iter(&self) -> impl Iterator<Item = T>;
fn y_iter(&self) -> impl Iterator<Item = T>;
fn y_clipped(&self, range: &Range<T>) -> Vec<(T, T)>;
fn x(&self) -> Vec<T> {
self.x_iter().collect()
}
fn y(&self) -> Vec<T> {
self.y_iter().collect()
}
fn x_range(&self) -> Option<RangeInclusive<T>> {
let x_min = self.x_iter().fold(None, |acc: Option<(T, T)>, x| {
Some(match acc {
Some((min, max)) => (
nalgebra::RealField::min(min, x),
nalgebra::RealField::max(max, x),
),
None => (x, x),
})
});
x_min.map(|(start, end)| start..=end)
}
fn y_range(&self) -> Option<RangeInclusive<T>> {
let y_min = self.y_iter().fold(None, |acc: Option<(T, T)>, y| {
Some(match acc {
Some((min, max)) => (
nalgebra::RealField::min(min, y),
nalgebra::RealField::max(max, y),
),
None => (y, y),
})
});
y_min.map(|(start, end)| start..=end)
}
fn as_f64(&self) -> crate::error::Result<Vec<(f64, f64)>> {
self.x_iter()
.zip(self.y_iter())
.map(|(x, y)| {
let x_f64 = f64::try_cast(x)?;
let y_f64 = f64::try_cast(y)?;
Ok((x_f64, y_f64))
})
.collect()
}
}
impl<T: Value> CoordExt<T> for Vec<(T, T)> {
fn x_iter(&self) -> impl Iterator<Item = T> {
self.iter().map(|(x, _)| *x)
}
fn y_iter(&self) -> impl Iterator<Item = T> {
self.iter().map(|(_, y)| *y)
}
fn y_clipped(&self, range: &Range<T>) -> Vec<(T, T)> {
self.iter()
.map(|(x, y)| (*x, nalgebra::RealField::clamp(*y, range.start, range.end)))
.collect()
}
}
impl<T: Value> CoordExt<T> for &[(T, T)] {
fn x_iter(&self) -> impl Iterator<Item = T> {
self.iter().map(|(x, _)| *x)
}
fn y_iter(&self) -> impl Iterator<Item = T> {
self.iter().map(|(_, y)| *y)
}
fn y_clipped(&self, range: &Range<T>) -> Vec<(T, T)> {
self.iter()
.map(|(x, y)| (*x, nalgebra::RealField::clamp(*y, range.start, range.end)))
.collect()
}
}
impl<T: Value> CoordExt<T> for std::borrow::Cow<'_, [(T, T)]> {
fn x_iter(&self) -> impl Iterator<Item = T> {
self.iter().map(|(x, _)| *x)
}
fn y_iter(&self) -> impl Iterator<Item = T> {
self.iter().map(|(_, y)| *y)
}
fn y_clipped(&self, range: &Range<T>) -> Vec<(T, T)> {
self.iter()
.map(|(x, y)| (*x, nalgebra::RealField::clamp(*y, range.start, range.end)))
.collect()
}
}
pub trait IntClampedCast:
num_traits::Num + num_traits::NumCast + num_traits::Bounded + Copy + PartialOrd + Ord
{
fn clamped_cast<T: num_traits::PrimInt>(self) -> T {
if let Some(v) = num_traits::cast(self) {
return v;
}
let min = match num_traits::cast::<T, Self>(T::min_value()) {
Some(v) => v, None => Self::min_value(), };
let max = match num_traits::cast::<T, Self>(T::max_value()) {
Some(v) => v, None => Self::max_value(), };
let clamped = self.clamp(min, max);
num_traits::cast(clamped).expect("clamped value should be in range")
}
}
impl<T: num_traits::PrimInt> IntClampedCast for T {}
pub trait FloatClampedCast:
num_traits::Num + num_traits::NumCast + Copy + PartialOrd + num_traits::float::FloatCore
{
fn clamped_cast<T: num_traits::float::FloatCore>(self) -> T {
if let Some(v) = num_traits::cast(self) {
return v;
}
let min = match num_traits::cast::<T, Self>(T::min_value()) {
Some(v) => v, None => Self::min_value(), };
let max = match num_traits::cast::<T, Self>(T::max_value()) {
Some(v) => v, None => Self::max_value(), };
let clamped = self.clamp(min, max);
num_traits::cast(clamped).expect("clamped value should be in range")
}
}
impl<T: num_traits::float::FloatCore> FloatClampedCast for T {}
pub(crate) fn bisect<B, T>(f: &B, mut a: T, mut b: T, mut fa: T, mut fb: T, steps: usize) -> (T, T)
where
B: Fn(T) -> T,
T: Value,
{
for _ in 0..steps {
let m = (a + b) / T::two();
let fm = f(m);
if (fa * fm).is_sign_negative() {
b = m;
fb = fm;
} else {
a = m;
fa = fm;
}
}
((a + b) / T::two(), (fa + fb) / T::two())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_value_range() {
let range = SteppedValues::new(0.0..=1.0, 0.1);
let values: Vec<_> = range.collect();
assert_eq!(values.len(), 11);
}
#[test]
fn clamped_cast_edge_cases() {
assert_eq!(0i8.clamped_cast::<i8>(), 0);
assert_eq!(127i8.clamped_cast::<i8>(), 127);
assert_eq!((-128i8).clamped_cast::<i8>(), -128);
assert_eq!(0i8.clamped_cast::<u8>(), 0);
assert_eq!(127i8.clamped_cast::<u8>(), 127);
assert_eq!((-1i8).clamped_cast::<u8>(), 0);
assert_eq!((-128i8).clamped_cast::<u8>(), 0);
assert_eq!(0u8.clamped_cast::<i8>(), 0);
assert_eq!(127u8.clamped_cast::<i8>(), 127);
assert_eq!(128u8.clamped_cast::<i8>(), 127);
assert_eq!(255u8.clamped_cast::<i8>(), 127);
assert_eq!(0i16.clamped_cast::<i8>(), 0);
assert_eq!(127i16.clamped_cast::<i8>(), 127);
assert_eq!(128i16.clamped_cast::<i8>(), 127);
assert_eq!((-1i16).clamped_cast::<i8>(), -1);
assert_eq!((-128i16).clamped_cast::<i8>(), -128);
assert_eq!((-129i16).clamped_cast::<i8>(), -128);
assert_eq!(32767i16.clamped_cast::<i8>(), 127);
assert_eq!((-32768i16).clamped_cast::<i8>(), -128);
assert_eq!(0i16.clamped_cast::<u8>(), 0);
assert_eq!(255i16.clamped_cast::<u8>(), 255);
assert_eq!(256i16.clamped_cast::<u8>(), 255);
assert_eq!((-1i16).clamped_cast::<u8>(), 0);
assert_eq!((-32768i16).clamped_cast::<u8>(), 0);
assert_eq!(0u16.clamped_cast::<i8>(), 0);
assert_eq!(127u16.clamped_cast::<i8>(), 127);
assert_eq!(128u16.clamped_cast::<i8>(), 127);
assert_eq!(255u16.clamped_cast::<i8>(), 127);
assert_eq!(65535u16.clamped_cast::<i8>(), 127);
assert_eq!(0i32.clamped_cast::<i16>(), 0);
assert_eq!(32767i32.clamped_cast::<i16>(), 32767);
assert_eq!(32768i32.clamped_cast::<i16>(), 32767);
assert_eq!((-32768i32).clamped_cast::<i16>(), -32768);
assert_eq!((-32769i32).clamped_cast::<i16>(), -32768);
assert_eq!(0i32.clamped_cast::<u16>(), 0);
assert_eq!(65535i32.clamped_cast::<u16>(), 65535);
assert_eq!(65536i32.clamped_cast::<u16>(), 65535);
assert_eq!((-1i32).clamped_cast::<u16>(), 0);
assert_eq!((-32768i32).clamped_cast::<u16>(), 0);
assert_eq!(0u32.clamped_cast::<i16>(), 0);
assert_eq!(32767u32.clamped_cast::<i16>(), 32767);
assert_eq!(32768u32.clamped_cast::<i16>(), 32767);
assert_eq!(65535u32.clamped_cast::<i16>(), 32767);
assert_eq!(u32::MAX.clamped_cast::<i16>(), 32767);
assert_eq!(0u32.clamped_cast::<u16>(), 0);
assert_eq!(65535u32.clamped_cast::<u16>(), 65535);
assert_eq!(65536u32.clamped_cast::<u16>(), 65535);
assert_eq!(u32::MAX.clamped_cast::<u16>(), 65535);
assert_eq!(i64::MIN.clamped_cast::<i8>(), -128);
assert_eq!(i64::MAX.clamped_cast::<i8>(), 127);
assert_eq!((-129i64).clamped_cast::<i8>(), -128);
assert_eq!(128i64.clamped_cast::<i8>(), 127);
assert_eq!(0u64.clamped_cast::<i8>(), 0);
assert_eq!(255u64.clamped_cast::<i8>(), 127);
assert_eq!(u64::MAX.clamped_cast::<i8>(), 127);
assert_eq!(0i128.clamped_cast::<u8>(), 0);
assert_eq!(255i128.clamped_cast::<u8>(), 255);
assert_eq!(256i128.clamped_cast::<u8>(), 255);
assert_eq!((-1i128).clamped_cast::<u8>(), 0);
assert_eq!(i128::MIN.clamped_cast::<u8>(), 0);
assert_eq!(0u128.clamped_cast::<i8>(), 0);
assert_eq!(127u128.clamped_cast::<i8>(), 127);
assert_eq!(128u128.clamped_cast::<i8>(), 127);
assert_eq!(u128::MAX.clamped_cast::<i8>(), 127);
}
}