scirs2_core/
numeric.rs

1//! Numeric traits and utilities for SciRS2
2//!
3//! This module provides unified access to numeric traits and complex numbers.
4//!
5//! # SciRS2 POLICY Compliance
6//!
7//! This is the **only** module in the SciRS2 ecosystem that should directly
8//! import external numeric libraries. All other crates must use this module.
9//!
10//! # Re-exports
11//!
12//! - `num_traits`: All numeric traits (Float, Zero, One, etc.)
13//! - `num_complex`: Complex number types
14//! - `num_integer`: Integer-specific functions (gcd, lcm, etc.)
15
16use crate::error::{CoreError, CoreResult, ErrorContext};
17use std::fmt::Debug;
18use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
19
20// ============================================================================
21// Complete Re-exports for SciRS2 POLICY Compliance
22// ============================================================================
23
24/// Complete re-export of num-traits for SciRS2 ecosystem
25pub use num_traits::{
26    self,
27    bounds::Bounded,
28    cast::{AsPrimitive, FromPrimitive, NumCast, ToPrimitive},
29    float::{Float, FloatConst},
30    identities::{One, Zero},
31    int::PrimInt,
32    ops::{
33        checked::*,
34        inv::Inv,
35        mul_add::{MulAdd, MulAddAssign},
36        saturating::*,
37        wrapping::*,
38    },
39    pow::{checked_pow, Pow},
40    real::Real,
41    sign::{Signed, Unsigned},
42    Num, NumAssign, NumAssignOps, NumAssignRef, NumOps, NumRef,
43};
44
45/// Complete re-export of num-complex for SciRS2 ecosystem
46pub use num_complex::{self, Complex, Complex32, Complex64, ComplexFloat};
47
48/// Complete re-export of num-integer for SciRS2 ecosystem
49pub use num_integer::{
50    self, div_ceil, div_floor, div_mod_floor, gcd, gcd_lcm, lcm, Average, ExtendedGcd, Integer,
51    Roots,
52};
53
54// ============================================================================
55// SciRS2 Custom Traits and Utilities
56// ============================================================================
57
58/// A trait for numeric types that can be used in scientific calculations
59///
60/// This trait combines common numeric traits required for scientific computing
61/// operations, providing a unified trait bound for generic code.
62pub trait ScientificNumber:
63    Num
64    + Clone
65    + Copy
66    + PartialOrd
67    + Debug
68    + Zero
69    + One
70    + Add<Output = Self>
71    + Sub<Output = Self>
72    + Mul<Output = Self>
73    + Div<Output = Self>
74    + AddAssign
75    + SubAssign
76    + MulAssign
77    + DivAssign
78    + NumCast
79{
80    /// Absolute value
81    #[must_use]
82    fn abs(self) -> Self;
83
84    /// Square root
85    #[must_use]
86    fn sqrt(self) -> Self;
87
88    /// Square
89    #[must_use]
90    fn square(self) -> Self {
91        self * self
92    }
93
94    /// Maximum of two values
95    #[must_use]
96    fn max(self, other: Self) -> Self;
97
98    /// Minimum of two values
99    #[must_use]
100    fn min(self, other: Self) -> Self;
101
102    /// Check if the value is finite
103    #[must_use]
104    fn is_finite(self) -> bool;
105
106    /// Convert to f64
107    #[must_use]
108    fn to_f64(self) -> Option<f64>;
109
110    /// Convert from f64
111    #[must_use]
112    fn from_f64(value: f64) -> Option<Self>;
113
114    /// Convert from little-endian bytes
115    #[must_use]
116    fn from_le_bytes(bytes: &[u8]) -> Self;
117
118    /// Convert from big-endian bytes
119    #[must_use]
120    fn from_be_bytes(bytes: &[u8]) -> Self;
121
122    /// Convert to little-endian bytes
123    #[must_use]
124    fn to_le_bytes(self) -> Vec<u8>;
125
126    /// Convert to big-endian bytes
127    #[must_use]
128    fn to_be_bytes(self) -> Vec<u8>;
129}
130
131/// A trait for real-valued floating point types
132pub trait RealNumber: ScientificNumber + Float {
133    /// Returns the machine epsilon (the difference between 1.0 and the least value greater than 1.0)
134    #[must_use]
135    fn epsilon() -> Self;
136
137    /// Exponential function (e^x)
138    #[must_use]
139    fn exp(self) -> Self;
140
141    /// Natural logarithm (ln(x))
142    #[must_use]
143    fn ln(self) -> Self;
144
145    /// Base-10 logarithm
146    #[must_use]
147    fn log10(self) -> Self;
148
149    /// Base-2 logarithm
150    #[must_use]
151    fn log2(self) -> Self;
152
153    /// Sine function
154    #[must_use]
155    fn sin(self) -> Self;
156
157    /// Cosine function
158    #[must_use]
159    fn cos(self) -> Self;
160
161    /// Tangent function
162    #[must_use]
163    fn tan(self) -> Self;
164
165    /// Hyperbolic sine
166    #[must_use]
167    fn sinh(self) -> Self;
168
169    /// Hyperbolic cosine
170    #[must_use]
171    fn cosh(self) -> Self;
172
173    /// Hyperbolic tangent
174    #[must_use]
175    fn tanh(self) -> Self;
176
177    /// Inverse sine
178    #[must_use]
179    fn asin(self) -> Self;
180
181    /// Inverse cosine
182    #[must_use]
183    fn acos(self) -> Self;
184
185    /// Inverse tangent
186    #[must_use]
187    fn atan(self) -> Self;
188
189    /// Inverse tangent of y/x with correct quadrant
190    #[must_use]
191    fn atan2(self, other: Self) -> Self;
192
193    /// Power function
194    #[must_use]
195    fn powf(self, n: Self) -> Self;
196
197    /// Integer power function
198    #[must_use]
199    fn powi(self, n: i32) -> Self;
200
201    /// Factorial function (approximation for non-integers)
202    #[must_use]
203    fn factorial(self) -> Self;
204}
205
206/// A trait for complex number types
207pub trait ComplexNumber: ScientificNumber {
208    /// The real part of the complex number
209    type RealPart: RealNumber;
210
211    /// Returns the real part of the complex number
212    #[must_use]
213    fn re(&self) -> Self::RealPart;
214
215    /// Returns the imaginary part of the complex number
216    #[must_use]
217    fn im(&self) -> Self::RealPart;
218
219    /// Create a new complex number from real and imaginary parts
220    #[must_use]
221    fn from_parts(re: Self::RealPart, im: Self::RealPart) -> Self;
222
223    /// Returns the complex conjugate
224    #[must_use]
225    fn conj(self) -> Self;
226
227    /// Returns the magnitude (absolute value)
228    #[must_use]
229    fn abs(self) -> Self::RealPart;
230
231    /// Returns the argument (phase)
232    #[must_use]
233    fn arg(self) -> Self::RealPart;
234
235    /// Returns the complex number in exponential form (r, theta)
236    #[must_use]
237    fn to_polar(self) -> (Self::RealPart, Self::RealPart);
238
239    /// Creates a complex number from polar coordinates
240    #[must_use]
241    fn from_polar(r: Self::RealPart, theta: Self::RealPart) -> Self;
242
243    /// Exponential function
244    #[must_use]
245    fn exp(self) -> Self;
246
247    /// Natural logarithm
248    #[must_use]
249    fn ln(self) -> Self;
250
251    /// Power function with complex exponent
252    #[must_use]
253    fn powc(self, exp: Self) -> Self;
254
255    /// Power function with real exponent
256    #[must_use]
257    fn powf(self, exp: Self::RealPart) -> Self;
258
259    /// Square root
260    #[must_use]
261    fn sqrt(self) -> Self;
262}
263
264/// A trait for integers that can be used in scientific calculations
265pub trait ScientificInteger: ScientificNumber + Eq {
266    /// Greatest common divisor
267    #[must_use]
268    fn gcd(self, other: Self) -> Self;
269
270    /// Least common multiple
271    #[must_use]
272    fn lcm(self, other: Self) -> Self;
273
274    /// Check if the number is prime
275    #[must_use]
276    fn is_prime(self) -> bool;
277
278    /// Check if the number is even
279    #[must_use]
280    fn is_even(self) -> bool;
281
282    /// Check if the number is odd
283    #[must_use]
284    fn is_odd(self) -> bool;
285
286    /// Modular exponentiation (self^exp mod modulus)
287    #[must_use]
288    fn mod_pow(self, exp: Self, modulus: Self) -> Self;
289
290    /// Factorial
291    fn factorial(self) -> CoreResult<Self>;
292
293    /// Binomial coefficient (n choose k)
294    #[must_use]
295    fn binomial(self, k: Self) -> Self;
296}
297
298/// Trait for types that can be used as sparse matrix elements
299///
300/// This trait captures the minimal requirements for sparse matrix element types,
301/// supporting both integer and floating-point types. It provides the basic
302/// arithmetic operations and identity elements needed for sparse matrix operations.
303///
304/// # Design Philosophy
305///
306/// Unlike `Float` or `ScientificNumber`, this trait is intentionally minimal to support
307/// the widest range of numeric types in sparse matrices, including:
308/// - Integer types (u8, i32, u64, etc.) for graph adjacency matrices, binary operators, etc.
309/// - Floating-point types (f32, f64) for numerical computation
310///
311/// # Examples
312///
313/// ```
314/// use scirs2_core::numeric::SparseElement;
315///
316/// // Integer sparse matrix element
317/// let a: u8 = 1;
318/// let b: u8 = 2;
319/// assert_eq!(a + b, 3);
320/// assert_eq!(u8::sparse_zero(), 0);
321/// assert_eq!(u8::sparse_one(), 1);
322/// assert!(u8::sparse_zero().is_zero());
323///
324/// // Float sparse matrix element
325/// let x: f64 = 1.0;
326/// let y: f64 = 2.0;
327/// assert_eq!(x + y, 3.0);
328/// assert_eq!(f64::sparse_zero(), 0.0);
329/// assert_eq!(f64::sparse_one(), 1.0);
330/// assert!(f64::sparse_zero().is_zero());
331/// ```
332pub trait SparseElement:
333    Copy + PartialEq + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> + Default + Debug
334{
335    /// The zero element (additive identity) for sparse matrix operations
336    ///
337    /// This method is prefixed with `sparse_` to avoid ambiguity with `num_traits::Zero::zero()`.
338    #[must_use]
339    fn sparse_zero() -> Self;
340
341    /// The one element (multiplicative identity) for sparse matrix operations
342    ///
343    /// This method is prefixed with `sparse_` to avoid ambiguity with `num_traits::One::one()`.
344    #[must_use]
345    fn sparse_one() -> Self;
346
347    /// The zero element (additive identity)
348    ///
349    /// # Deprecation Notice
350    ///
351    /// This method is deprecated to avoid ambiguity with `num_traits::Zero::zero()`.
352    /// Use `sparse_zero()` instead.
353    #[deprecated(
354        since = "0.1.0-rc.2",
355        note = "Use `sparse_zero()` instead to avoid ambiguity with num_traits::Zero"
356    )]
357    #[must_use]
358    fn zero() -> Self {
359        Self::sparse_zero()
360    }
361
362    /// The one element (multiplicative identity)
363    ///
364    /// # Deprecation Notice
365    ///
366    /// This method is deprecated to avoid ambiguity with `num_traits::One::one()`.
367    /// Use `sparse_one()` instead.
368    #[deprecated(
369        since = "0.1.0-rc.2",
370        note = "Use `sparse_one()` instead to avoid ambiguity with num_traits::One"
371    )]
372    #[must_use]
373    fn one() -> Self {
374        Self::sparse_one()
375    }
376
377    /// Check if value is zero
378    #[must_use]
379    fn is_zero(&self) -> bool {
380        *self == Self::sparse_zero()
381    }
382}
383
384// Implement SparseElement for unsigned integer types
385impl SparseElement for u8 {
386    fn sparse_zero() -> Self {
387        0
388    }
389    fn sparse_one() -> Self {
390        1
391    }
392}
393
394impl SparseElement for u16 {
395    fn sparse_zero() -> Self {
396        0
397    }
398    fn sparse_one() -> Self {
399        1
400    }
401}
402
403impl SparseElement for u32 {
404    fn sparse_zero() -> Self {
405        0
406    }
407    fn sparse_one() -> Self {
408        1
409    }
410}
411
412impl SparseElement for u64 {
413    fn sparse_zero() -> Self {
414        0
415    }
416    fn sparse_one() -> Self {
417        1
418    }
419}
420
421impl SparseElement for u128 {
422    fn sparse_zero() -> Self {
423        0
424    }
425    fn sparse_one() -> Self {
426        1
427    }
428}
429
430impl SparseElement for usize {
431    fn sparse_zero() -> Self {
432        0
433    }
434    fn sparse_one() -> Self {
435        1
436    }
437}
438
439// Implement SparseElement for signed integer types
440impl SparseElement for i8 {
441    fn sparse_zero() -> Self {
442        0
443    }
444    fn sparse_one() -> Self {
445        1
446    }
447}
448
449impl SparseElement for i16 {
450    fn sparse_zero() -> Self {
451        0
452    }
453    fn sparse_one() -> Self {
454        1
455    }
456}
457
458impl SparseElement for i32 {
459    fn sparse_zero() -> Self {
460        0
461    }
462    fn sparse_one() -> Self {
463        1
464    }
465}
466
467impl SparseElement for i64 {
468    fn sparse_zero() -> Self {
469        0
470    }
471    fn sparse_one() -> Self {
472        1
473    }
474}
475
476impl SparseElement for i128 {
477    fn sparse_zero() -> Self {
478        0
479    }
480    fn sparse_one() -> Self {
481        1
482    }
483}
484
485impl SparseElement for isize {
486    fn sparse_zero() -> Self {
487        0
488    }
489    fn sparse_one() -> Self {
490        1
491    }
492}
493
494// Implement SparseElement for floating-point types
495impl SparseElement for f32 {
496    fn sparse_zero() -> Self {
497        0.0
498    }
499    fn sparse_one() -> Self {
500        1.0
501    }
502}
503
504impl SparseElement for f64 {
505    fn sparse_zero() -> Self {
506        0.0
507    }
508    fn sparse_one() -> Self {
509        1.0
510    }
511}
512
513// Implement ScientificNumber for f32
514impl ScientificNumber for f32 {
515    fn abs(self) -> Self {
516        self.abs()
517    }
518
519    fn sqrt(self) -> Self {
520        self.sqrt()
521    }
522
523    fn max(self, other: Self) -> Self {
524        self.max(other)
525    }
526
527    fn min(self, other: Self) -> Self {
528        self.min(other)
529    }
530
531    fn is_finite(self) -> bool {
532        self.is_finite()
533    }
534
535    fn to_f64(self) -> Option<f64> {
536        Some(self as f64)
537    }
538
539    fn from_f64(value: f64) -> Option<Self> {
540        if value.is_finite() && value <= Self::MAX as f64 && value >= Self::MIN as f64 {
541            Some(value as f32)
542        } else {
543            None
544        }
545    }
546
547    fn from_le_bytes(bytes: &[u8]) -> Self {
548        let mut array = [0u8; 4];
549        array.copy_from_slice(&bytes[..4]);
550        f32::from_le_bytes(array)
551    }
552
553    fn from_be_bytes(bytes: &[u8]) -> Self {
554        let mut array = [0u8; 4];
555        array.copy_from_slice(&bytes[..4]);
556        f32::from_be_bytes(array)
557    }
558
559    fn to_le_bytes(self) -> Vec<u8> {
560        self.to_le_bytes().to_vec()
561    }
562
563    fn to_be_bytes(self) -> Vec<u8> {
564        self.to_be_bytes().to_vec()
565    }
566}
567
568// Implement RealNumber for f32
569impl RealNumber for f32 {
570    fn epsilon() -> Self {
571        Self::EPSILON
572    }
573
574    fn exp(self) -> Self {
575        self.exp()
576    }
577
578    fn ln(self) -> Self {
579        self.ln()
580    }
581
582    fn log10(self) -> Self {
583        self.log10()
584    }
585
586    fn log2(self) -> Self {
587        self.log2()
588    }
589
590    fn sin(self) -> Self {
591        self.sin()
592    }
593
594    fn cos(self) -> Self {
595        self.cos()
596    }
597
598    fn tan(self) -> Self {
599        self.tan()
600    }
601
602    fn sinh(self) -> Self {
603        self.sinh()
604    }
605
606    fn cosh(self) -> Self {
607        self.cosh()
608    }
609
610    fn tanh(self) -> Self {
611        self.tanh()
612    }
613
614    fn asin(self) -> Self {
615        self.asin()
616    }
617
618    fn acos(self) -> Self {
619        self.acos()
620    }
621
622    fn atan(self) -> Self {
623        self.atan()
624    }
625
626    fn atan2(self, other: Self) -> Self {
627        self.atan2(other)
628    }
629
630    fn powf(self, n: Self) -> Self {
631        self.powf(n)
632    }
633
634    fn powi(self, n: i32) -> Self {
635        self.powi(n)
636    }
637
638    fn factorial(self) -> Self {
639        if self < 0.0 {
640            return Self::NAN;
641        }
642
643        // Use Stirling's approximation for non-integers or large values
644        if self != self.trunc() || self > 100.0 {
645            const SQRT_TWO_PI: f32 = 2.506_628_3;
646            return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
647        }
648
649        let mut result = 1.0;
650        let n = self as u32;
651        for i in 2..=n {
652            result *= i as f32;
653        }
654
655        result
656    }
657}
658
659// Implement ScientificNumber for f64
660impl ScientificNumber for f64 {
661    fn abs(self) -> Self {
662        self.abs()
663    }
664
665    fn sqrt(self) -> Self {
666        self.sqrt()
667    }
668
669    fn max(self, other: Self) -> Self {
670        self.max(other)
671    }
672
673    fn min(self, other: Self) -> Self {
674        self.min(other)
675    }
676
677    fn is_finite(self) -> bool {
678        self.is_finite()
679    }
680
681    fn to_f64(self) -> Option<f64> {
682        Some(self)
683    }
684
685    fn from_f64(value: f64) -> Option<Self> {
686        Some(value)
687    }
688
689    fn from_le_bytes(bytes: &[u8]) -> Self {
690        let mut array = [0u8; 8];
691        array.copy_from_slice(&bytes[..8]);
692        f64::from_le_bytes(array)
693    }
694
695    fn from_be_bytes(bytes: &[u8]) -> Self {
696        let mut array = [0u8; 8];
697        array.copy_from_slice(&bytes[..8]);
698        f64::from_be_bytes(array)
699    }
700
701    fn to_le_bytes(self) -> Vec<u8> {
702        self.to_le_bytes().to_vec()
703    }
704
705    fn to_be_bytes(self) -> Vec<u8> {
706        self.to_be_bytes().to_vec()
707    }
708}
709
710// Implement RealNumber for f64
711impl RealNumber for f64 {
712    fn epsilon() -> Self {
713        Self::EPSILON
714    }
715
716    fn exp(self) -> Self {
717        self.exp()
718    }
719
720    fn ln(self) -> Self {
721        self.ln()
722    }
723
724    fn log10(self) -> Self {
725        self.log10()
726    }
727
728    fn log2(self) -> Self {
729        self.log2()
730    }
731
732    fn sin(self) -> Self {
733        self.sin()
734    }
735
736    fn cos(self) -> Self {
737        self.cos()
738    }
739
740    fn tan(self) -> Self {
741        self.tan()
742    }
743
744    fn sinh(self) -> Self {
745        self.sinh()
746    }
747
748    fn cosh(self) -> Self {
749        self.cosh()
750    }
751
752    fn tanh(self) -> Self {
753        self.tanh()
754    }
755
756    fn asin(self) -> Self {
757        self.asin()
758    }
759
760    fn acos(self) -> Self {
761        self.acos()
762    }
763
764    fn atan(self) -> Self {
765        self.atan()
766    }
767
768    fn atan2(self, other: Self) -> Self {
769        self.atan2(other)
770    }
771
772    fn powf(self, n: Self) -> Self {
773        self.powf(n)
774    }
775
776    fn powi(self, n: i32) -> Self {
777        self.powi(n)
778    }
779
780    fn factorial(self) -> Self {
781        if self < 0.0 {
782            return Self::NAN;
783        }
784
785        // Use Stirling's approximation for non-integers or large values
786        if self != self.trunc() || self > 170.0 {
787            const SQRT_TWO_PI: f64 = 2.506_628_274_631_000_2;
788            return SQRT_TWO_PI * self.powf(self + 0.5) * (-self).exp();
789        }
790
791        let mut result = 1.0;
792        let n = self as u32;
793        for i in 2..=n {
794            result *= i as f64;
795        }
796
797        result
798    }
799}
800
801// Implement ScientificNumber for i32
802impl ScientificNumber for i32 {
803    fn abs(self) -> Self {
804        self.abs()
805    }
806
807    fn sqrt(self) -> Self {
808        (self as f64).sqrt() as i32
809    }
810
811    fn max(self, other: Self) -> Self {
812        std::cmp::max(self, other)
813    }
814
815    fn min(self, other: Self) -> Self {
816        std::cmp::min(self, other)
817    }
818
819    fn is_finite(self) -> bool {
820        true // integers are always finite
821    }
822
823    fn to_f64(self) -> Option<f64> {
824        Some(self as f64)
825    }
826
827    fn from_f64(value: f64) -> Option<Self> {
828        if value.is_finite() && value <= i32::MAX as f64 && value >= i32::MIN as f64 {
829            Some(value as i32)
830        } else {
831            None
832        }
833    }
834
835    fn from_le_bytes(bytes: &[u8]) -> Self {
836        let mut array = [0u8; 4];
837        array.copy_from_slice(&bytes[..4]);
838        i32::from_le_bytes(array)
839    }
840
841    fn from_be_bytes(bytes: &[u8]) -> Self {
842        let mut array = [0u8; 4];
843        array.copy_from_slice(&bytes[..4]);
844        i32::from_be_bytes(array)
845    }
846
847    fn to_le_bytes(self) -> Vec<u8> {
848        self.to_le_bytes().to_vec()
849    }
850
851    fn to_be_bytes(self) -> Vec<u8> {
852        self.to_be_bytes().to_vec()
853    }
854}
855
856// Implement ScientificInteger for i32
857impl ScientificInteger for i32 {
858    fn gcd(self, other: Self) -> Self {
859        let mut a = self.abs();
860        let mut b = other.abs();
861
862        if a == 0 {
863            return b;
864        }
865        if b == 0 {
866            return a;
867        }
868
869        while b != 0 {
870            let temp = b;
871            b = a % b;
872            a = temp;
873        }
874
875        a
876    }
877
878    fn lcm(self, other: Self) -> Self {
879        if self == 0 || other == 0 {
880            return 0;
881        }
882
883        let gcd = self.gcd(other);
884
885        (self / gcd) * other
886    }
887
888    fn is_prime(self) -> bool {
889        if self <= 1 {
890            return false;
891        }
892        if self <= 3 {
893            return true;
894        }
895        if self % 2 == 0 || self % 3 == 0 {
896            return false;
897        }
898
899        let mut i = 5;
900        while i * i <= self {
901            if self % i == 0 || self % (i + 2) == 0 {
902                return false;
903            }
904            i += 6;
905        }
906
907        true
908    }
909
910    fn is_even(self) -> bool {
911        self % 2 == 0
912    }
913
914    fn is_odd(self) -> bool {
915        self % 2 != 0
916    }
917
918    fn mod_pow(self, exp: Self, modulus: Self) -> Self {
919        if modulus == 1 {
920            return 0;
921        }
922
923        let mut base = self % modulus;
924        let mut result = 1;
925        let mut exponent = exp;
926
927        while exponent > 0 {
928            if exponent % 2 == 1 {
929                result = (result * base) % modulus;
930            }
931            exponent >>= 1;
932            base = (base * base) % modulus;
933        }
934
935        result
936    }
937
938    fn factorial(self) -> CoreResult<Self> {
939        if self < 0 {
940            return Err(CoreError::ValueError(ErrorContext::new(
941                "Factorial not defined for negative numbers".to_string(),
942            )));
943        }
944
945        let mut result = 1;
946        for i in 2..=self {
947            result *= i;
948        }
949
950        Ok(result)
951    }
952
953    fn binomial(self, k: Self) -> Self {
954        if k < 0 || k > self {
955            return 0;
956        }
957
958        let k = std::cmp::min(k, self - k);
959        let mut result = 1;
960
961        for i in 0..k {
962            result = result * (self - i) / (i + 1);
963        }
964
965        result
966    }
967}
968
969/// Conversion between different numeric types
970pub trait NumericConversion<T> {
971    /// Try to convert to the target type
972    fn try_convert(self) -> Option<T>;
973
974    /// Convert to the target type, or a default value if conversion fails
975    fn convert_or(self, default: T) -> T;
976
977    /// Convert to the target type, or panic if conversion fails
978    fn convert(self) -> T;
979}
980
981/// Implement NumericConversion for all types that implement NumCast
982impl<F, T> NumericConversion<T> for F
983where
984    F: NumCast,
985    T: NumCast,
986{
987    fn try_convert(self) -> Option<T> {
988        num_traits::cast(self)
989    }
990
991    fn convert_or(self, default: T) -> T {
992        self.try_convert().unwrap_or(default)
993    }
994
995    fn convert(self) -> T {
996        self.try_convert().expect("Numeric conversion failed")
997    }
998}
999
1000/// Trait for converting between degrees and radians
1001pub trait AngleConversion: Sized {
1002    /// Convert from degrees to radians
1003    fn to_radians(&self) -> CoreResult<Self>
1004    where
1005        Self: std::marker::Sized;
1006
1007    /// Convert from radians to degrees
1008    fn to_degrees(&self) -> CoreResult<Self>
1009    where
1010        Self: std::marker::Sized;
1011}
1012
1013/// Implement AngleConversion for all RealNumber types
1014impl<T: RealNumber> AngleConversion for T {
1015    fn to_radians(&self) -> CoreResult<Self> {
1016        let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
1017            CoreError::ValueError(ErrorContext::new(
1018                "Failed to convert PI constant to target type".to_string(),
1019            ))
1020        })?;
1021        let one_eighty = T::from_f64(180.0).ok_or_else(|| {
1022            CoreError::ValueError(ErrorContext::new(
1023                "Failed to convert 180.0 to target type".to_string(),
1024            ))
1025        })?;
1026        Ok(*self * pi / one_eighty)
1027    }
1028
1029    fn to_degrees(&self) -> CoreResult<Self> {
1030        let pi = T::from_f64(std::f64::consts::PI).ok_or_else(|| {
1031            CoreError::ValueError(ErrorContext::new(
1032                "Failed to convert PI constant to target type".to_string(),
1033            ))
1034        })?;
1035        let one_eighty = T::from_f64(180.0).ok_or_else(|| {
1036            CoreError::ValueError(ErrorContext::new(
1037                "Failed to convert 180.0 to target type".to_string(),
1038            ))
1039        })?;
1040        Ok(*self * one_eighty / pi)
1041    }
1042}
1043
1044/// Type-safe representation of a unitless quantity
1045#[derive(Clone, Copy, PartialEq, Debug)]
1046pub struct Scalar<T: ScientificNumber>(pub T);
1047
1048impl<T: ScientificNumber> Scalar<T> {
1049    /// Create a new scalar
1050    pub fn new(value: T) -> Self {
1051        Scalar(value)
1052    }
1053
1054    /// Get the underlying value
1055    pub fn value(&self) -> T {
1056        self.0
1057    }
1058}
1059
1060impl<T: ScientificNumber> From<T> for Scalar<T> {
1061    fn from(value: T) -> Self {
1062        Scalar(value)
1063    }
1064}
1065
1066impl<T: ScientificNumber> Add for Scalar<T> {
1067    type Output = Self;
1068
1069    fn add(self, other: Self) -> Self::Output {
1070        Scalar(self.0 + other.0)
1071    }
1072}
1073
1074impl<T: ScientificNumber> Sub for Scalar<T> {
1075    type Output = Self;
1076
1077    fn sub(self, other: Self) -> Self::Output {
1078        Scalar(self.0 - other.0)
1079    }
1080}
1081
1082impl<T: ScientificNumber> Mul for Scalar<T> {
1083    type Output = Self;
1084
1085    fn mul(self, other: Self) -> Self::Output {
1086        Scalar(self.0 * other.0)
1087    }
1088}
1089
1090impl<T: ScientificNumber> Div for Scalar<T> {
1091    type Output = Self;
1092
1093    fn div(self, other: Self) -> Self::Output {
1094        Scalar(self.0 / other.0)
1095    }
1096}
1097
1098impl<T: ScientificNumber + Neg<Output = T>> Neg for Scalar<T> {
1099    type Output = Self;
1100
1101    fn neg(self) -> Self::Output {
1102        Scalar(self.0.neg())
1103    }
1104}
1105
1106/// Automated precision tracking for numerical computations
1107pub mod precision_tracking;
1108
1109/// Specialized numeric types for scientific domains
1110pub mod scientific_types;
1111
1112/// Arbitrary precision numerical computation support
1113#[cfg(feature = "arbitrary-precision")]
1114pub mod arbitrary_precision;
1115
1116/// Numerical stability improvements
1117pub mod stability;
1118
1119/// Stable numerical algorithms
1120pub mod stable_algorithms;
1121
1122/// Advanced-optimized SIMD operations for numerical computations
1123///
1124/// This module provides vectorized implementations of common mathematical operations
1125/// using the highest available SIMD instruction sets for maximum performance.
1126pub mod advanced_simd {
1127    #[allow(unused_imports)]
1128    use super::*;
1129
1130    #[cfg(target_arch = "aarch64")]
1131    use std::arch::aarch64::*;
1132    #[cfg(target_arch = "x86_64")]
1133    use std::arch::x86_64::*;
1134
1135    /// Optimized vectorized addition for f32 arrays
1136    #[inline]
1137    pub fn add_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
1138        debug_assert_eq!(a.len(), b.len());
1139        debug_assert_eq!(a.len(), result.len());
1140
1141        let len = a.len();
1142        let mut i = 0;
1143
1144        // AVX2 path - process 8 elements at a time
1145        #[cfg(target_arch = "x86_64")]
1146        {
1147            if is_x86_feature_detected!("avx2") {
1148                unsafe {
1149                    while i + 8 <= len {
1150                        let va = _mm256_loadu_ps(a.as_ptr().add(i));
1151                        let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1152                        let vr = _mm256_add_ps(va, vb);
1153                        _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1154                        i += 8;
1155                    }
1156                }
1157            }
1158            // SSE path - process 4 elements at a time
1159            else if is_x86_feature_detected!("sse") {
1160                unsafe {
1161                    while i + 4 <= len {
1162                        let va = _mm_loadu_ps(a.as_ptr().add(i));
1163                        let vb = _mm_loadu_ps(b.as_ptr().add(i));
1164                        let vr = _mm_add_ps(va, vb);
1165                        _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1166                        i += 4;
1167                    }
1168                }
1169            }
1170        }
1171
1172        // ARM NEON path - process 4 elements at a time
1173        #[cfg(target_arch = "aarch64")]
1174        {
1175            if std::arch::is_aarch64_feature_detected!("neon") {
1176                unsafe {
1177                    while i + 4 <= len {
1178                        let va = vld1q_f32(a.as_ptr().add(i));
1179                        let vb = vld1q_f32(b.as_ptr().add(i));
1180                        let vr = vaddq_f32(va, vb);
1181                        vst1q_f32(result.as_mut_ptr().add(i), vr);
1182                        i += 4;
1183                    }
1184                }
1185            }
1186        }
1187
1188        // Scalar fallback for remaining elements
1189        while i < len {
1190            result[i] = a[i] + b[i];
1191            i += 1;
1192        }
1193    }
1194
1195    /// Optimized vectorized multiplication for f32 arrays
1196    #[inline]
1197    pub fn mul_f32_advanced(a: &[f32], b: &[f32], result: &mut [f32]) {
1198        debug_assert_eq!(a.len(), b.len());
1199        debug_assert_eq!(a.len(), result.len());
1200
1201        let len = a.len();
1202        let mut i = 0;
1203
1204        // AVX2 + FMA path for maximum performance
1205        #[cfg(target_arch = "x86_64")]
1206        {
1207            if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1208                unsafe {
1209                    while i + 8 <= len {
1210                        let va = _mm256_loadu_ps(a.as_ptr().add(i));
1211                        let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1212                        let vr = _mm256_mul_ps(va, vb);
1213                        _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1214                        i += 8;
1215                    }
1216                }
1217            } else if is_x86_feature_detected!("sse") {
1218                unsafe {
1219                    while i + 4 <= len {
1220                        let va = _mm_loadu_ps(a.as_ptr().add(i));
1221                        let vb = _mm_loadu_ps(b.as_ptr().add(i));
1222                        let vr = _mm_mul_ps(va, vb);
1223                        _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1224                        i += 4;
1225                    }
1226                }
1227            }
1228        }
1229
1230        // ARM NEON path
1231        #[cfg(target_arch = "aarch64")]
1232        {
1233            if std::arch::is_aarch64_feature_detected!("neon") {
1234                unsafe {
1235                    while i + 4 <= len {
1236                        let va = vld1q_f32(a.as_ptr().add(i));
1237                        let vb = vld1q_f32(b.as_ptr().add(i));
1238                        let vr = vmulq_f32(va, vb);
1239                        vst1q_f32(result.as_mut_ptr().add(i), vr);
1240                        i += 4;
1241                    }
1242                }
1243            }
1244        }
1245
1246        // Scalar fallback
1247        while i < len {
1248            result[i] = a[i] * b[i];
1249            i += 1;
1250        }
1251    }
1252
1253    /// Optimized fused multiply-add (a * b + c) for f32 arrays
1254    #[inline]
1255    pub fn fma_f32_advanced(a: &[f32], b: &[f32], c: &[f32], result: &mut [f32]) {
1256        debug_assert_eq!(a.len(), b.len());
1257        debug_assert_eq!(a.len(), c.len());
1258        debug_assert_eq!(a.len(), result.len());
1259
1260        let len = a.len();
1261        let mut i = 0;
1262
1263        // AVX2 + FMA path for optimal performance
1264        #[cfg(target_arch = "x86_64")]
1265        {
1266            if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1267                unsafe {
1268                    while i + 8 <= len {
1269                        let va = _mm256_loadu_ps(a.as_ptr().add(i));
1270                        let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1271                        let vc = _mm256_loadu_ps(c.as_ptr().add(i));
1272                        let vr = _mm256_fmadd_ps(va, vb, vc);
1273                        _mm256_storeu_ps(result.as_mut_ptr().add(i), vr);
1274                        i += 8;
1275                    }
1276                }
1277            } else if is_x86_feature_detected!("sse") {
1278                unsafe {
1279                    while i + 4 <= len {
1280                        let va = _mm_loadu_ps(a.as_ptr().add(i));
1281                        let vb = _mm_loadu_ps(b.as_ptr().add(i));
1282                        let vc = _mm_loadu_ps(c.as_ptr().add(i));
1283                        let vr = _mm_add_ps(_mm_mul_ps(va, vb), vc);
1284                        _mm_storeu_ps(result.as_mut_ptr().add(i), vr);
1285                        i += 4;
1286                    }
1287                }
1288            }
1289        }
1290
1291        // ARM NEON path with FMA
1292        #[cfg(target_arch = "aarch64")]
1293        {
1294            if std::arch::is_aarch64_feature_detected!("neon") {
1295                unsafe {
1296                    while i + 4 <= len {
1297                        let va = vld1q_f32(a.as_ptr().add(i));
1298                        let vb = vld1q_f32(b.as_ptr().add(i));
1299                        let vc = vld1q_f32(c.as_ptr().add(i));
1300                        let vr = vfmaq_f32(vc, va, vb);
1301                        vst1q_f32(result.as_mut_ptr().add(i), vr);
1302                        i += 4;
1303                    }
1304                }
1305            }
1306        }
1307
1308        // Scalar fallback
1309        while i < len {
1310            result[i] = a[i] * b[i] + c[0];
1311            i += 1;
1312        }
1313    }
1314
1315    /// Optimized vectorized dot product for f32 arrays
1316    #[inline]
1317    pub fn dot_product_f32_advanced(a: &[f32], b: &[f32]) -> f32 {
1318        debug_assert_eq!(a.len(), b.len());
1319
1320        let len = a.len();
1321        let mut i = 0;
1322        let mut sum = 0.0f32;
1323
1324        // AVX2 + FMA path for maximum throughput
1325        #[cfg(target_arch = "x86_64")]
1326        {
1327            if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
1328                unsafe {
1329                    let mut acc = _mm256_setzero_ps();
1330                    while i + 8 <= len {
1331                        let va = _mm256_loadu_ps(a.as_ptr().add(i));
1332                        let vb = _mm256_loadu_ps(b.as_ptr().add(i));
1333                        acc = _mm256_fmadd_ps(va, vb, acc);
1334                        i += 8;
1335                    }
1336                    // Horizontal sum of 8 floats
1337                    let hi = _mm256_extractf128_ps(acc, 1);
1338                    let lo = _mm256_castps256_ps128(acc);
1339                    let sum4 = _mm_add_ps(hi, lo);
1340                    let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1341                    let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1342                    sum = _mm_cvtss_f32(sum1);
1343                }
1344            } else if is_x86_feature_detected!("sse") {
1345                unsafe {
1346                    let mut acc = _mm_setzero_ps();
1347                    while i + 4 <= len {
1348                        let va = _mm_loadu_ps(a.as_ptr().add(i));
1349                        let vb = _mm_loadu_ps(b.as_ptr().add(i));
1350                        acc = _mm_add_ps(acc, _mm_mul_ps(va, vb));
1351                        i += 4;
1352                    }
1353                    // Horizontal sum of 4 floats
1354                    let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1355                    let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1356                    sum = _mm_cvtss_f32(sum1);
1357                }
1358            }
1359        }
1360
1361        // ARM NEON path with accumulation
1362        #[cfg(target_arch = "aarch64")]
1363        {
1364            if std::arch::is_aarch64_feature_detected!("neon") {
1365                unsafe {
1366                    let mut acc = vdupq_n_f32(0.0);
1367                    while i + 4 <= len {
1368                        let va = vld1q_f32(a.as_ptr().add(i));
1369                        let vb = vld1q_f32(b.as_ptr().add(i));
1370                        acc = vfmaq_f32(acc, va, vb);
1371                        i += 4;
1372                    }
1373                    // Horizontal sum
1374                    sum = vaddvq_f32(acc);
1375                }
1376            }
1377        }
1378
1379        // Scalar accumulation for remaining elements
1380        while i < len {
1381            sum += a[i] * b[i];
1382            i += 1;
1383        }
1384
1385        sum
1386    }
1387
1388    /// Optimized vectorized sum reduction for f32 arrays
1389    #[inline]
1390    pub fn sum_f32_advanced(data: &[f32]) -> f32 {
1391        let len = data.len();
1392        let mut i = 0;
1393        let mut sum = 0.0f32;
1394
1395        // AVX2 path
1396        #[cfg(target_arch = "x86_64")]
1397        {
1398            if is_x86_feature_detected!("avx2") {
1399                unsafe {
1400                    let mut acc = _mm256_setzero_ps();
1401                    while i + 8 <= len {
1402                        let v = _mm256_loadu_ps(data.as_ptr().add(i));
1403                        acc = _mm256_add_ps(acc, v);
1404                        i += 8;
1405                    }
1406                    // Horizontal sum
1407                    let hi = _mm256_extractf128_ps(acc, 1);
1408                    let lo = _mm256_castps256_ps128(acc);
1409                    let sum4 = _mm_add_ps(hi, lo);
1410                    let sum2 = _mm_add_ps(sum4, _mm_movehl_ps(sum4, sum4));
1411                    let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1412                    sum = _mm_cvtss_f32(sum1);
1413                }
1414            } else if is_x86_feature_detected!("sse") {
1415                unsafe {
1416                    let mut acc = _mm_setzero_ps();
1417                    while i + 4 <= len {
1418                        let v = _mm_loadu_ps(data.as_ptr().add(i));
1419                        acc = _mm_add_ps(acc, v);
1420                        i += 4;
1421                    }
1422                    let sum2 = _mm_add_ps(acc, _mm_movehl_ps(acc, acc));
1423                    let sum1 = _mm_add_ss(sum2, _mm_shuffle_ps(sum2, sum2, 1));
1424                    sum = _mm_cvtss_f32(sum1);
1425                }
1426            }
1427        }
1428
1429        // ARM NEON path
1430        #[cfg(target_arch = "aarch64")]
1431        {
1432            if std::arch::is_aarch64_feature_detected!("neon") {
1433                unsafe {
1434                    let mut acc = vdupq_n_f32(0.0);
1435                    while i + 4 <= len {
1436                        let v = vld1q_f32(data.as_ptr().add(i));
1437                        acc = vaddq_f32(acc, v);
1438                        i += 4;
1439                    }
1440                    sum = vaddvq_f32(acc);
1441                }
1442            }
1443        }
1444
1445        // Scalar accumulation
1446        while i < len {
1447            sum += data[i];
1448            i += 1;
1449        }
1450
1451        sum
1452    }
1453}
1454
1455#[cfg(test)]
1456mod tests {
1457    use super::*;
1458
1459    #[test]
1460    fn test_scientific_number_f32() {
1461        let a: f32 = 3.0;
1462        let b: f32 = 4.0;
1463
1464        assert_eq!(a.abs(), 3.0);
1465        assert_eq!(a.sqrt(), (3.0_f32).sqrt());
1466        assert_eq!(a.square(), 9.0);
1467        assert_eq!(a.max(b), 4.0);
1468        assert_eq!(a.min(b), 3.0);
1469        assert!(a.is_finite());
1470        assert_eq!(a.to_f64(), Some(3.0));
1471        assert_eq!(<f32 as ScientificNumber>::from_f64(3.5), Some(3.5));
1472    }
1473
1474    #[test]
1475    fn test_scientific_number_f64() {
1476        let a: f64 = 3.0;
1477        let b: f64 = 4.0;
1478
1479        assert_eq!(a.abs(), 3.0);
1480        assert_eq!(a.sqrt(), (3.0_f64).sqrt());
1481        assert_eq!(a.square(), 9.0);
1482        assert_eq!(a.max(b), 4.0);
1483        assert_eq!(a.min(b), 3.0);
1484        assert!(a.is_finite());
1485        assert_eq!(a.to_f64(), Some(3.0));
1486        assert_eq!(<f64 as ScientificNumber>::from_f64(3.5), Some(3.5));
1487    }
1488
1489    #[test]
1490    fn test_real_number_f32() {
1491        let a: f32 = 3.0;
1492
1493        assert_eq!(<f32 as RealNumber>::epsilon(), f32::EPSILON);
1494        assert_eq!(a.exp(), (3.0_f32).exp());
1495        assert_eq!(a.ln(), (3.0_f32).ln());
1496        assert_eq!(a.sin(), (3.0_f32).sin());
1497        assert_eq!(a.cos(), (3.0_f32).cos());
1498        assert_eq!(a.powf(2.0), 9.0);
1499    }
1500
1501    #[test]
1502    fn test_real_number_f64() {
1503        let a: f64 = 3.0;
1504
1505        assert_eq!(<f64 as RealNumber>::epsilon(), f64::EPSILON);
1506        assert_eq!(a.exp(), (3.0_f64).exp());
1507        assert_eq!(a.ln(), (3.0_f64).ln());
1508        assert_eq!(a.sin(), (3.0_f64).sin());
1509        assert_eq!(a.cos(), (3.0_f64).cos());
1510        assert_eq!(a.powf(2.0), 9.0);
1511    }
1512
1513    #[test]
1514    fn test_scientific_integer_i32() {
1515        let a: i32 = 12;
1516        let b: i32 = 8;
1517
1518        assert_eq!(a.gcd(b), 4);
1519        assert_eq!(a.lcm(b), 24);
1520        assert!(!a.is_prime());
1521        assert!(11_i32.is_prime());
1522        assert!(a.is_even());
1523        assert!(!a.is_odd());
1524        assert_eq!(a.mod_pow(2, 10), 4); // 12^2 mod 10 = 4
1525        assert_eq!(5_i32.factorial().unwrap(), 120);
1526        assert_eq!(5_i32.binomial(2), 10); // 5 choose 2 = 10
1527    }
1528
1529    #[test]
1530    fn test_numeric_conversion() {
1531        let a: f64 = 3.5;
1532        let b: i32 = a.try_convert().expect("3.5 should convert to i32 as 3");
1533        assert_eq!(b, 3);
1534
1535        let c: f32 = 100.5;
1536        let d: f64 = c.convert();
1537        assert_eq!(d, 100.5);
1538
1539        let e: i32 = 100;
1540        let f: f32 = e.convert();
1541        assert_eq!(f, 100.0);
1542    }
1543
1544    #[test]
1545    fn test_angle_conversion() {
1546        let degrees: f64 = 180.0;
1547        let radians = <f64 as AngleConversion>::to_radians(&degrees).unwrap();
1548        assert!((radians - std::f64::consts::PI).abs() < 1e-10);
1549
1550        let radians: f64 = std::f64::consts::PI / 2.0;
1551        let degrees = <f64 as AngleConversion>::to_degrees(&radians).unwrap();
1552        assert!((degrees - 90.0).abs() < 1e-10);
1553    }
1554
1555    #[test]
1556    fn test_scalar() {
1557        let a = Scalar::new(3.0_f64);
1558        let b = Scalar::new(4.0_f64);
1559
1560        assert_eq!((a + b).value(), 7.0);
1561        assert_eq!((a - b).value(), -1.0);
1562        assert_eq!((a * b).value(), 12.0);
1563        assert_eq!((a / b).value(), 0.75);
1564        assert_eq!((-a).value(), -3.0);
1565
1566        let c: Scalar<f64> = 5.0.into();
1567        assert_eq!(c.value(), 5.0);
1568    }
1569}