Skip to main content

diffsol_la/linear_solver/nalgebra/
lu.rs

1use nalgebra::Dyn;
2
3use crate::{
4    error::LaError, linear_solver_error, matrix::dense_nalgebra_serial::NalgebraMat, LinearOp,
5    LinearSolver, Matrix, NalgebraContext, NalgebraScalar, NalgebraVec,
6};
7
8/// A [LinearSolver] that uses the LU decomposition in the [`nalgebra` library](https://nalgebra.org/) to solve the linear system.
9#[derive(Clone)]
10pub struct LU<T>
11where
12    T: NalgebraScalar,
13{
14    matrix: Option<NalgebraMat<T>>,
15    lu: Option<nalgebra::LU<T, Dyn, Dyn>>,
16}
17
18impl<T> Default for LU<T>
19where
20    T: NalgebraScalar,
21{
22    fn default() -> Self {
23        Self {
24            lu: None,
25            matrix: None,
26        }
27    }
28}
29
30impl<T: NalgebraScalar> LinearSolver<NalgebraMat<T>> for LU<T> {
31    fn solve_in_place(&self, state: &mut NalgebraVec<T>) -> Result<(), LaError> {
32        if self.lu.is_none() {
33            return Err(linear_solver_error!(LuNotInitialized));
34        }
35        let lu = self.lu.as_ref().unwrap();
36        match lu.solve_mut(&mut state.data) {
37            true => Ok(()),
38            false => Err(linear_solver_error!(LuSolveFailed))?,
39        }
40    }
41
42    fn set_linearisation<
43        C: LinearOp<T = T, V = NalgebraVec<T>, M = NalgebraMat<T>, C = NalgebraContext>,
44    >(
45        &mut self,
46        op: &C,
47    ) {
48        let matrix = self.matrix.as_mut().expect("Matrix not set");
49        op.matrix_inplace(matrix);
50        self.lu = Some(matrix.data.clone().lu());
51    }
52
53    fn set_sparsity<
54        C: LinearOp<T = T, V = NalgebraVec<T>, M = NalgebraMat<T>, C = NalgebraContext>,
55    >(
56        &mut self,
57        op: &C,
58    ) {
59        let ncols = op.ncols();
60        let nrows = op.nrows();
61        let matrix = C::M::new_from_sparsity(nrows, ncols, op.sparsity(), *op.context());
62        self.matrix = Some(matrix);
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69    use crate::{linear_solver::tests::diagonal_op, Vector};
70
71    #[test]
72    fn test_lu() {
73        let mut s = LU::<f64>::default();
74        let op = diagonal_op::<NalgebraMat<f64>>(2.0);
75        s.set_sparsity(&op);
76        s.set_linearisation(&op);
77        let b = NalgebraVec::from_vec(vec![2.0, 4.0], Default::default());
78        let x = s.solve(&b).unwrap();
79        x.assert_eq_st(
80            &NalgebraVec::from_vec(vec![1.0, 2.0], Default::default()),
81            1e-10,
82        );
83    }
84}