math_rs/matrix/
traits.rs

1use std::str::FromStr;
2
3use crate::{result::Result, MathError};
4
5/// # Arithmetically Operable
6/// Supertrait that englobes all the traits any operable element should implement. It includes
7/// - The four basic operations: addition, substraction, multiplication and division, but checked.
8/// - The `Sized` trait, which is automatically implemented for any type that has a constant size known at compile-time.
9/// - The `Clone` trait, which is automatically implemented for any type that implements `Copy`.
10/// - The `PartialEq` trait, which is automatically implemented for any type that implements `Eq`.
11/// - The `FromStr` trait, which is automatically implemented for any type that implements `FromStr`.
12/// - The `Zero` trait, which will indicate how the zero element of the type is represented.
13/// - The `Identity` trait, which will indicate how the identity element of the type is represented.
14pub trait ArithmeticallyOperable<T>:
15    CheckedAdd + CheckedSub + CheckedMul + Sized + Clone + PartialEq + FromStr + Zero + Identity
16{
17}
18
19impl<T> ArithmeticallyOperable<T> for T where
20    T: CheckedAdd + CheckedSub + CheckedMul + Sized + Clone + PartialEq + FromStr + Zero + Identity
21{
22}
23
24pub trait CheckedAdd {
25    type Output;
26    fn checked_add(&self, rhs: &Self) -> Self::Output;
27}
28
29macro_rules! impl_checked_add {
30    ($($t:ty),*) => {
31        $(impl CheckedAdd for $t {
32            type Output = Result<$t>;
33            fn checked_add(&self, rhs: &Self) -> Self::Output {
34                (*self as $t).checked_add(*rhs).ok_or(MathError::MatrixError("Addition error".to_string()))
35            }
36        })*
37    };
38}
39impl_checked_add!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128);
40
41impl CheckedAdd for f32 {
42    type Output = Result<f32>;
43
44    fn checked_add(&self, rhs: &Self) -> Self::Output {
45        Ok(self + rhs)
46    }
47}
48
49impl CheckedAdd for f64 {
50    type Output = Result<f64>;
51
52    fn checked_add(&self, rhs: &Self) -> Self::Output {
53        Ok(self + rhs)
54    }
55}
56
57pub trait CheckedSub {
58    type Output;
59    fn checked_sub(&self, rhs: &Self) -> Self::Output;
60}
61
62macro_rules! impl_checked_sub {
63    ($($t:ty),*) => {
64        $(impl CheckedSub for $t {
65            type Output = Result<$t>;
66            fn checked_sub(&self, rhs: &Self) -> Self::Output {
67                (*self as $t).checked_sub(*rhs).ok_or(MathError::MatrixError("Substraction error".to_string()))
68            }
69        })*
70    };
71}
72impl_checked_sub!(isize, i8, i16, i32, i64, i128);
73
74impl CheckedSub for f32 {
75    type Output = Result<f32>;
76
77    fn checked_sub(&self, rhs: &Self) -> Self::Output {
78        Ok(self - rhs)
79    }
80}
81
82impl CheckedSub for f64 {
83    type Output = Result<f64>;
84
85    fn checked_sub(&self, rhs: &Self) -> Self::Output {
86        Ok(self - rhs)
87    }
88}
89
90impl CheckedSub for usize {
91    type Output = Result<isize>;
92    fn checked_sub(&self, rhs: &Self) -> Self::Output {
93        (*self as isize)
94            .checked_sub(*rhs as isize)
95            .ok_or(MathError::MatrixError("Substraction error".to_string()))
96    }
97}
98
99impl CheckedSub for u8 {
100    type Output = Result<i8>;
101    fn checked_sub(&self, rhs: &Self) -> Self::Output {
102        (*self as i8)
103            .checked_sub(*rhs as i8)
104            .ok_or(MathError::MatrixError("Substraction error".to_string()))
105    }
106}
107
108impl CheckedSub for u16 {
109    type Output = Result<i16>;
110    fn checked_sub(&self, rhs: &Self) -> Self::Output {
111        (*self as i16)
112            .checked_sub(*rhs as i16)
113            .ok_or(MathError::MatrixError("Substraction error".to_string()))
114    }
115}
116
117impl CheckedSub for u32 {
118    type Output = Result<i32>;
119    fn checked_sub(&self, rhs: &Self) -> Self::Output {
120        (*self as i32)
121            .checked_sub(*rhs as i32)
122            .ok_or(MathError::MatrixError("Substraction error".to_string()))
123    }
124}
125
126impl CheckedSub for u64 {
127    type Output = Result<i64>;
128    fn checked_sub(&self, rhs: &Self) -> Self::Output {
129        (*self as i64)
130            .checked_sub(*rhs as i64)
131            .ok_or(MathError::MatrixError("Substraction error".to_string()))
132    }
133}
134
135impl CheckedSub for u128 {
136    type Output = Result<i128>;
137    fn checked_sub(&self, rhs: &Self) -> Self::Output {
138        (*self as i128)
139            .checked_sub(*rhs as i128)
140            .ok_or(MathError::MatrixError("Substraction error".to_string()))
141    }
142}
143
144pub trait CheckedDiv {
145    type Output;
146    fn checked_div(&self, rhs: &Self) -> Self::Output;
147}
148
149macro_rules! impl_checked_div {
150    ($($t:ty),*) => {
151        $(impl CheckedDiv for $t {
152            type Output = Result<$t>;
153            fn checked_div(&self, rhs: &Self) -> Self::Output {
154                (*self as $t).checked_div(*rhs).ok_or(MathError::MatrixError("Division error".to_string()))
155            }
156        })*
157    };
158}
159
160impl_checked_div!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128);
161
162impl CheckedDiv for f32 {
163    type Output = Result<f32>;
164
165    fn checked_div(&self, rhs: &Self) -> Self::Output {
166        Ok(self / rhs)
167    }
168}
169
170impl CheckedDiv for f64 {
171    type Output = Result<f64>;
172
173    fn checked_div(&self, rhs: &Self) -> Self::Output {
174        Ok(self / rhs)
175    }
176}
177
178pub trait CheckedMul {
179    type Output;
180    fn checked_mul(&self, rhs: &Self) -> Self::Output;
181}
182
183macro_rules! impl_checked_mul {
184    ($($t:ty),*) => {
185        $(impl CheckedMul for $t {
186            type Output = Result<$t>;
187            fn checked_mul(&self, rhs: &Self) -> Self::Output {
188                (*self as $t).checked_mul(*rhs).ok_or(MathError::MatrixError("Multiplication error".to_string()))
189            }
190        })*
191    };
192}
193
194impl_checked_mul!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128);
195
196impl CheckedMul for f32 {
197    type Output = Result<f32>;
198
199    fn checked_mul(&self, rhs: &Self) -> Self::Output {
200        Ok(self * rhs)
201    }
202}
203
204impl CheckedMul for f64 {
205    type Output = Result<f64>;
206
207    fn checked_mul(&self, rhs: &Self) -> Self::Output {
208        Ok(self * rhs)
209    }
210}
211
212pub trait Zero {
213    fn zero(rows: usize, columns: usize, tolerance: f32) -> Self;
214    fn is_zero(&self) -> bool;
215}
216
217macro_rules! impl_zero {
218    ($($t:ty),*) => {
219        $(impl Zero for $t {
220            fn zero(_rows: usize, _columns: usize, _tolerance: f32) -> Self {
221                0 as $t
222            }
223            fn is_zero(&self) -> bool {
224                *self == 0 as $t
225            }
226        })*
227    };
228}
229
230impl_zero!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64);
231
232pub trait Identity {
233    fn id(dimensions: usize, tolerance: f32) -> Self;
234}
235
236macro_rules! impl_identity {
237    ($($t:ty),*) => {
238        $(impl Identity for $t {
239            fn id(_dimensions: usize, _tolerance: f32) -> Self {
240                1 as $t
241            }
242        })*
243    };
244}
245
246impl_identity!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64);
247
248pub trait Invertible {
249    fn inverse_gauss_jordan(&self) -> Result<Self>
250    where
251        Self: Sized;
252
253    fn inverse_montante(&self) -> Result<Self>
254    where
255        Self: Sized;
256
257    fn inverse_adjoint(&self) -> Result<Self>
258    where
259        Self: Sized;
260}
261
262pub trait Parseable {
263    fn parse(string: &str, tolerance: f32) -> Result<Self>
264    where
265        Self: Sized;
266}
267
268pub trait Serializable {
269    /// Serialize the matrix, return it in the form `{{a, b, c}, {d, e, f}, {g, h, i}}`
270    fn serialize(&self) -> String;
271}
272
273pub trait Matrix: ArithmeticallyOperable<Self> + Invertible + Parseable + Serializable {
274    type T: ArithmeticallyOperable<Self::T>;
275    /// Will return the number of columns of the matrix
276    fn columns(&self) -> usize;
277
278    /// Will return the number of rows of the matrix
279    fn rows(&self) -> usize;
280
281    /// Will return `true` if the matrix is squared, i.e., if `rows == columns`
282    fn is_square(&self) -> bool;
283
284    /// Will return `true` if the matrix is symmetric, i.e., if `A == A^T`
285    fn is_symmetric(&self) -> bool;
286
287    /// Get a reference of an element of the matrix, or error if you provide wrong indexes
288    fn get(&self, row: usize, column: usize) -> Result<&Self::T>;
289
290    /// Get a mutable reference of an element of the matrix, or error if you provide wrong indexes
291    fn get_mut(&mut self, row: usize, column: usize) -> Result<&mut Self::T>;
292
293    /// Set an element of the matrix, or error if you provide wrong indexes
294    fn set(&mut self, row: usize, column: usize, value: Self::T) -> Result<()>;
295
296    /// Swap two rows of the matrix, or error if you provide wrong indexes
297    fn swap_rows(&mut self, row1: usize, row2: usize) -> Result<()>;
298
299    /// Return a new matrix being the transposed of the current one. It does not eliminate the current one
300    fn transpose(&self) -> Self;
301
302    /// Return a new matrix being the reduced gaussian inferior triangular of the current one. It does not eliminate the current one
303    fn gaussian_triangulation(&self) -> Result<Self>;
304
305    /// Returns a tuple containing the matrices `L` and `U` of the LU decomposition, in order. It does not eliminate the current one
306    fn lu_decomposition(&self) -> Result<(Self, Self)>;
307
308    /// Returns a matrix resulting from the Cholesky decomposition. It does not eliminate the current one
309    fn cholesky_decomposition(&self) -> Result<Self>;
310
311    /// Return the determinant or a `None` if the matrix is not squared
312    fn determinant_using_gauss(&self) -> Option<Self::T>;
313
314    fn determinant_using_lu(&self) -> Option<Self::T>;
315}