conspire/math/matrix/square/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::math::assert::FiniteDifference;
5
6use crate::{
7 ABS_TOL,
8 math::{
9 Hessian, Rank2, Scalar, Tensor, TensorRank2Vec2D, TensorVec, Vector, write_tensor_rank_0,
10 },
11};
12use std::{
13 fmt::{self, Display, Formatter},
14 iter::Sum,
15 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
16 vec::IntoIter,
17};
18
19#[derive(Debug, PartialEq)]
21pub enum SquareMatrixError {
22 Singular,
23}
24
25#[derive(Clone, Debug, PartialEq)]
27pub struct SquareMatrix(Vec<Vector>);
28
29impl Default for SquareMatrix {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35impl SquareMatrix {
36 pub fn solve_lu(&self, b: &Vector) -> Result<Vector, SquareMatrixError> {
113 let n = self.len();
114 let mut p: Vec<usize> = (0..n).collect();
115 let mut factor;
116 let mut lu = self.clone();
117 let mut max_row;
118 let mut max_val;
119 let mut pivot;
120 for i in 0..n {
121 max_row = i;
122 max_val = lu[max_row][i].abs();
123 for k in i + 1..n {
124 if lu[k][i].abs() > max_val {
125 max_row = k;
126 max_val = lu[max_row][i].abs();
127 }
128 }
129 if max_row != i {
130 lu.0.swap(i, max_row);
131 p.swap(i, max_row);
132 }
133 pivot = lu[i][i];
134 if pivot.abs() < ABS_TOL {
135 return Err(SquareMatrixError::Singular);
136 }
137 for j in i + 1..n {
138 if lu[j][i] != 0.0 {
139 lu[j][i] /= pivot;
140 factor = lu[j][i];
141 let (front, back) = lu.0.split_at_mut(j);
142 back[0].as_mut_slice()[i + 1..n]
143 .iter_mut()
144 .zip(front[i].as_slice()[i + 1..n].iter())
145 .for_each(|(lu_jk, lu_ik)| *lu_jk -= factor * lu_ik);
146 }
147 }
148 }
149 let mut x: Vector = p.into_iter().map(|p_i| b[p_i]).collect();
150 forward_substitution(&mut x, &lu);
151 backward_substitution(&mut x, &lu);
152 Ok(x)
153 }
154 pub fn zero(len: usize) -> Self {
155 (0..len).map(|_| Vector::zero(len)).collect()
156 }
157}
158
159fn forward_substitution(x: &mut Vector, a: &SquareMatrix) {
160 a.iter().enumerate().for_each(|(i, a_i)| {
161 x[i] -= a_i
162 .iter()
163 .take(i)
164 .zip(x.iter().take(i))
165 .map(|(a_ij, x_j)| a_ij * x_j)
166 .sum::<Scalar>()
167 })
168}
169
170fn backward_substitution(x: &mut Vector, a: &SquareMatrix) {
171 a.0.iter().enumerate().rev().for_each(|(i, a_i)| {
172 x[i] -= a_i
173 .iter()
174 .skip(i + 1)
175 .zip(x.iter().skip(i + 1))
176 .map(|(a_ij, x_j)| a_ij * x_j)
177 .sum::<Scalar>();
178 x[i] /= a_i[i];
179 })
180}
181
182impl FiniteDifference for SquareMatrix {
183 fn error_fd(&self, comparator: &Self, epsilon: Scalar) -> Option<(bool, usize)> {
184 let error_count = self
185 .iter()
186 .zip(comparator.iter())
187 .map(|(self_i, comparator_i)| {
188 self_i
189 .iter()
190 .zip(comparator_i.iter())
191 .filter(|&(&self_ij, &comparator_ij)| {
192 (self_ij / comparator_ij - 1.0).abs() >= epsilon
193 && (self_ij.abs() >= epsilon || comparator_ij.abs() >= epsilon)
194 })
195 .count()
196 })
197 .sum();
198 if error_count > 0 {
199 Some((true, error_count))
200 } else {
201 None
202 }
203 }
204}
205
206impl Display for SquareMatrix {
207 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
208 write!(f, "\x1B[s")?;
209 write!(f, "[[")?;
210 self.iter().enumerate().try_for_each(|(i, row)| {
211 row.iter()
212 .try_for_each(|entry| write_tensor_rank_0(f, entry))?;
213 if i + 1 < self.len() {
214 writeln!(f, "\x1B[2D],")?;
215 write!(f, "\x1B[u")?;
216 write!(f, "\x1B[{}B [", i + 1)?;
217 }
218 Ok(())
219 })?;
220 write!(f, "\x1B[2D]]")
221 }
222}
223
224impl<const N: usize> From<[[Scalar; N]; N]> for SquareMatrix {
225 fn from(array: [[Scalar; N]; N]) -> Self {
226 array.into_iter().map(Vector::from).collect()
227 }
228}
229
230impl<const D: usize, const I: usize, const J: usize> From<TensorRank2Vec2D<D, I, J>>
231 for SquareMatrix
232{
233 fn from(tensor_rank_2_vec_2d: TensorRank2Vec2D<D, I, J>) -> Self {
234 let mut square_matrix = Self::zero(tensor_rank_2_vec_2d.len() * D);
235 tensor_rank_2_vec_2d
236 .iter()
237 .enumerate()
238 .for_each(|(a, entry_a)| {
239 entry_a.iter().enumerate().for_each(|(b, entry_ab)| {
240 entry_ab.iter().enumerate().for_each(|(i, entry_ab_i)| {
241 entry_ab_i.iter().enumerate().for_each(|(j, entry_ab_ij)| {
242 square_matrix[D * a + i][D * b + j] = *entry_ab_ij
243 })
244 })
245 })
246 });
247 square_matrix
248 }
249}
250
251impl From<SquareMatrix> for Vec<Vec<Scalar>> {
252 fn from(square_matrix: SquareMatrix) -> Self {
253 square_matrix
254 .into_iter()
255 .map(|vector| vector.into())
256 .collect()
257 }
258}
259
260impl FromIterator<Vector> for SquareMatrix {
261 fn from_iter<Ii: IntoIterator<Item = Vector>>(into_iterator: Ii) -> Self {
262 Self(Vec::from_iter(into_iterator))
263 }
264}
265
266impl Index<usize> for SquareMatrix {
267 type Output = Vector;
268 fn index(&self, index: usize) -> &Self::Output {
269 &self.0[index]
270 }
271}
272
273impl IndexMut<usize> for SquareMatrix {
274 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
275 &mut self.0[index]
276 }
277}
278
279impl Hessian for SquareMatrix {
280 fn entry(&self, row: usize, column: usize) -> Scalar {
281 self[row][column]
282 }
283 fn fill_into(self, square_matrix: &mut SquareMatrix) {
284 self.into_iter()
285 .zip(square_matrix.iter_mut())
286 .for_each(|(self_i, square_matrix_i)| {
287 self_i
288 .into_iter()
289 .zip(square_matrix_i.iter_mut())
290 .for_each(|(self_ij, square_matrix_ij)| *square_matrix_ij = self_ij)
291 });
292 }
293}
294
295impl Rank2 for SquareMatrix {
296 type Transpose = Self;
297 fn deviatoric(&self) -> Self {
298 let len = self.len();
299 let scale = -self.trace() / len as Scalar;
300 (0..len)
301 .map(|i| {
302 (0..len)
303 .map(|j| ((i == j) as u8) as Scalar * scale)
304 .collect()
305 })
306 .collect::<Self>()
307 + self
308 }
309 fn deviatoric_and_trace(&self) -> (Self, Scalar) {
310 let len = self.len();
311 let trace = self.trace();
312 let scale = -trace / len as Scalar;
313 (
314 (0..len)
315 .map(|i| {
316 (0..len)
317 .map(|j| ((i == j) as u8) as Scalar * scale)
318 .collect()
319 })
320 .collect::<Self>()
321 + self,
322 trace,
323 )
324 }
325 fn is_diagonal(&self) -> bool {
326 self.iter()
327 .enumerate()
328 .map(|(i, self_i)| {
329 self_i
330 .iter()
331 .enumerate()
332 .map(|(j, self_ij)| (self_ij == &0.0) as u8 * (i != j) as u8)
333 .sum::<u8>()
334 })
335 .sum::<u8>()
336 == (self.len().pow(2) - self.len()) as u8
337 }
338 fn is_identity(&self) -> bool {
339 self.iter().enumerate().all(|(i, self_i)| {
340 self_i
341 .iter()
342 .enumerate()
343 .all(|(j, self_ij)| self_ij == &((i == j) as u8 as Scalar))
344 })
345 }
346 fn is_symmetric(&self) -> bool {
347 self.iter().enumerate().all(|(i, self_i)| {
348 self_i
349 .iter()
350 .zip(self.iter())
351 .all(|(self_ij, self_j)| self_ij == &self_j[i])
352 })
353 }
354 fn squared_trace(&self) -> Scalar {
355 self.iter()
356 .enumerate()
357 .map(|(i, self_i)| {
358 self_i
359 .iter()
360 .zip(self.iter())
361 .map(|(self_ij, self_j)| self_ij * self_j[i])
362 .sum::<Scalar>()
363 })
364 .sum()
365 }
366 fn trace(&self) -> Scalar {
367 self.iter().enumerate().map(|(i, self_i)| self_i[i]).sum()
368 }
369 fn transpose(&self) -> Self::Transpose {
370 (0..self.len())
371 .map(|i| (0..self.len()).map(|j| self[j][i]).collect())
372 .collect()
373 }
374}
375
376impl Tensor for SquareMatrix {
377 type Item = Vector;
378 fn iter(&self) -> impl Iterator<Item = &Self::Item> {
379 self.0.iter()
380 }
381 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
382 self.0.iter_mut()
383 }
384 fn len(&self) -> usize {
385 self.0.len()
386 }
387 fn size(&self) -> usize {
388 unimplemented!("Do not like that inner Vecs could be different sizes")
389 }
390}
391
392impl IntoIterator for SquareMatrix {
393 type Item = Vector;
394 type IntoIter = IntoIter<Self::Item>;
395 fn into_iter(self) -> Self::IntoIter {
396 self.0.into_iter()
397 }
398}
399
400impl TensorVec for SquareMatrix {
401 type Item = Vector;
402 fn append(&mut self, other: &mut Self) {
403 self.0.append(&mut other.0)
404 }
405 fn capacity(&self) -> usize {
406 self.0.capacity()
407 }
408 fn is_empty(&self) -> bool {
409 self.0.is_empty()
410 }
411 fn new() -> Self {
412 Self(Vec::new())
413 }
414 fn push(&mut self, item: Self::Item) {
415 self.0.push(item)
416 }
417 fn remove(&mut self, index: usize) -> Self::Item {
418 self.0.remove(index)
419 }
420 fn reserve(&mut self, additional: usize) {
421 self.0.reserve(additional)
422 }
423 fn retain<F>(&mut self, f: F)
424 where
425 F: FnMut(&Self::Item) -> bool,
426 {
427 self.0.retain(f)
428 }
429 fn swap_remove(&mut self, index: usize) -> Self::Item {
430 self.0.swap_remove(index)
431 }
432 fn with_capacity(capacity: usize) -> Self {
433 Self(Vec::with_capacity(capacity))
434 }
435}
436
437impl Sum for SquareMatrix {
438 fn sum<Ii>(iter: Ii) -> Self
439 where
440 Ii: Iterator<Item = Self>,
441 {
442 iter.reduce(|mut acc, item| {
443 acc += item;
444 acc
445 })
446 .unwrap_or_else(Self::default)
447 }
448}
449
450impl Div<Scalar> for SquareMatrix {
451 type Output = Self;
452 fn div(mut self, tensor_rank_0: Scalar) -> Self::Output {
453 self /= &tensor_rank_0;
454 self
455 }
456}
457
458impl Div<&Scalar> for SquareMatrix {
459 type Output = Self;
460 fn div(mut self, tensor_rank_0: &Scalar) -> Self::Output {
461 self /= tensor_rank_0;
462 self
463 }
464}
465
466impl DivAssign<Scalar> for SquareMatrix {
467 fn div_assign(&mut self, tensor_rank_0: Scalar) {
468 self.iter_mut().for_each(|entry| *entry /= &tensor_rank_0);
469 }
470}
471
472impl DivAssign<&Scalar> for SquareMatrix {
473 fn div_assign(&mut self, tensor_rank_0: &Scalar) {
474 self.iter_mut().for_each(|entry| *entry /= tensor_rank_0);
475 }
476}
477
478impl Mul<Scalar> for SquareMatrix {
479 type Output = Self;
480 fn mul(mut self, tensor_rank_0: Scalar) -> Self::Output {
481 self *= &tensor_rank_0;
482 self
483 }
484}
485
486impl Mul<&Scalar> for SquareMatrix {
487 type Output = Self;
488 fn mul(mut self, tensor_rank_0: &Scalar) -> Self::Output {
489 self *= tensor_rank_0;
490 self
491 }
492}
493
494impl Mul<&Scalar> for &SquareMatrix {
495 type Output = SquareMatrix;
496 fn mul(self, tensor_rank_0: &Scalar) -> Self::Output {
497 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
498 }
499}
500
501impl MulAssign<Scalar> for SquareMatrix {
502 fn mul_assign(&mut self, tensor_rank_0: Scalar) {
503 self.iter_mut().for_each(|entry| *entry *= &tensor_rank_0);
504 }
505}
506
507impl MulAssign<&Scalar> for SquareMatrix {
508 fn mul_assign(&mut self, tensor_rank_0: &Scalar) {
509 self.iter_mut().for_each(|entry| *entry *= tensor_rank_0);
510 }
511}
512
513impl Mul<Vector> for SquareMatrix {
514 type Output = Vector;
515 fn mul(self, vector: Vector) -> Self::Output {
516 self.iter().map(|self_i| self_i * &vector).collect()
517 }
518}
519
520impl Mul<&Vector> for SquareMatrix {
521 type Output = Vector;
522 fn mul(self, vector: &Vector) -> Self::Output {
523 self.iter().map(|self_i| self_i * vector).collect()
524 }
525}
526
527impl Add for SquareMatrix {
528 type Output = Self;
529 fn add(mut self, vector: Self) -> Self::Output {
530 self += vector;
531 self
532 }
533}
534
535impl Add<&Self> for SquareMatrix {
536 type Output = Self;
537 fn add(mut self, vector: &Self) -> Self::Output {
538 self += vector;
539 self
540 }
541}
542
543impl AddAssign for SquareMatrix {
544 fn add_assign(&mut self, vector: Self) {
545 self.iter_mut()
546 .zip(vector.iter())
547 .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
548 }
549}
550
551impl AddAssign<&Self> for SquareMatrix {
552 fn add_assign(&mut self, vector: &Self) {
553 self.iter_mut()
554 .zip(vector.iter())
555 .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
556 }
557}
558
559impl Mul for SquareMatrix {
560 type Output = Self;
561 fn mul(self, matrix: Self) -> Self::Output {
562 let mut output = Self::zero(matrix.len());
563 self.iter()
564 .zip(output.iter_mut())
565 .for_each(|(self_i, output_i)| {
566 self_i
567 .iter()
568 .zip(matrix.iter())
569 .for_each(|(self_ij, matrix_j)| *output_i += matrix_j * self_ij)
570 });
571 output
572 }
573}
574
575impl Sub for SquareMatrix {
576 type Output = Self;
577 fn sub(mut self, square_matrix: Self) -> Self::Output {
578 self -= square_matrix;
579 self
580 }
581}
582
583impl Sub<&Self> for SquareMatrix {
584 type Output = Self;
585 fn sub(mut self, square_matrix: &Self) -> Self::Output {
586 self -= square_matrix;
587 self
588 }
589}
590
591impl Sub for &SquareMatrix {
592 type Output = SquareMatrix;
593 fn sub(self, square_matrix: Self) -> Self::Output {
594 square_matrix
595 .iter()
596 .zip(self.iter())
597 .map(|(square_matrix_i, self_i)| self_i - square_matrix_i)
598 .collect()
599 }
600}
601
602impl SubAssign for SquareMatrix {
603 fn sub_assign(&mut self, square_matrix: Self) {
604 self.iter_mut()
605 .zip(square_matrix.iter())
606 .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
607 }
608}
609
610impl SubAssign<&Self> for SquareMatrix {
611 fn sub_assign(&mut self, square_matrix: &Self) {
612 self.iter_mut()
613 .zip(square_matrix.iter())
614 .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
615 }
616}