com_croftsoft_core/math/matrix/functions/
mod.rs

1// =============================================================================
2//! - Functions for the structure Matrix
3//!
4//! # Metadata
5//! - Copyright: © 1998 - 2022 [`CroftSoft Inc`]
6//! - Author: [`David Wallace Croft`]
7//! - Rust version: 2022-10-05
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// Associated functions --------------------------------------------------------
26
27impl<const R: usize, const C: usize> Matrix<R, C> {
28  // ---------------------------------------------------------------------------
29  /// Adds the arguments and return the sum as a new Matrix
30  // ---------------------------------------------------------------------------
31  pub fn add_matrix_with_matrix(
32    augend: &Self,
33    addend: &Self,
34  ) -> Self {
35    let mut sum = Self::default();
36    for r in 0..R {
37      for c in 0..C {
38        sum.rows[r][c] = augend.rows[r][c] + addend.rows[r][c];
39      }
40    }
41    sum
42  }
43
44  // ---------------------------------------------------------------------------
45  /// Adds the arguments and then returns the sum as a new Matrix
46  // ---------------------------------------------------------------------------
47  pub fn add_matrix_with_scalar(
48    augend: &Self,
49    addend: f64,
50  ) -> Self {
51    let mut sum = Self::new(addend);
52    for r in 0..R {
53      for c in 0..C {
54        sum.rows[r][c] += augend.rows[r][c];
55      }
56    }
57    sum
58  }
59
60  // ---------------------------------------------------------------------------
61  /// Divides corresponding entries and returns the quotient as a new Matrix
62  // ---------------------------------------------------------------------------
63  pub fn divide_matrix_by_matrix_entrywise(
64    dividend_matrix: &Self,
65    divisor_matrix: &Self,
66  ) -> Self {
67    let mut quotient_matrix = Self::default();
68    for r in 0..R {
69      for c in 0..C {
70        quotient_matrix.rows[r][c] =
71          dividend_matrix.rows[r][c] / divisor_matrix.rows[r][c];
72      }
73    }
74    quotient_matrix
75  }
76
77  // ---------------------------------------------------------------------------
78  /// Divides each entry by the scalar and then returns a new Matrix
79  // ---------------------------------------------------------------------------
80  pub fn divide_matrix_by_scalar(
81    dividend: &Self,
82    divisor: f64,
83  ) -> Self {
84    let mut quotient = Self::default();
85    for r in 0..R {
86      for c in 0..C {
87        quotient.rows[r][c] = dividend.rows[r][c] / divisor;
88      }
89    }
90    quotient
91  }
92
93  // ---------------------------------------------------------------------------
94  /// Multiplies the arguments and then returns the product as a new Matrix
95  // ---------------------------------------------------------------------------
96  pub fn multiply_matrix_with_matrix<const K: usize>(
97    multiplicand: &Self,
98    multiplier: &Matrix<C, K>,
99  ) -> Matrix<R, K> {
100    let mut product = Matrix::<R, K>::default();
101    for r in 0..R {
102      for k in 0..K {
103        for i in 0..C {
104          product.rows[r][k] += multiplicand.rows[r][i] * multiplier.rows[i][k];
105        }
106      }
107    }
108    product
109  }
110
111  // ---------------------------------------------------------------------------
112  /// Multiplies entries and returns the Hadamard product as a new Matrix
113  ///
114  /// <https://en.wikipedia.org/wiki/Hadamard_product_(matrices)>
115  // ---------------------------------------------------------------------------
116  pub fn multiply_matrix_with_matrix_entrywise(
117    original_matrix: &Self,
118    weighting_matrix: &Self,
119  ) -> Self {
120    let mut hadamard_product = Self::default();
121    for r in 0..R {
122      for c in 0..C {
123        hadamard_product.rows[r][c] =
124          original_matrix.rows[r][c] * weighting_matrix.rows[r][c];
125      }
126    }
127    hadamard_product
128  }
129
130  pub fn multiply_matrix_with_scalar(
131    multiplicand: &Self,
132    multiplier: f64,
133  ) -> Self {
134    let mut product = Self::new(multiplier);
135    for r in 0..R {
136      for c in 0..C {
137        product.rows[r][c] *= multiplicand.rows[r][c];
138      }
139    }
140    product
141  }
142
143  // ---------------------------------------------------------------------------
144  /// Multiplies all entries by -1.0 and then returns the new negated Matrix
145  // ---------------------------------------------------------------------------
146  pub fn negate_matrix(matrix: &Self) -> Self {
147    let mut negated_matrix = Self::default();
148    for r in 0..R {
149      for c in 0..C {
150        negated_matrix.rows[r][c] = -matrix.rows[r][c];
151      }
152    }
153    negated_matrix
154  }
155
156  // ---------------------------------------------------------------------------
157  /// Makes a new Matrix with all entries set to the argument
158  // ---------------------------------------------------------------------------
159  pub fn new(value: f64) -> Self {
160    Self {
161      rows: [[value; C]; R],
162    }
163  }
164
165  // ---------------------------------------------------------------------------
166  /// Subtracts the 2nd from the 1st and returns the difference as a new Matrix
167  // ---------------------------------------------------------------------------
168  pub fn subtract_matrix_from_matrix(
169    minuend: &Self,
170    subtrahend: &Self,
171  ) -> Self {
172    let mut difference = Self::default();
173    for r in 0..R {
174      for c in 0..C {
175        difference.rows[r][c] = minuend.rows[r][c] - subtrahend.rows[r][c];
176      }
177    }
178    difference
179  }
180
181  // ---------------------------------------------------------------------------
182  /// Subtracts the 2nd from the 1st and returns the difference as a new Matrix
183  // ---------------------------------------------------------------------------
184  pub fn subtract_matrix_from_scalar(
185    minuend: f64,
186    subtrahend: &Self,
187  ) -> Self {
188    let mut difference = Self::new(minuend);
189    for r in 0..R {
190      for c in 0..C {
191        difference.rows[r][c] -= subtrahend.rows[r][c];
192      }
193    }
194    difference
195  }
196
197  // ---------------------------------------------------------------------------
198  /// Subtracts the 2nd from the 1st and returns the difference as a new Matrix
199  // ---------------------------------------------------------------------------
200  pub fn subtract_scalar_from_matrix(
201    minuend: &Self,
202    subtrahend: f64,
203  ) -> Self {
204    let mut difference = Self::default();
205    for r in 0..R {
206      for c in 0..C {
207        difference.rows[r][c] = minuend.rows[r][c] - subtrahend;
208      }
209    }
210    difference
211  }
212}
213
214// Associated functions for a square Matrix ------------------------------------
215
216impl<const R: usize> Matrix<R, R> {
217  // ---------------------------------------------------------------------------
218  /// Makes a square matrix with the diagonal values set to 1.0 and all others 0
219  // ---------------------------------------------------------------------------
220  pub fn identity() -> Self {
221    let mut identity_matrix = Self::default();
222    for r in 0..R {
223      identity_matrix.rows[r][r] = 1.0;
224    }
225    identity_matrix
226  }
227}
228
229// Associated functions for a rotation Matrix ----------------------------------
230
231impl Matrix<3, 3> {
232  pub fn to_rotation_matrix_x_from_degrees(degrees: Degrees) -> Self {
233    Self::to_rotation_matrix_x_from_radians(degrees.into())
234  }
235
236  pub fn to_rotation_matrix_x_from_radians(radians: Radians) -> Self {
237    let cos = radians.0.cos();
238    let sin = radians.0.sin();
239    Matrix {
240      rows: [
241        [
242          1.0, 0.0, 0.0,
243        ],
244        [
245          0.0, cos, -sin,
246        ],
247        [
248          0.0, sin, cos,
249        ],
250      ],
251    }
252  }
253
254  pub fn to_rotation_matrix_y_from_degrees(degrees: Degrees) -> Self {
255    Self::to_rotation_matrix_y_from_radians(degrees.into())
256  }
257
258  pub fn to_rotation_matrix_y_from_radians(radians: Radians) -> Self {
259    let cos = radians.0.cos();
260    let sin = radians.0.sin();
261    Matrix {
262      rows: [
263        [
264          cos, 0.0, sin,
265        ],
266        [
267          0.0, 1.0, 0.0,
268        ],
269        [
270          -sin, 0.0, cos,
271        ],
272      ],
273    }
274  }
275
276  pub fn to_rotation_matrix_z_from_degrees(degrees: Degrees) -> Self {
277    Self::to_rotation_matrix_z_from_radians(degrees.into())
278  }
279
280  pub fn to_rotation_matrix_z_from_radians(radians: Radians) -> Self {
281    let cos = radians.0.cos();
282    let sin = radians.0.sin();
283    Matrix {
284      rows: [
285        [
286          cos, -sin, 0.0,
287        ],
288        [
289          sin, cos, 0.0,
290        ],
291        [
292          0.0, 0.0, 1.0,
293        ],
294      ],
295    }
296  }
297}