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}