conspire/math/matrix/square/
mod.rs1#[cfg(test)]
2mod test;
3
4#[cfg(test)]
5use crate::math::test::ErrorTensor;
6
7use crate::{
8 ABS_TOL,
9 math::{
10 Hessian, Rank2, Scalar, Tensor, TensorRank2Vec2D, TensorVec, Vector, write_tensor_rank_0,
11 },
12};
13use std::{
14 collections::VecDeque,
15 fmt::{self, Display, Formatter},
16 iter::Sum,
17 ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
18 vec::IntoIter,
19};
20
21pub struct Banded {
23 bandwidth: usize,
24 inverse: Vec<usize>,
25 mapping: Vec<usize>,
26}
27
28impl Banded {
29 pub fn map(&self, old: usize) -> usize {
30 self.inverse[old]
31 }
32 pub fn old(&self, new: usize) -> usize {
33 self.mapping[new]
34 }
35 pub fn width(&self) -> usize {
36 self.bandwidth
37 }
38}
39
40impl From<Vec<Vec<bool>>> for Banded {
41 fn from(structure: Vec<Vec<bool>>) -> Self {
42 let num = structure.len();
43 structure.iter().enumerate().for_each(|(i, row_i)| {
44 assert_eq!(row_i.len(), num);
45 row_i
46 .iter()
47 .zip(structure.iter())
48 .for_each(|(entry_ij, row_j)| assert_eq!(&row_j[i], entry_ij))
49 });
50 let mut adj_list = vec![Vec::new(); num];
51 (0..num).for_each(|i| {
52 (0..num)
53 .filter(|&j| structure[i][j] && i != j)
54 .for_each(|j| adj_list[i].push(j))
55 });
56 let start_vertex = (0..num)
57 .min_by_key(|&i| adj_list[i].len())
58 .expect("Matrix must have at least one entry.");
59 let mut visited = vec![false; num];
60 let mut mapping = Vec::new();
61 let mut queue = VecDeque::new();
62 queue.push_back(start_vertex);
63 visited[start_vertex] = true;
64 while let Some(vertex) = queue.pop_front() {
65 mapping.push(vertex);
66 let mut neighbors: Vec<usize> = adj_list[vertex]
67 .iter()
68 .filter(|&&neighbor| !visited[neighbor])
69 .copied()
70 .collect();
71 neighbors.sort_by_key(|&neighbor| adj_list[neighbor].len());
72 for neighbor in neighbors {
73 visited[neighbor] = true;
74 queue.push_back(neighbor);
75 }
76 }
77 mapping.reverse();
78 let mut inverse = vec![0; num];
79 mapping
80 .iter()
81 .enumerate()
82 .for_each(|(new, &old)| inverse[old] = new);
83 let mut bandwidth = 0;
84 (0..num).for_each(|i| {
85 (i + 1..num)
86 .filter(|&j| structure[mapping[i]][mapping[j]])
87 .for_each(|j| bandwidth = bandwidth.max(j - i))
88 });
89 Self {
90 bandwidth,
91 mapping,
92 inverse,
93 }
94 }
95}
96
97#[derive(Debug, PartialEq)]
99pub enum SquareMatrixError {
100 Singular,
101}
102
103#[derive(Clone, Debug, PartialEq)]
105pub struct SquareMatrix(Vec<Vector>);
106
107impl Default for SquareMatrix {
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113impl SquareMatrix {
114 pub fn solve_lu(&self, b: &Vector) -> Result<Vector, SquareMatrixError> {
191 let n = self.len();
192 let mut p: Vec<usize> = (0..n).collect();
193 let mut factor;
194 let mut lu = self.clone();
195 let mut max_row;
196 let mut max_val;
197 let mut pivot;
198 for i in 0..n {
199 max_row = i;
200 max_val = lu[max_row][i].abs();
201 for k in i + 1..n {
202 if lu[k][i].abs() > max_val {
203 max_row = k;
204 max_val = lu[max_row][i].abs();
205 }
206 }
207 if max_row != i {
208 lu.0.swap(i, max_row);
209 p.swap(i, max_row);
210 }
211 pivot = lu[i][i];
212 if pivot.abs() < ABS_TOL {
213 return Err(SquareMatrixError::Singular);
214 }
215 for j in i + 1..n {
216 if lu[j][i] != 0.0 {
217 lu[j][i] /= pivot;
218 factor = lu[j][i];
219 for k in i + 1..n {
220 lu[j][k] -= factor * lu[i][k];
221 }
222 }
223 }
224 }
225 let mut x: Vector = p.into_iter().map(|p_i| b[p_i]).collect();
226 forward_substitution(&mut x, &lu);
227 backward_substitution(&mut x, &lu);
228 Ok(x)
229 }
230 pub fn solve_lu_banded(
232 &self,
233 b: &Vector,
234 banded: &Banded,
235 ) -> Result<Vector, SquareMatrixError> {
236 let bandwidth = banded.width();
237 let mut bandwidth_updated;
238 let n = self.len();
239 let mut p: Vec<usize> = (0..n).collect();
240 let mut end;
241 let mut factor;
242 let mut max_row;
243 let mut max_val;
244 let mut pivot;
245 let mut rearr: Self = (0..n)
246 .map(|i| (0..n).map(|j| self[banded.old(i)][banded.old(j)]).collect())
247 .collect();
248 for i in 0..n {
249 end = n.min(i + 1 + bandwidth);
250 pivot = rearr[i][i];
251 if pivot.abs() < ABS_TOL {
252 max_row = i;
253 max_val = rearr[max_row][i].abs();
254 for k in i + 1..end {
255 if rearr[k][i].abs() > max_val {
256 max_row = k;
257 max_val = rearr[max_row][i].abs();
258 }
259 }
260 if max_row != i {
261 rearr.0.swap(i, max_row);
262 p.swap(i, max_row);
263 pivot = rearr[i][i];
264 if pivot.abs() < ABS_TOL {
265 return Err(SquareMatrixError::Singular);
266 }
267 }
268 }
269 bandwidth_updated = bandwidth;
270 (i + 1 + bandwidth..n).for_each(|j| {
271 if rearr[i][j] != 0.0 {
272 bandwidth_updated = bandwidth_updated.max(j - i)
273 }
274 });
275 end = n.min(i + 1 + bandwidth_updated);
276 for j in i + 1..end {
277 if rearr[j][i] != 0.0 {
278 rearr[j][i] /= pivot;
279 factor = rearr[j][i];
280 for k in i + 1..end {
281 rearr[j][k] -= factor * rearr[i][k];
282 }
283 }
284 }
285 }
286 let mut x: Vector = p.into_iter().map(|p_i| b[banded.old(p_i)]).collect();
287 forward_substitution(&mut x, &rearr);
288 backward_substitution(&mut x, &rearr);
289 Ok((0..n).map(|i| x[banded.map(i)]).collect())
290 }
291 pub fn zero(len: usize) -> Self {
292 (0..len).map(|_| Vector::zero(len)).collect()
293 }
294}
295
296fn forward_substitution(x: &mut Vector, a: &SquareMatrix) {
297 a.iter().enumerate().for_each(|(i, a_i)| {
298 x[i] -= a_i
299 .iter()
300 .take(i)
301 .zip(x.iter().take(i))
302 .map(|(a_ij, x_j)| a_ij * x_j)
303 .sum::<Scalar>()
304 })
305}
306
307fn backward_substitution(x: &mut Vector, a: &SquareMatrix) {
308 a.0.iter().enumerate().rev().for_each(|(i, a_i)| {
309 x[i] -= a_i
310 .iter()
311 .skip(i + 1)
312 .zip(x.iter().skip(i + 1))
313 .map(|(a_ij, x_j)| a_ij * x_j)
314 .sum::<Scalar>();
315 x[i] /= a_i[i];
316 })
317}
318
319#[cfg(test)]
320impl ErrorTensor for SquareMatrix {
321 fn error_fd(&self, comparator: &Self, epsilon: Scalar) -> Option<(bool, usize)> {
322 let error_count = self
323 .iter()
324 .zip(comparator.iter())
325 .map(|(self_i, comparator_i)| {
326 self_i
327 .iter()
328 .zip(comparator_i.iter())
329 .filter(|&(&self_ij, &comparator_ij)| {
330 (self_ij / comparator_ij - 1.0).abs() >= epsilon
331 && (self_ij.abs() >= epsilon || comparator_ij.abs() >= epsilon)
332 })
333 .count()
334 })
335 .sum();
336 if error_count > 0 {
337 Some((true, error_count))
338 } else {
339 None
340 }
341 }
342}
343
344impl Display for SquareMatrix {
345 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
346 write!(f, "\x1B[s")?;
347 write!(f, "[[")?;
348 self.iter().enumerate().try_for_each(|(i, row)| {
349 row.iter()
350 .try_for_each(|entry| write_tensor_rank_0(f, entry))?;
351 if i + 1 < self.len() {
352 writeln!(f, "\x1B[2D],")?;
353 write!(f, "\x1B[u")?;
354 write!(f, "\x1B[{}B [", i + 1)?;
355 }
356 Ok(())
357 })?;
358 write!(f, "\x1B[2D]]")
359 }
360}
361
362impl<const N: usize> From<[[Scalar; N]; N]> for SquareMatrix {
363 fn from(array: [[Scalar; N]; N]) -> Self {
364 array.into_iter().map(Vector::from).collect()
365 }
366}
367
368impl<const D: usize, const I: usize, const J: usize> From<TensorRank2Vec2D<D, I, J>>
369 for SquareMatrix
370{
371 fn from(tensor_rank_2_vec_2d: TensorRank2Vec2D<D, I, J>) -> Self {
372 let mut square_matrix = Self::zero(tensor_rank_2_vec_2d.len() * D);
373 tensor_rank_2_vec_2d
374 .iter()
375 .enumerate()
376 .for_each(|(a, entry_a)| {
377 entry_a.iter().enumerate().for_each(|(b, entry_ab)| {
378 entry_ab.iter().enumerate().for_each(|(i, entry_ab_i)| {
379 entry_ab_i.iter().enumerate().for_each(|(j, entry_ab_ij)| {
380 square_matrix[D * a + i][D * b + j] = *entry_ab_ij
381 })
382 })
383 })
384 });
385 square_matrix
386 }
387}
388
389impl FromIterator<Vector> for SquareMatrix {
390 fn from_iter<Ii: IntoIterator<Item = Vector>>(into_iterator: Ii) -> Self {
391 Self(Vec::from_iter(into_iterator))
392 }
393}
394
395impl Index<usize> for SquareMatrix {
396 type Output = Vector;
397 fn index(&self, index: usize) -> &Self::Output {
398 &self.0[index]
399 }
400}
401
402impl IndexMut<usize> for SquareMatrix {
403 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
404 &mut self.0[index]
405 }
406}
407
408impl Hessian for SquareMatrix {
409 fn fill_into(self, square_matrix: &mut SquareMatrix) {
410 self.into_iter()
411 .zip(square_matrix.iter_mut())
412 .for_each(|(self_i, square_matrix_i)| {
413 self_i
414 .into_iter()
415 .zip(square_matrix_i.iter_mut())
416 .for_each(|(self_ij, square_matrix_ij)| *square_matrix_ij = self_ij)
417 });
418 }
419}
420
421impl Rank2 for SquareMatrix {
422 type Transpose = Self;
423 fn deviatoric(&self) -> Self {
424 let len = self.len();
425 let scale = -self.trace() / len as Scalar;
426 (0..len)
427 .map(|i| {
428 (0..len)
429 .map(|j| ((i == j) as u8) as Scalar * scale)
430 .collect()
431 })
432 .collect::<Self>()
433 + self
434 }
435 fn deviatoric_and_trace(&self) -> (Self, Scalar) {
436 let len = self.len();
437 let trace = self.trace();
438 let scale = -trace / len as Scalar;
439 (
440 (0..len)
441 .map(|i| {
442 (0..len)
443 .map(|j| ((i == j) as u8) as Scalar * scale)
444 .collect()
445 })
446 .collect::<Self>()
447 + self,
448 trace,
449 )
450 }
451 fn is_diagonal(&self) -> bool {
452 self.iter()
453 .enumerate()
454 .map(|(i, self_i)| {
455 self_i
456 .iter()
457 .enumerate()
458 .map(|(j, self_ij)| (self_ij == &0.0) as u8 * (i != j) as u8)
459 .sum::<u8>()
460 })
461 .sum::<u8>()
462 == (self.len().pow(2) - self.len()) as u8
463 }
464 fn is_identity(&self) -> bool {
465 self.iter().enumerate().all(|(i, self_i)| {
466 self_i
467 .iter()
468 .enumerate()
469 .all(|(j, self_ij)| self_ij == &((i == j) as u8 as Scalar))
470 })
471 }
472 fn is_symmetric(&self) -> bool {
473 self.iter().enumerate().all(|(i, self_i)| {
474 self_i
475 .iter()
476 .zip(self.iter())
477 .all(|(self_ij, self_j)| self_ij == &self_j[i])
478 })
479 }
480 fn squared_trace(&self) -> Scalar {
481 self.iter()
482 .enumerate()
483 .map(|(i, self_i)| {
484 self_i
485 .iter()
486 .zip(self.iter())
487 .map(|(self_ij, self_j)| self_ij * self_j[i])
488 .sum::<Scalar>()
489 })
490 .sum()
491 }
492 fn trace(&self) -> Scalar {
493 self.iter().enumerate().map(|(i, self_i)| self_i[i]).sum()
494 }
495 fn transpose(&self) -> Self::Transpose {
496 (0..self.len())
497 .map(|i| (0..self.len()).map(|j| self[j][i]).collect())
498 .collect()
499 }
500}
501
502impl Tensor for SquareMatrix {
503 type Item = Vector;
504 fn iter(&self) -> impl Iterator<Item = &Self::Item> {
505 self.0.iter()
506 }
507 fn iter_mut(&mut self) -> impl Iterator<Item = &mut Self::Item> {
508 self.0.iter_mut()
509 }
510 fn len(&self) -> usize {
511 self.0.len()
512 }
513 fn size(&self) -> usize {
514 unimplemented!("Do not like that inner Vecs could be different sizes")
515 }
516}
517
518impl IntoIterator for SquareMatrix {
519 type Item = Vector;
520 type IntoIter = IntoIter<Self::Item>;
521 fn into_iter(self) -> Self::IntoIter {
522 self.0.into_iter()
523 }
524}
525
526impl TensorVec for SquareMatrix {
527 type Item = Vector;
528 fn append(&mut self, other: &mut Self) {
529 self.0.append(&mut other.0)
530 }
531 fn capacity(&self) -> usize {
532 self.0.capacity()
533 }
534 fn is_empty(&self) -> bool {
535 self.0.is_empty()
536 }
537 fn new() -> Self {
538 Self(Vec::new())
539 }
540 fn push(&mut self, item: Self::Item) {
541 self.0.push(item)
542 }
543 fn remove(&mut self, index: usize) -> Self::Item {
544 self.0.remove(index)
545 }
546 fn retain<F>(&mut self, f: F)
547 where
548 F: FnMut(&Self::Item) -> bool,
549 {
550 self.0.retain(f)
551 }
552 fn swap_remove(&mut self, index: usize) -> Self::Item {
553 self.0.swap_remove(index)
554 }
555}
556
557impl Sum for SquareMatrix {
558 fn sum<Ii>(iter: Ii) -> Self
559 where
560 Ii: Iterator<Item = Self>,
561 {
562 iter.reduce(|mut acc, item| {
563 acc += item;
564 acc
565 })
566 .unwrap_or_else(Self::default)
567 }
568}
569
570impl Div<Scalar> for SquareMatrix {
571 type Output = Self;
572 fn div(mut self, tensor_rank_0: Scalar) -> Self::Output {
573 self /= &tensor_rank_0;
574 self
575 }
576}
577
578impl Div<&Scalar> for SquareMatrix {
579 type Output = Self;
580 fn div(mut self, tensor_rank_0: &Scalar) -> Self::Output {
581 self /= tensor_rank_0;
582 self
583 }
584}
585
586impl DivAssign<Scalar> for SquareMatrix {
587 fn div_assign(&mut self, tensor_rank_0: Scalar) {
588 self.iter_mut().for_each(|entry| *entry /= &tensor_rank_0);
589 }
590}
591
592impl DivAssign<&Scalar> for SquareMatrix {
593 fn div_assign(&mut self, tensor_rank_0: &Scalar) {
594 self.iter_mut().for_each(|entry| *entry /= tensor_rank_0);
595 }
596}
597
598impl Mul<Scalar> for SquareMatrix {
599 type Output = Self;
600 fn mul(mut self, tensor_rank_0: Scalar) -> Self::Output {
601 self *= &tensor_rank_0;
602 self
603 }
604}
605
606impl Mul<&Scalar> for SquareMatrix {
607 type Output = Self;
608 fn mul(mut self, tensor_rank_0: &Scalar) -> Self::Output {
609 self *= tensor_rank_0;
610 self
611 }
612}
613
614impl Mul<&Scalar> for &SquareMatrix {
615 type Output = SquareMatrix;
616 fn mul(self, tensor_rank_0: &Scalar) -> Self::Output {
617 self.iter().map(|self_i| self_i * tensor_rank_0).collect()
618 }
619}
620
621impl MulAssign<Scalar> for SquareMatrix {
622 fn mul_assign(&mut self, tensor_rank_0: Scalar) {
623 self.iter_mut().for_each(|entry| *entry *= &tensor_rank_0);
624 }
625}
626
627impl MulAssign<&Scalar> for SquareMatrix {
628 fn mul_assign(&mut self, tensor_rank_0: &Scalar) {
629 self.iter_mut().for_each(|entry| *entry *= tensor_rank_0);
630 }
631}
632
633impl Mul<Vector> for SquareMatrix {
634 type Output = Vector;
635 fn mul(self, vector: Vector) -> Self::Output {
636 self.iter().map(|self_i| self_i * &vector).collect()
637 }
638}
639
640impl Mul<&Vector> for SquareMatrix {
641 type Output = Vector;
642 fn mul(self, vector: &Vector) -> Self::Output {
643 self.iter().map(|self_i| self_i * vector).collect()
644 }
645}
646
647impl Add for SquareMatrix {
648 type Output = Self;
649 fn add(mut self, vector: Self) -> Self::Output {
650 self += vector;
651 self
652 }
653}
654
655impl Add<&Self> for SquareMatrix {
656 type Output = Self;
657 fn add(mut self, vector: &Self) -> Self::Output {
658 self += vector;
659 self
660 }
661}
662
663impl AddAssign for SquareMatrix {
664 fn add_assign(&mut self, vector: Self) {
665 self.iter_mut()
666 .zip(vector.iter())
667 .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
668 }
669}
670
671impl AddAssign<&Self> for SquareMatrix {
672 fn add_assign(&mut self, vector: &Self) {
673 self.iter_mut()
674 .zip(vector.iter())
675 .for_each(|(self_entry, tensor_rank_1)| *self_entry += tensor_rank_1);
676 }
677}
678
679impl Mul for SquareMatrix {
680 type Output = Self;
681 fn mul(self, matrix: Self) -> Self::Output {
682 let mut output = Self::zero(matrix.len());
683 self.iter()
684 .zip(output.iter_mut())
685 .for_each(|(self_i, output_i)| {
686 self_i
687 .iter()
688 .zip(matrix.iter())
689 .for_each(|(self_ij, matrix_j)| *output_i += matrix_j * self_ij)
690 });
691 output
692 }
693}
694
695impl Sub for SquareMatrix {
696 type Output = Self;
697 fn sub(mut self, square_matrix: Self) -> Self::Output {
698 self -= square_matrix;
699 self
700 }
701}
702
703impl Sub<&Self> for SquareMatrix {
704 type Output = Self;
705 fn sub(mut self, square_matrix: &Self) -> Self::Output {
706 self -= square_matrix;
707 self
708 }
709}
710
711impl Sub for &SquareMatrix {
712 type Output = SquareMatrix;
713 fn sub(self, square_matrix: Self) -> Self::Output {
714 square_matrix
715 .iter()
716 .zip(self.iter())
717 .map(|(square_matrix_i, self_i)| self_i - square_matrix_i)
718 .collect()
719 }
720}
721
722impl SubAssign for SquareMatrix {
723 fn sub_assign(&mut self, square_matrix: Self) {
724 self.iter_mut()
725 .zip(square_matrix.iter())
726 .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
727 }
728}
729
730impl SubAssign<&Self> for SquareMatrix {
731 fn sub_assign(&mut self, square_matrix: &Self) {
732 self.iter_mut()
733 .zip(square_matrix.iter())
734 .for_each(|(self_entry, tensor_rank_1)| *self_entry -= tensor_rank_1);
735 }
736}