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}