linalg_traits/
scalar.rs

1use num_traits::Float;
2use std::fmt::Debug;
3use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
4
5/// Trait defining a generic scalar type.
6///
7/// # Interoperability with [`f64`]s.
8///
9/// We enforce that scalar types be interoperable with [`f64`]s. Some common differentiation
10/// methods, notably forward-mode automatic differentation and complex-step differentiation, rely
11/// on replacing real numbers with a custom type of number that has its own arithmetic (dual numbers
12/// for forward-mode automatic differentiation, complex numbers for complex-step differentiation).
13/// Forcing scalars to have this interoperability with [`f64`]s built-in helps enable downstream
14/// crates to write functions in way that can be used with both plain [`f64`]s for most use cases,
15/// and with custom types when the functions need to be differentiated.
16///
17/// Additionally, we chose to restrict this interoperability to be with [`f64`]s since
18/// double-precision floating point numbers are the de facto standard for numerical computations.
19///
20/// # Note
21///
22/// [`nalgebra::Complex`] does not satisfy the the [`Scalar`] trait because it does not implement
23/// the [`PartialOrd`] trait.
24pub trait Scalar:
25    // Float trait from num-traits, providing:
26    //  --> Copy
27    //  --> PartialEq
28    //  --> PartialOrd
29    //  --> Add<Self, Output = Self>
30    //  --> Sub<Self, Output = Self>
31    //  --> Mul<Self, Output = Self>
32    //  --> Div<Self, Output = Self>
33    //  --> Rem<Self, Output = Self>
34    //  --> Neg<Output = Self>
35    //  --> Zero
36    //  --> One
37    //  --> Standard mathematical methods (i.e. most methods implement for f64s).
38    Float
39    // Arithmetic-assignment operators with itself.
40    + AddAssign<Self>
41    + SubAssign<Self>
42    + MulAssign<Self>
43    + DivAssign<Self>
44    + RemAssign<Self>
45    // Arithmetic operators with f64.
46    + Add<f64, Output = Self>
47    + Sub<f64, Output = Self>
48    + Mul<f64, Output = Self>
49    + Div<f64, Output = Self>
50    + Rem<f64, Output = Self>
51    // Arithmetic-assignment operators with f64.
52    + AddAssign<f64>
53    + SubAssign<f64>
54    + MulAssign<f64>
55    + DivAssign<f64>
56    + RemAssign<f64>
57    // Debug printing.
58    + Debug
59    // Type must be defined at compile time.
60    + 'static
61{
62    /// Construct an instance of this scalar from an [`f64`].
63    /// 
64    /// # Arguments
65    /// 
66    /// * `x` - An [`f64`].
67    /// 
68    /// # Return
69    /// 
70    /// An instance of this scalar type constructed from an [`f64`].
71    fn new(x: f64) -> Self {
72        Self::from(x).unwrap()
73    }
74}
75
76impl<T> Scalar for T where
77    T: Float
78        + AddAssign<Self>
79        + SubAssign<Self>
80        + MulAssign<Self>
81        + DivAssign<Self>
82        + RemAssign<Self>
83        + Add<f64, Output = Self>
84        + Sub<f64, Output = Self>
85        + Mul<f64, Output = Self>
86        + Div<f64, Output = Self>
87        + Rem<f64, Output = Self>
88        + AddAssign<f64>
89        + SubAssign<f64>
90        + MulAssign<f64>
91        + DivAssign<f64>
92        + RemAssign<f64>
93        + Debug
94        + 'static
95{
96}