Skip to main content

oxiblas_core/scalar/
traits.rs

1//! Core scalar trait definitions: Scalar, Real, ComplexScalar, and Field.
2
3use core::fmt::{Debug, Display};
4use core::iter::Sum;
5use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
6use num_traits::{FromPrimitive, NumAssign, One, Zero};
7
8/// Base trait for all scalar types used in OxiBLAS.
9///
10/// This trait provides the fundamental requirements for any numeric type
11/// that can be used in matrix operations.
12pub trait Scalar:
13    Copy
14    + Clone
15    + Debug
16    + Display
17    + Default
18    + Send
19    + Sync
20    + PartialEq
21    + Zero
22    + One
23    + Add<Output = Self>
24    + Sub<Output = Self>
25    + Mul<Output = Self>
26    + Div<Output = Self>
27    + AddAssign
28    + SubAssign
29    + MulAssign
30    + DivAssign
31    + Neg<Output = Self>
32    + Sum
33    + NumAssign
34    + FromPrimitive
35    + 'static
36{
37    /// The real component type (for complex numbers, this is the component type).
38    type Real: Real;
39
40    /// Returns the absolute value (modulus for complex numbers).
41    fn abs(self) -> Self::Real;
42
43    /// Returns the complex conjugate. For real numbers, returns self.
44    fn conj(self) -> Self;
45
46    /// Returns true if this is a real type (not complex).
47    fn is_real() -> bool;
48
49    /// Returns the real part.
50    fn real(self) -> Self::Real;
51
52    /// Returns the imaginary part (zero for real types).
53    fn imag(self) -> Self::Real;
54
55    /// Creates a scalar from real and imaginary parts.
56    fn from_real_imag(re: Self::Real, im: Self::Real) -> Self;
57
58    /// Creates a scalar from just the real part (imaginary = 0).
59    fn from_real(re: Self::Real) -> Self {
60        Self::from_real_imag(re, Self::Real::zero())
61    }
62
63    /// Square of the absolute value (more efficient than abs().powi(2)).
64    fn abs_sq(self) -> Self::Real {
65        let re = self.real();
66        let im = self.imag();
67        re * re + im * im
68    }
69
70    /// Machine epsilon for this type.
71    fn epsilon() -> Self::Real;
72
73    /// Smallest positive normal value.
74    fn min_positive() -> Self::Real;
75
76    /// Largest finite value.
77    fn max_value() -> Self::Real;
78
79    /// Size of the type in bytes.
80    const SIZE: usize = core::mem::size_of::<Self>();
81
82    /// Alignment requirement.
83    const ALIGN: usize = core::mem::align_of::<Self>();
84}
85
86/// Trait for real number types (f32, f64).
87pub trait Real: Scalar<Real = Self> + num_traits::Float + PartialOrd {
88    /// Square root.
89    fn sqrt(self) -> Self;
90
91    /// Natural logarithm.
92    fn ln(self) -> Self;
93
94    /// Exponential function.
95    fn exp(self) -> Self;
96
97    /// Sine.
98    fn sin(self) -> Self;
99
100    /// Cosine.
101    fn cos(self) -> Self;
102
103    /// Arctangent of y/x with correct quadrant.
104    fn atan2(self, other: Self) -> Self;
105
106    /// Power function.
107    fn powf(self, n: Self) -> Self;
108
109    /// Sign function, matching `f32::signum`/`f64::signum` (IEEE-754) exactly:
110    /// `1.0` if the value is positive, `+0.0`, or `+INFINITY`; `-1.0` if the
111    /// value is negative, `-0.0`, or `-INFINITY`; `NaN` if the value is `NaN`.
112    ///
113    /// Note this is *not* the mathematical sign function (which would map
114    /// zero to zero) — it always returns a value with magnitude 1.0 for
115    /// finite/infinite non-NaN inputs, preserving the sign bit of zero.
116    /// Every implementation of `Real::signum` in this crate MUST honor
117    /// these exact semantics for consistency across scalar types.
118    fn signum(self) -> Self;
119
120    /// Fused multiply-add: self * a + b
121    fn mul_add(self, a: Self, b: Self) -> Self;
122
123    /// Floor function.
124    fn floor(self) -> Self;
125
126    /// Ceiling function.
127    fn ceil(self) -> Self;
128
129    /// Round to nearest integer.
130    fn round(self) -> Self;
131
132    /// Truncate toward zero.
133    fn trunc(self) -> Self;
134
135    /// Safe reciprocal (returns None if self is zero or would overflow).
136    fn safe_recip(self) -> Option<Self> {
137        if Scalar::abs(self) < Self::min_positive() {
138            None
139        } else {
140            Some(Self::one() / self)
141        }
142    }
143
144    /// Hypot: sqrt(self^2 + other^2) computed without overflow.
145    fn hypot(self, other: Self) -> Self;
146}
147
148/// Trait for complex scalar types.
149pub trait ComplexScalar: Scalar {
150    /// Creates a complex number from real and imaginary parts.
151    fn new(re: Self::Real, im: Self::Real) -> Self;
152
153    /// Returns the argument (phase angle) of the complex number.
154    fn arg(self) -> Self::Real;
155
156    /// Returns the polar form (r, theta) where self = r * e^(i*theta).
157    fn to_polar(self) -> (Self::Real, Self::Real) {
158        (self.abs(), self.arg())
159    }
160
161    /// Creates a complex number from polar form.
162    fn from_polar(r: Self::Real, theta: Self::Real) -> Self;
163
164    /// Complex exponential.
165    fn cexp(self) -> Self;
166
167    /// Complex logarithm (principal branch).
168    fn cln(self) -> Self;
169
170    /// Complex square root (principal branch).
171    fn csqrt(self) -> Self;
172}
173
174/// Field trait - complete algebraic structure with all operations.
175///
176/// This is the main trait used throughout OxiBLAS for generic programming
177/// over numeric types.
178pub trait Field: Scalar {
179    /// Computes self * alpha + other * beta
180    #[inline]
181    fn scale_add(self, alpha: Self, other: Self, beta: Self) -> Self {
182        self * alpha + other * beta
183    }
184
185    /// Computes self * conj(other) for complex, self * other for real.
186    fn mul_conj(self, other: Self) -> Self;
187
188    /// Computes conj(self) * other for complex, self * other for real.
189    fn conj_mul(self, other: Self) -> Self;
190
191    /// Reciprocal (1/self).
192    fn recip(self) -> Self;
193
194    /// Integer power.
195    fn powi(self, n: i32) -> Self;
196}