1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::fmt;
7
8use use_matrix::Matrix2;
9use use_vector::Vector2;
10
11#[derive(Clone, Copy, Debug, PartialEq)]
13pub enum LinearError {
14 SingularMatrix { determinant: f64 },
16}
17
18impl fmt::Display for LinearError {
19 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
20 match self {
21 Self::SingularMatrix { determinant } => {
22 write!(
23 formatter,
24 "matrix is singular with determinant {determinant}"
25 )
26 },
27 }
28 }
29}
30
31impl std::error::Error for LinearError {}
32
33pub fn solve_2x2(matrix: Matrix2, rhs: Vector2) -> Result<Vector2, LinearError> {
54 let determinant = matrix.determinant();
55
56 matrix
57 .inverse()
58 .map(|inverse| inverse * rhs)
59 .ok_or(LinearError::SingularMatrix { determinant })
60}
61
62pub mod prelude;
63
64#[cfg(test)]
65mod tests {
66 use super::{LinearError, solve_2x2};
67 use use_matrix::Matrix2;
68 use use_vector::Vector2;
69
70 #[test]
71 fn solves_nonsingular_systems_and_rejects_unusable_ones() {
72 let matrix = Matrix2::new(2.0, 1.0, 5.0, 3.0);
73 let rhs = Vector2::new(1.0, 2.0);
74 let solution = solve_2x2(matrix, rhs).expect("system should solve");
75
76 assert_eq!(solution, Vector2::new(1.0, -1.0));
77 assert_eq!(matrix * solution, rhs);
78 assert_eq!(
79 solve_2x2(Matrix2::new(1.0, 2.0, 2.0, 4.0), Vector2::new(1.0, 2.0)),
80 Err(LinearError::SingularMatrix { determinant: 0.0 })
81 );
82 assert!(matches!(
83 solve_2x2(
84 Matrix2::new(f64::INFINITY, 0.0, 0.0, 1.0),
85 Vector2::new(1.0, 2.0)
86 ),
87 Err(LinearError::SingularMatrix { determinant }) if !determinant.is_finite()
88 ));
89 }
90}