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