#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct LinearSolveTiming {
pub factorization: Duration,
pub rhs_solve: Duration,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BvpLinearSolveError {
DimensionMismatch {
matrix_rows: usize,
matrix_columns: usize,
rhs_len: usize,
},
UnsupportedLinearPolicy {
backend: &'static str,
policy: String,
},
VectorTypeMismatch {
backend: &'static str,
expected: &'static str,
},
FactorizationFailed {
backend: &'static str,
message: String,
},
SolveFailed {
backend: &'static str,
message: String,
},
LegacyPanic {
backend: &'static str,
message: String,
},
}
impl std::fmt::Display for BvpLinearSolveError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::DimensionMismatch {
matrix_rows,
matrix_columns,
rhs_len,
} => write!(
f,
"linear system dimension mismatch: matrix={matrix_rows}x{matrix_columns}, rhs={rhs_len}"
),
Self::UnsupportedLinearPolicy { backend, policy } => {
write!(
f,
"backend {backend} does not support linear policy {policy:?}"
)
}
Self::VectorTypeMismatch { backend, expected } => {
write!(f, "backend {backend} requires vector type {expected}")
}
Self::FactorizationFailed { backend, message } => {
write!(f, "backend {backend} factorization failed: {message}")
}
Self::SolveFailed { backend, message } => {
write!(f, "backend {backend} solve failed: {message}")
}
Self::LegacyPanic { backend, message } => {
write!(
f,
"backend {backend} panicked in compatibility solve: {message}"
)
}
}
}
}
impl std::error::Error for BvpLinearSolveError {}
fn panic_message(payload: Box<dyn Any + Send>) -> String {
if let Some(message) = payload.downcast_ref::<&str>() {
(*message).to_string()
} else if let Some(message) = payload.downcast_ref::<String>() {
message.clone()
} else {
"linear backend panicked with a non-string payload".to_string()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BvpCallbackError {
TypeMismatch {
expected: &'static str,
actual: String,
},
Panic { message: String },
OutputShapeMismatch { expected: usize, actual: usize },
}
impl fmt::Display for BvpCallbackError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TypeMismatch { expected, actual } => {
write!(f, "callback expected {expected} input, got {actual}")
}
Self::Panic { message } => write!(f, "callback panicked: {message}"),
Self::OutputShapeMismatch { expected, actual } => write!(
f,
"callback output shape mismatch: expected length {expected}, got {actual}"
),
}
}
}
impl std::error::Error for BvpCallbackError {}
fn solve_dense_nalgebra_linear_system_timed(
matrix: &DMatrix<f64>,
rhs: &DVector<f64>,
bandwidth: (usize, usize),
) -> (DVector<f64>, LinearSolveTiming) {
let condition_for_banded_matrix = matrix.nrows() > 10 * (bandwidth.0 + bandwidth.1);
if condition_for_banded_matrix {
let factor_begin = Instant::now();
let mut lu = LU_nalgebra::new(matrix.to_owned(), Some(bandwidth));
lu.LU();
let factorization = factor_begin.elapsed();
let rhs_begin = Instant::now();
let solution = lu.solve_linear_system_easy(rhs);
(
solution,
LinearSolveTiming {
factorization,
rhs_solve: rhs_begin.elapsed(),
},
)
} else {
assert_eq!(
matrix.nrows(),
rhs.len(),
"dimensions of matrix and vector must match"
);
let factor_begin = Instant::now();
let lu = matrix.to_owned().lu();
let factorization = factor_begin.elapsed();
let rhs_begin = Instant::now();
let solution = lu.solve(rhs).expect("dense nalgebra linear solve failed");
(
solution,
LinearSolveTiming {
factorization,
rhs_solve: rhs_begin.elapsed(),
},
)
}
}
fn solve_dense_nalgebra_linear_system(
matrix: &DMatrix<f64>,
rhs: &DVector<f64>,
bandwidth: (usize, usize),
) -> DVector<f64> {
solve_dense_nalgebra_linear_system_timed(matrix, rhs, bandwidth).0
}