#![forbid(unsafe_code)]
use la_stack::prelude::*;
fn main() -> Result<(), LaError> {
let epsilon = BigRational::new(1.into(), (1_u64 << 60).into());
let one = BigRational::from_integer(1.into());
let zero = BigRational::from_integer(0.into());
let matrix = RationalMatrix::<5>::try_from_fn(|row, col| match (row, col) {
(0, 0 | 1) | (1, 0) => one.clone(),
(1, 1) => &one + &epsilon,
_ if row == col => one.clone(),
_ => zero.clone(),
})?;
let rhs = RationalVector::try_new([
zero,
-&epsilon,
BigRational::from_integer(2.into()),
BigRational::from_integer(3.into()),
BigRational::from_integer(4.into()),
])?;
let exact_solution = matrix.solve(&rhs)?;
assert_eq!(matrix.det(), epsilon);
assert_eq!(matrix.det_sign(), DeterminantSign::Positive);
assert_eq!(
exact_solution.as_array(),
&[1, -1, 2, 3, 4].map(|value| BigRational::from_integer(value.into())),
);
println!("exact determinant: {}", matrix.det());
println!("exact determinant sign: {:?}", matrix.det_sign());
println!("exact solution: {:?}", exact_solution.as_array());
let epsilon_f64 = epsilon.try_to_f64()?;
assert_eq!((1.0 + epsilon_f64).to_bits(), 1.0_f64.to_bits());
let f64_matrix = Matrix::<5>::try_from_rows([
[1.0, 1.0, 0.0, 0.0, 0.0],
[1.0, 1.0 + epsilon_f64, 0.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 1.0],
])?;
let f64_rhs = Vector::<5>::try_new([0.0, -epsilon_f64, 2.0, 3.0, 4.0])?;
let f64_solve = f64_matrix
.lu(DEFAULT_SINGULAR_TOL)
.and_then(|lu| lu.solve(f64_rhs));
assert_eq!(
f64_solve,
Err(LaError::singular_numerical(
1,
FactorizationKind::Lu,
0.0,
DEFAULT_SINGULAR_TOL.get(),
)),
);
println!("1.0 + 2^-60 supplied as f64: {}", 1.0 + epsilon_f64);
println!("solve from f64 inputs: {f64_solve:?}");
Ok(())
}