trigivs 0.1.1

Rust library for solving tridiagonal systems of linear equations using Givens rotations
Documentation
use approx::assert_abs_diff_eq;
use crate::prelude::*;

#[test]
fn test_determinant(){
    let sup = [4., 7., 7., 100.];
    let diag = [1., 3., 6., 4., 12.];
    let sub = [2., 5., 10., 90.];

    let result = compute_tridiag_determinant(&sup, &diag, &sub);
    let expected = 586080.;

    assert_abs_diff_eq!(result, expected, epsilon=1e-6);
}

#[test]
fn test_1diag_solver(){
    let diag = [2.];
    let rhs = [10.];
    
    let result = solve_givens(&[], &diag, &[], &rhs).unwrap();
    let expected = [5.];

    assert_abs_diff_eq!(result.as_ref() as &[f64], expected.as_ref(), epsilon=1e-6);
}

#[test]
fn test_2diag_solver(){
    let sup = [-4.];
    let diag = [3., 2.];
    let sub = [5.];
    let rhs = [-3., 21.];
    
    let result = solve_givens(&sup, &diag, &sub, &rhs).unwrap();
    let expected = [3., 3.];

    assert_abs_diff_eq!(result.as_ref() as &[f64], expected.as_ref(), epsilon=1e-6);
}

#[test]
fn test_solver(){
    let sup = [4., 7., 7., 100.];
    let diag = [1., 3., 6., 4., 12.];
    let sub = [2., 5., 10., 90.];
    let rhs = [-7., 17., -20., 514., -300.];
    
    let result = solve_givens(&sup, &diag, &sub, &rhs).unwrap();
    let expected = [1., -2., 3., -4., 5.];

    assert_abs_diff_eq!(result.as_ref() as &[f64], expected.as_ref(), epsilon=1e-6);
}

#[test]
fn test_zero_division(){
    let sup = [4., 7., 0., 100.];
    let diag = [1., 3., 0., 4., 12.];
    let sub = [2., 0., 10., 90.];
    let rhs = [-7., 17., -20., 514., -300.];
    
    let result = solve_givens(&sup, &diag, &sub, &rhs);
    
    assert!(matches!(result, Err(SolverErrors::DivisionByZero)));
}

#[test]
fn test_1diag_precomp(){
    let diag = [2.];

    let rhs1 = [10.];
    let rhs2 = [-8.];
    
    let precomp = precompute_givens(&[], &diag, &[]).unwrap();

    let result1 = precomp.solve_givens_rhs(&rhs1).unwrap();
    let result2 = precomp.solve_givens_rhs(&rhs2).unwrap();

    let expected1 = [5.];
    let expected2 = [-4.];

    assert_abs_diff_eq!(result1.as_ref() as &[f64], expected1.as_ref(), epsilon=1e-6);
    assert_abs_diff_eq!(result2.as_ref() as &[f64], expected2.as_ref(), epsilon=1e-6);
}

#[test]
fn test_2diag_precomp(){
    let sup = [-4.];
    let diag = [3., 2.];
    let sub = [5.];

    let rhs1 = [-3., 21.];
    let rhs2  = [-23., 5.];
    
    let precomp = precompute_givens(&sup, &diag, &sub).unwrap();

    let result1 = precomp.solve_givens_rhs(&rhs1).unwrap();
    let result2 = precomp.solve_givens_rhs(&rhs2).unwrap();

    let expected1 = [3., 3.];
    let expected2 = [-1., 5.];

    assert_abs_diff_eq!(result1.as_ref() as &[f64], expected1.as_ref(), epsilon=1e-6);
    assert_abs_diff_eq!(result2.as_ref() as &[f64], expected2.as_ref(), epsilon=1e-6);
}

#[test]
fn test_precomp(){
    let sup = [4., 7., 7., 100.];
    let diag = [1., 3., 6., 4., 12.];
    let sub = [2., 5., 10., 90.];
    
    let rhs1 = [-7., 17., -20., 514., -300.];
    let rhs2 = [43., 57., -72., 450., -1740.];
    
    let precomp = precompute_givens(&sup, &diag, &sub).unwrap();
    
    let result1 = precomp.solve_givens_rhs(&rhs1).unwrap();
    let result2 = precomp.solve_givens_rhs(&rhs2).unwrap();

    let expected1 = [1., -2., 3., -4., 5.];
    let expected2 = [3., 10., 3., -20., 5.];

    assert_abs_diff_eq!(result1.as_ref() as &[f64], expected1.as_ref(), epsilon=1e-6);
    assert_abs_diff_eq!(result2.as_ref() as &[f64], expected2.as_ref(), epsilon=1e-6);
}

#[test]
fn test_precom_direct_eq_solver(){
    let sup = [4., 7., 7., 100.];
    let diag = [1., 3., 6., 4., 12.];
    let sub = [2., 5., 10., 90.];
    let rhs = [-7., 17., -20., 514., -300.];
    
    let precomp = precompute_givens(&sup, &diag, &sub).unwrap();

    let result1 = solve_givens(&sup, &diag, &sub, &rhs).unwrap();
    let result2 = precomp.solve_givens_rhs(&rhs).unwrap();

    assert_abs_diff_eq!(result1.as_ref() as &[f64], result2.as_ref(), epsilon=1e-6);
}

#[cfg(feature = "alloc")]
#[test]
fn test_invalid_diag(){
    let sup = [4., 7., 7., 100.];
    let diag = [1., 3., 6., 4., 12.];
    let sub = [2., 5., 10.];
    let rhs = [-7., 17., -20., 514., -300.];

    let result = solve_givens(&sup, &diag, &sub, &rhs);

    assert!(matches!(result, Err(SolverErrors::InvalidDiagonals)));
}

#[cfg(feature = "alloc")]
#[test]
fn test_invalid_rhs(){
    let sup = [4., 7., 7., 100.];
    let diag = [1., 3., 6., 4., 12.];
    let sub = [2., 5., 10., 90.];
    let rhs = [-7., 17., -20., 514.];
    
    let result = solve_givens(&sup, &diag, &sub, &rhs);

    assert!(matches!(result, Err(SolverErrors::InvalidRhsSizing)));
}

#[cfg(feature = "alloc")]
#[test]
fn test_invalid_diag_precomp(){
    let sup = [4., 7., 7., 100.];
    let diag = [1., 3., 6., 4., 12.];
    let sub = [2., 5., 10.];

    let result = precompute_givens(&sup, &diag, &sub);

    assert!(matches!(result, Err(SolverErrors::InvalidDiagonals)));
}

#[cfg(feature = "alloc")]
#[test]
fn test_invalid_rhs_precomp(){
    let sup = [4., 7., 7., 100.];
    let diag = [1., 3., 6., 4., 12.];
    let sub = [2., 5., 10., 90.];
    
    let rhs = [-7., 17., -20., 514.];
    
    let precomp = precompute_givens(&sup, &diag, &sub).unwrap();
    let result = precomp.solve_givens_rhs(&rhs);

    assert!(matches!(result, Err(SolverErrors::InvalidRhsSizing)));
}