use crate::algebra::*;
use crate::analysis::*;
pub trait Trig: UnitalRing + Divisibility {
fn sin(self) -> Self;
fn cos(self) -> Self;
fn tan(self) -> Self;
#[inline] fn sin_cos(self) -> (Self, Self) {(self.clone().sin(), self.cos())}
fn sinh(self) -> Self;
fn cosh(self) -> Self;
fn tanh(self) -> Self;
fn try_asin(self) -> Option<Self>;
fn try_acos(self) -> Option<Self>;
#[inline] fn asin(self) -> Self {self.try_asin().unwrap()}
#[inline] fn acos(self) -> Self {self.try_acos().unwrap()}
fn atan(self) -> Self;
fn atan2(y: Self, x: Self) -> Self;
fn try_asinh(self) -> Option<Self>;
fn try_acosh(self) -> Option<Self>;
fn try_atanh(self) -> Option<Self>;
#[inline] fn asinh(self) -> Self {self.try_asinh().unwrap()}
#[inline] fn acosh(self) -> Self {self.try_acosh().unwrap()}
#[inline] fn atanh(self) -> Self {self.try_atanh().unwrap()}
fn pi() -> Self;
#[inline] fn frac_2_pi() -> Self {Self::one().mul_n(2u32).divide(Self::pi()).unwrap()}
#[inline] fn frac_pi_2() -> Self {Self::pi().divide(Self::one().mul_n(2u32)).unwrap()}
#[inline] fn frac_pi_3() -> Self {Self::pi().divide(Self::one().mul_n(3u32)).unwrap()}
#[inline] fn frac_pi_4() -> Self {Self::pi().divide(Self::one().mul_n(4u32)).unwrap()}
#[inline] fn frac_pi_6() -> Self {Self::pi().divide(Self::one().mul_n(6u32)).unwrap()}
#[inline] fn frac_pi_8() -> Self {Self::pi().divide(Self::one().mul_n(8u32)).unwrap()}
#[inline] fn pythag_const() -> Self {Self::one().mul_n(2u32) * Self::pythag_const_inv()}
#[inline] fn pythag_const_inv() -> Self {Self::frac_pi_4().sin()}
#[inline] fn to_degrees(self) -> Self {self * (Self::one().mul_n(180u32).divide(Self::pi()).unwrap())}
#[inline] fn to_radians(self) -> Self {self * (Self::pi().divide(Self::one().mul_n(180u32)).unwrap())}
}
pub use crate::algebra::Exponential;
pub trait RealExponential: Exponential + UnitalRing + Divisibility {
#[inline] fn try_pow(self, power:Self) -> Option<Self> { self.try_ln().map(move |x| (x * power).exp()) }
#[inline] fn try_root(self, index:Self) -> Option<Self> { index.inverse().and_then(move |x| self.try_pow(x)) }
#[inline] fn try_log(self, base: Self) -> Option<Self> {
self.try_ln().and_then(move |x| base.try_ln().and_then(move |y| x.divide(y)))
}
#[inline] fn ln(self) -> Self {self.try_ln().unwrap()}
#[inline] fn log(self, base: Self) -> Self {self.try_log(base).unwrap()}
#[inline] fn pow(self, p: Self) -> Self {self.try_pow(p).unwrap()}
#[inline] fn root(self, r: Self) -> Self {self.try_root(r).unwrap()}
#[inline] fn exp2(self) -> Self {self.pow(Self::one().mul_n(2u32))}
#[inline] fn exp10(self) -> Self { self.pow(Self::one().mul_n(10u32)) }
#[inline] fn log2(self) -> Self {self.log(Self::one().mul_n(2u32))}
#[inline] fn log10(self) -> Self { self.log(Self::one().mul_n(10u32)) }
#[inline] fn sqrt(self) -> Self {self.root(Self::one().mul_n(2u32))}
#[inline] fn cbrt(self) -> Self {self.root(Self::one().mul_n(3u32))}
#[inline] fn ln_1p(self) -> Self {(self-Self::one()).ln()}
#[inline] fn exp_m1(self) -> Self {self.exp()-Self::one()}
#[inline] fn e() -> Self {Self::one().exp()}
#[inline] fn ln_2() -> Self {Self::one().mul_n(2u32).ln()}
#[inline] fn ln_10() -> Self {Self::one().mul_n(10u32).ln()}
#[inline] fn log2_e() -> Self {Self::ln_2().inverse().unwrap()}
#[inline] fn log10_e() -> Self {Self::ln_10().inverse().unwrap()}
#[inline] fn log2_10() -> Self {Self::ln_10().divide(Self::ln_2()).unwrap()}
#[inline] fn log10_2() -> Self {Self::ln_2().divide(Self::ln_10()).unwrap()}
#[inline] fn sqrt_2() -> Self {Self::one().mul_n(2u32).sqrt()}
#[inline] fn frac_1_sqrt_2() -> Self {Self::sqrt_2().inverse().unwrap()}
}
pub trait ComplexSubset: PartialEq + Clone + Semiring {
type Real: Real
+ ComplexSubset<Natural = Self::Natural, Integer = Self::Integer, Real = Self::Real>;
type Natural: Natural
+ IntegerSubset<Signed = Self::Integer, Unsigned = Self::Natural>
+ ComplexSubset<Natural = Self::Natural, Integer = Self::Integer, Real = Self::Real>;
type Integer: Integer
+ IntegerSubset<Signed = Self::Integer, Unsigned = Self::Natural>
+ ComplexSubset<Natural = Self::Natural, Integer = Self::Integer, Real = Self::Real>;
fn as_real(self) -> Self::Real;
fn as_natural(self) -> Self::Natural;
fn as_integer(self) -> Self::Integer;
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn round(self) -> Self;
fn trunc(self) -> Self;
fn fract(self) -> Self;
fn im(self) -> Self;
fn re(self) -> Self;
fn conj(self) -> Self;
#[inline] fn modulus_sqrd(self) -> Self { self.clone() * self.conj()}
#[inline] fn modulus(self) -> Self::Real { (self.clone() * self.conj()).as_real().sqrt()}
}
pub trait ComplexSemiring = CommutativeSemiring + ComplexSubset;
pub trait ComplexRing = CommutativeRing + ComplexSubset;
pub trait ComplexField = Field + ComplexSubset;
pub trait Real: ArchField + ComplexSubset<Real=Self> + Trig + RealExponential {
fn approx(self) -> f64;
fn repr(f: f64) -> Self;
}
pub trait Complex: ComplexField + Trig + RealExponential + From<<Self as ComplexSubset>::Real> {
fn i() -> Self;
fn mul_i(self) -> Self;
fn div_i(self) -> Self;
}
#[cfg(feature = "std")]
macro_rules! float_to_option {
($expr:expr) => {
{
let result = $expr;
if result.is_infinite() || result.is_nan() {
None
} else {
Some(result)
}
}
}
}
#[cfg(feature = "std")]
macro_rules! impl_real {
($($f:ident:$n:ident:$z:ident)*) => {$(
impl Trig for $f {
#[inline(always)] fn sin(self) -> Self {self.sin()}
#[inline(always)] fn cos(self) -> Self {self.cos()}
#[inline(always)] fn tan(self) -> Self {self.tan()}
#[inline(always)] fn sin_cos(self) -> (Self,Self) {self.sin_cos()}
#[inline(always)] fn sinh(self) -> Self {self.sinh()}
#[inline(always)] fn cosh(self) -> Self {self.cosh()}
#[inline(always)] fn tanh(self) -> Self {self.tanh()}
#[inline] fn try_asin(self) -> Option<Self> {float_to_option!(self.asin())}
#[inline] fn try_acos(self) -> Option<Self> {float_to_option!(self.acos())}
#[inline(always)] fn asin(self) -> Self {self.asin()}
#[inline(always)] fn acos(self) -> Self {self.acos()}
#[inline(always)] fn atan(self) -> Self {self.atan()}
#[inline(always)] fn atan2(y:Self, x:Self) -> Self {$f::atan2(y,x)}
#[inline] fn try_asinh(self) -> Option<Self> {float_to_option!(self.asinh())}
#[inline] fn try_acosh(self) -> Option<Self> {float_to_option!(self.acosh())}
#[inline] fn try_atanh(self) -> Option<Self> {float_to_option!(self.atanh())}
#[inline(always)] fn asinh(self) -> Self {self.asinh()}
#[inline(always)] fn acosh(self) -> Self {self.acosh()}
#[inline(always)] fn atanh(self) -> Self {self.atanh()}
#[inline(always)] fn pi() -> Self {::core::$f::consts::PI}
#[inline(always)] fn frac_2_pi() -> Self {::core::$f::consts::FRAC_2_PI}
#[inline(always)] fn frac_pi_2() -> Self {::core::$f::consts::FRAC_PI_2}
#[inline(always)] fn frac_pi_3() -> Self {::core::$f::consts::FRAC_PI_3}
#[inline(always)] fn frac_pi_4() -> Self {::core::$f::consts::FRAC_PI_4}
#[inline(always)] fn frac_pi_6() -> Self {::core::$f::consts::FRAC_PI_6}
#[inline(always)] fn frac_pi_8() -> Self {::core::$f::consts::FRAC_PI_8}
#[inline(always)] fn pythag_const() -> Self {::core::$f::consts::SQRT_2}
#[inline(always)] fn pythag_const_inv() -> Self {::core::$f::consts::FRAC_1_SQRT_2}
#[inline(always)] fn to_degrees(self) -> Self { self.to_degrees() }
#[inline(always)] fn to_radians(self) -> Self { self.to_radians() }
}
impl Exponential for $f {
#[inline(always)] fn exp(self) -> Self {self.exp()}
#[inline] fn try_ln(self) -> Option<Self> { float_to_option!(self.ln()) }
}
impl RealExponential for $f {
#[inline] fn try_pow(self, power:Self) -> Option<Self> { float_to_option!(self.pow(power)) }
#[inline] fn try_root(self, index:Self) -> Option<Self> { float_to_option!(self.root(index)) }
#[inline] fn try_log(self, base: Self) -> Option<Self> { float_to_option!(self.log(base)) }
#[inline(always)] fn pow(self, power:Self) -> Self { self.powf(power)}
#[inline(always)] fn exp2(self) -> Self {self.exp2()}
#[inline(always)] fn exp10(self) -> Self {$f::from(10.0).pow(self)}
#[inline(always)] fn log(self, base:Self) -> Self {self.log(base)}
#[inline(always)] fn ln(self) -> Self {self.ln()}
#[inline(always)] fn log2(self) -> Self {self.log2()}
#[inline(always)] fn log10(self) -> Self {self.log10()}
#[inline(always)] fn root(self, index:Self) -> Self {self.pow(index.recip())}
#[inline(always)] fn sqrt(self) -> Self {self.sqrt()}
#[inline(always)] fn cbrt(self) -> Self {self.cbrt()}
#[inline(always)] fn ln_1p(self) -> Self {self.ln_1p()}
#[inline(always)] fn exp_m1(self) -> Self {self.exp_m1()}
#[inline(always)] fn e() -> Self {::core::$f::consts::E}
#[inline(always)] fn ln_2() -> Self {::core::$f::consts::LN_2}
#[inline(always)] fn ln_10() -> Self {::core::$f::consts::LN_10}
#[inline(always)] fn log2_e() -> Self {::core::$f::consts::LOG2_E}
#[inline(always)] fn log10_e() -> Self {::core::$f::consts::LOG10_E}
#[inline(always)] fn log2_10() -> Self {::core::$f::consts::LOG2_10}
#[inline(always)] fn log10_2() -> Self {::core::$f::consts::LOG10_2}
#[inline(always)] fn sqrt_2() -> Self {::core::$f::consts::SQRT_2}
#[inline(always)] fn frac_1_sqrt_2() -> Self {::core::$f::consts::FRAC_1_SQRT_2}
}
impl ComplexSubset for $f {
type Real = $f;
type Natural = $n;
type Integer = $z;
#[inline(always)] fn as_real(self) -> Self::Real {self}
#[inline(always)] fn as_natural(self) -> Self::Natural {self as $n}
#[inline(always)] fn as_integer(self) -> Self::Integer {self as $z}
#[inline(always)] fn floor(self) -> Self { self.floor() }
#[inline(always)] fn ceil(self) -> Self {self.ceil()}
#[inline(always)] fn round(self) -> Self {self.round()}
#[inline(always)] fn trunc(self) -> Self {self.trunc()}
#[inline(always)] fn fract(self) -> Self {self.fract()}
#[inline(always)] fn im(self) -> Self {self}
#[inline(always)] fn re(self) -> Self {self}
#[inline(always)] fn conj(self) -> Self {self}
#[inline(always)] fn modulus_sqrd(self) -> Self { self * self }
#[inline(always)] fn modulus(self) -> Self::Real { self.abs() }
}
impl ComplexSubset for $n {
type Real = $f;
type Natural = $n;
type Integer = $z;
#[inline(always)] fn as_real(self) -> Self::Real {self as $f}
#[inline(always)] fn as_natural(self) -> Self::Natural {self}
#[inline(always)] fn as_integer(self) -> Self::Integer {self as $z}
#[inline(always)] fn floor(self) -> Self {self}
#[inline(always)] fn ceil(self) -> Self {self}
#[inline(always)] fn round(self) -> Self {self}
#[inline(always)] fn trunc(self) -> Self {self}
#[inline(always)] fn fract(self) -> Self {0}
#[inline(always)] fn im(self) -> Self {self}
#[inline(always)] fn re(self) -> Self {self}
#[inline(always)] fn conj(self) -> Self {self}
#[inline(always)] fn modulus_sqrd(self) -> Self { self * self }
#[inline(always)] fn modulus(self) -> Self::Real { self as $f }
}
impl ComplexSubset for $z {
type Real = $f;
type Natural = $n;
type Integer = $z;
#[inline(always)] fn as_real(self) -> Self::Real {self as $f}
#[inline(always)] fn as_natural(self) -> Self::Natural {self as $n}
#[inline(always)] fn as_integer(self) -> Self::Integer {self}
#[inline(always)] fn floor(self) -> Self {self}
#[inline(always)] fn ceil(self) -> Self {self}
#[inline(always)] fn round(self) -> Self {self}
#[inline(always)] fn trunc(self) -> Self {self}
#[inline(always)] fn fract(self) -> Self {0}
#[inline(always)] fn im(self) -> Self {self}
#[inline(always)] fn re(self) -> Self {self}
#[inline(always)] fn conj(self) -> Self {self}
#[inline(always)] fn modulus_sqrd(self) -> Self { self * self }
#[inline(always)] fn modulus(self) -> Self::Real { self.abs() as $f }
}
impl Real for $f {
#[inline(always)] fn approx(self) -> f64 {self as f64}
#[inline(always)] fn repr(f: f64) -> Self {f as $f}
}
)*}
}
#[cfg(feature = "std")] mod impls {
use super::{ Trig, Exponential, RealExponential, ComplexSubset, Real };
impl_real!(f32:u32:i32 f64:u64:i64);
}
macro_rules! int_exp {
($($t:ident)*) => {
$(
impl Exponential for $t {
#[inline] fn exp(self) -> Self { if self.even() {1} else {-1} }
#[inline] fn try_ln(self) -> Option<Self> {
match self {
1 => Some(0),
-1 => Some(1),
_ => None
}
}
}
)*
}
}
int_exp!(i8 i16 i32 i64 isize i128);