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}