com_croftsoft_core/math/matrix/methods/
mod.rs

1// =============================================================================
2//! - Methods for the structure Matrix
3//!
4//! # Metadata
5//! - Copyright: © 1998 - 2022 [`CroftSoft Inc`]
6//! - Author: [`David Wallace Croft`]
7//! - Rust version: 2022-10-03
8//! - Rust since: 2022-09-04
9//! - Java version: 1998-12-27
10//!
11//! # History
12//! - Adapted from the Java class com.croftsoft.core.math.Matrix
13//!   - In the Java-based [`CroftSoft Core Library`]
14//!
15//! [`CroftSoft Core Library`]: https://www.croftsoft.com/library/code/
16//! [`CroftSoft Inc`]: https://www.croftsoft.com/
17//! [`David Wallace Croft`]: https://www.croftsoft.com/people/david/
18// =============================================================================
19
20#[cfg(test)]
21mod test;
22
23use super::structures::*;
24
25// Methods ---------------------------------------------------------------------
26
27impl<const R: usize, const C: usize> Matrix<R, C> {
28  // ---------------------------------------------------------------------------
29  /// Adds the argument entries to all corresponding entries and returns self
30  // ---------------------------------------------------------------------------
31  pub fn add_matrix(
32    &mut self,
33    addend: &Self,
34  ) -> &mut Self {
35    for r in 0..R {
36      for c in 0..C {
37        self.rows[r][c] += addend.rows[r][c];
38      }
39    }
40    self
41  }
42
43  // ---------------------------------------------------------------------------
44  /// Adds the scalar to all entries and then returns a reference to self
45  // ---------------------------------------------------------------------------
46  pub fn add_scalar(
47    &mut self,
48    addend: f64,
49  ) -> &mut Self {
50    for r in 0..R {
51      for c in 0..C {
52        self.rows[r][c] += addend;
53      }
54    }
55    self
56  }
57
58  // ---------------------------------------------------------------------------
59  /// Divides corresponding entries and then returns a reference to self
60  // ---------------------------------------------------------------------------
61  pub fn divide_by_matrix_entrywise(
62    &mut self,
63    divisor: &Self,
64  ) -> &mut Self {
65    for r in 0..R {
66      for c in 0..C {
67        self.rows[r][c] /= divisor.rows[r][c];
68      }
69    }
70    self
71  }
72
73  // ---------------------------------------------------------------------------
74  /// Divides each entry by the argument and then returns a reference to self
75  // ---------------------------------------------------------------------------
76  pub fn divide_by_scalar(
77    &mut self,
78    divisor: f64,
79  ) -> &mut Self {
80    for r in 0..R {
81      for c in 0..C {
82        self.rows[r][c] /= divisor;
83      }
84    }
85    self
86  }
87
88  // ---------------------------------------------------------------------------
89  /// Returns the entry at the position given by the indices
90  // ---------------------------------------------------------------------------
91  pub fn get_entry(
92    &self,
93    indices: Indices,
94  ) -> f64 {
95    self.rows[indices.row][indices.column]
96  }
97
98  // ---------------------------------------------------------------------------
99  /// Returns a reference to a row of entries, indexed from zero
100  // ---------------------------------------------------------------------------
101  pub fn get_row(
102    &self,
103    row_index: usize,
104  ) -> &[f64; C] {
105    &self.rows[row_index]
106  }
107
108  // ---------------------------------------------------------------------------
109  /// Returns true if the number of rows equals the number of columns
110  // ---------------------------------------------------------------------------
111  pub fn is_square(&self) -> bool {
112    R == C
113  }
114
115  // ---------------------------------------------------------------------------
116  /// Returns false if any difference magnitude is greater than the tolerance.
117  ///
118  /// The tolerance should be a positive number.
119  // ---------------------------------------------------------------------------
120  pub fn matches_closely(
121    &self,
122    other: &Self,
123    tolerance: f64,
124  ) -> bool {
125    for r in 0..R {
126      for c in 0..C {
127        let difference_magnitude = (self.rows[r][c] - other.rows[r][c]).abs();
128        if difference_magnitude > tolerance {
129          return false;
130        }
131      }
132    }
133    true
134  }
135
136  // ---------------------------------------------------------------------------
137  /// Returns true if the other Matrix has the exact same entries
138  // ---------------------------------------------------------------------------
139  pub fn matches_exactly(
140    &self,
141    other: &Self,
142  ) -> bool {
143    for r in 0..R {
144      for c in 0..C {
145        if self.rows[r][c] != other.rows[r][c] {
146          return false;
147        }
148      }
149    }
150    true
151  }
152
153  // ---------------------------------------------------------------------------
154  /// Multiplies with a square matrix and then returns a reference to self
155  // ---------------------------------------------------------------------------
156  pub fn multiply_with_matrix(
157    &mut self,
158    multiplier: &Matrix<C, C>,
159  ) -> &mut Self {
160    let product = Self::multiply_matrix_with_matrix(self, multiplier);
161    for r in 0..R {
162      for c in 0..C {
163        self.rows[r][c] = product.rows[r][c];
164      }
165    }
166    self
167  }
168
169  // ---------------------------------------------------------------------------
170  /// Multiplies corresponding entries and then returns a reference to self
171  ///
172  /// This result is known as the Hadamard Product:<br>
173  /// <https://en.wikipedia.org/wiki/Hadamard_product_(matrices)>
174  // ---------------------------------------------------------------------------
175  pub fn multiply_with_matrix_entrywise(
176    &mut self,
177    weighting_matrix: &Self,
178  ) -> &mut Self {
179    for r in 0..R {
180      for c in 0..C {
181        self.rows[r][c] *= weighting_matrix.rows[r][c];
182      }
183    }
184    self
185  }
186
187  // ---------------------------------------------------------------------------
188  /// Multiplies all entries by the scalar and then returns a reference to self
189  // ---------------------------------------------------------------------------
190  pub fn multiply_with_scalar(
191    &mut self,
192    multiplier: f64,
193  ) -> &mut Self {
194    for r in 0..R {
195      for c in 0..C {
196        self.rows[r][c] *= multiplier;
197      }
198    }
199    self
200  }
201
202  // ---------------------------------------------------------------------------
203  /// Multiplies all entries by -1.0 and then returns a reference to self
204  // ---------------------------------------------------------------------------
205  pub fn negate(&mut self) -> &mut Self {
206    for r in 0..R {
207      for c in 0..C {
208        self.rows[r][c] *= -1.0;
209      }
210    }
211    self
212  }
213
214  // ---------------------------------------------------------------------------
215  /// Sets the entry at the position given by the indices and then returns self
216  // ---------------------------------------------------------------------------
217  pub fn set_entry(
218    &mut self,
219    indices: Indices,
220    value: f64,
221  ) -> &mut Self {
222    self.rows[indices.row][indices.column] = value;
223    self
224  }
225
226  // ---------------------------------------------------------------------------
227  /// Returns a new Matrix that is a submatrix of self
228  // ---------------------------------------------------------------------------
229  pub fn submatrix<const P: usize, const K: usize>(
230    &self,
231    offset_indices: Indices,
232  ) -> Matrix<P, K> {
233    let mut submatrix: Matrix<P, K> = Matrix::default();
234    let offset_row: usize = offset_indices.row;
235    let offset_column: usize = offset_indices.column;
236    for row in 0..P {
237      for column in 0..K {
238        submatrix.rows[row][column] =
239          self.rows[row + offset_row][column + offset_column];
240      }
241    }
242    submatrix
243  }
244
245  // ---------------------------------------------------------------------------
246  /// Subtracts all entries from the scalar and then returns a reference to self
247  // ---------------------------------------------------------------------------
248  pub fn subtract_from_scalar(
249    &mut self,
250    minuend: f64,
251  ) -> &mut Self {
252    for r in 0..R {
253      for c in 0..C {
254        self.rows[r][c] = minuend - self.rows[r][c];
255      }
256    }
257    self
258  }
259
260  // ---------------------------------------------------------------------------
261  /// Subtracts the argument entries from corresponding entries and returns self
262  // ---------------------------------------------------------------------------
263  pub fn subtract_matrix(
264    &mut self,
265    subtrahend: &Self,
266  ) -> &mut Self {
267    for r in 0..R {
268      for c in 0..C {
269        self.rows[r][c] -= subtrahend.rows[r][c];
270      }
271    }
272    self
273  }
274
275  // ---------------------------------------------------------------------------
276  /// Subtracts the scalar from all entries and then returns a reference to self
277  // ---------------------------------------------------------------------------
278  pub fn subtract_scalar(
279    &mut self,
280    subtrahend: f64,
281  ) -> &mut Self {
282    for r in 0..R {
283      for c in 0..C {
284        self.rows[r][c] -= subtrahend;
285      }
286    }
287    self
288  }
289
290  // ---------------------------------------------------------------------------
291  /// Calculates the sum of all of the entries in the Matrix
292  // ---------------------------------------------------------------------------
293  pub fn sum_entries(&self) -> f64 {
294    self.rows.iter().fold(0.0, |sum, row| {
295      sum + row.iter().fold(0.0, |sum, entry| sum + entry)
296    })
297  }
298
299  // ---------------------------------------------------------------------------
300  /// Returns a new Matrix with the rows and columns switched.
301  // ---------------------------------------------------------------------------
302  pub fn transpose(&self) -> Matrix<C, R> {
303    let mut transposed_matrix = Matrix::<C, R>::default();
304    for (row_index, row) in self.rows.iter().enumerate() {
305      for (column_index, entry) in row.iter().enumerate() {
306        transposed_matrix.rows[column_index][row_index] = *entry;
307      }
308    }
309    transposed_matrix
310  }
311}