use crate::{Native, float::{FUSED, sealed::Sealed}};
use num_complex::Complex;
use num_traits::{One, Zero};
use std::ops::{Add, Mul, Neg, Sub};
pub trait Scalar:
Sealed + Copy + PartialEq + Zero + One + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> + Neg<Output = Self> + Send + Sync
{
type Real: Native;
const COMPLEX: bool;
fn conj(self) -> Self;
fn re(self) -> Self::Real;
fn im(self) -> Self::Real;
fn from_real(x: Self::Real) -> Self;
fn abs1(self) -> Self::Real;
fn modulus(self) -> Self::Real;
fn mul_real(self, x: Self::Real) -> Self;
fn div_real(self, x: Self::Real) -> Self;
fn mul_acc(self, b: Self, c: Self) -> Self;
fn reciprocal(self) -> Self;
fn quotient(self, d: Self) -> Self;
}
impl<T: Native> Scalar for T {
type Real = T;
const COMPLEX: bool = false;
#[inline(always)]
fn conj(self) -> T { self }
#[inline(always)]
fn re(self) -> T { self }
#[inline(always)]
fn im(self) -> T { T::zero() }
#[inline(always)]
fn from_real(x: T) -> T { x }
#[inline(always)]
fn abs1(self) -> T { self.abs() }
#[inline(always)]
fn modulus(self) -> T { self.abs() }
#[inline(always)]
fn mul_real(self, x: T) -> T { self * x }
#[inline(always)]
fn div_real(self, x: T) -> T { self / x }
#[inline(always)]
fn mul_acc(self, b: T, c: T) -> T { self.mla::<FUSED>(b, c) }
#[inline(always)]
fn reciprocal(self) -> T { self.recip() }
#[inline(always)]
fn quotient(self, d: T) -> T { self / d }
}
impl<T: Native> Scalar for Complex<T> {
type Real = T;
const COMPLEX: bool = true;
#[inline(always)]
fn conj(self) -> Self { Complex::new(self.re, -self.im) }
#[inline(always)]
fn re(self) -> T { self.re }
#[inline(always)]
fn im(self) -> T { self.im }
#[inline(always)]
fn from_real(x: T) -> Self { Complex::new(x, T::zero()) }
#[inline(always)]
fn abs1(self) -> T { self.re.abs() + self.im.abs() }
#[inline(always)]
fn modulus(self) -> T { crate::complex::modulus::<T, FUSED>(self.re, self.im) }
#[inline(always)]
fn mul_real(self, x: T) -> Self { Complex::new(self.re * x, self.im * x) }
#[inline(always)]
fn div_real(self, x: T) -> Self { Complex::new(self.re / x, self.im / x) }
#[inline(always)]
fn mul_acc(self, b: Self, c: Self) -> Self {
let re = self.re.mla::<FUSED>(b.re, (-self.im).mla::<FUSED>(b.im, c.re));
Complex::new(re, self.re.mla::<FUSED>(b.im, self.im.mla::<FUSED>(b.re, c.im)))
}
#[inline(always)]
fn reciprocal(self) -> Self { Self::one().quotient(self) }
#[inline(always)]
fn quotient(self, d: Self) -> Self {
let (two, eps) = (T::one() + T::one(), T::epsilon());
let (big, small, up) = (T::max_value() / two, T::min_positive_value() * two / eps, two / (eps * eps));
let size = |z: Self| z.re.abs().max(z.im.abs());
let (xs, ys) = (size(self), size(d));
let (mut x, mut y, mut scale) = (self, d, T::one());
if xs >= big { (x, scale) = (x.div_real(two), scale * two) }
if ys >= big { (y, scale) = (y.div_real(two), scale / two) }
if xs <= small { (x, scale) = (x.mul_real(up), scale / up) }
if ys <= small { (y, scale) = (y.mul_real(up), scale * up) }
let smith = |a: T, b: T, c: T, d: T| {
let r = d / c;
let s = c + d * r;
if r != T::zero() { ((a + b * r) / s, (b - a * r) / s) } else { ((a + d * (b / c)) / s, (b - d * (a / c)) / s) }
};
let (re, im) = if y.re.abs() >= y.im.abs() { smith(x.re, x.im, y.re, y.im) } else { let (re, im) = smith(x.im, x.re, y.im, y.re); (re, -im) };
Complex::new(re, im).mul_real(scale)
}
}