use crate::astro::math::linear::{
invert_matrix_last_tie, matmul, matrix_sub, solve_matrix_last_tie, transpose,
};
use crate::estimation::recipe::NormalRecipe;
use crate::estimation::substrate::normal::NormalAssembler;
use crate::estimation::substrate::rows::ResidualRow;
use super::{FixedSolveError, FloatSolveError};
pub(super) type Row = ResidualRow;
const PPP_ASSEMBLER: NormalAssembler = NormalAssembler::new(NormalRecipe::PppDenseLastTie);
pub(super) fn solve_normal_equations(
rows: &[Row],
n: usize,
normal: NormalRecipe,
) -> Result<Vec<f64>, FloatSolveError> {
let assembler = NormalAssembler::new(normal);
let weighted = || rows.iter().map(Row::as_weighted);
let solution = match normal {
NormalRecipe::CanonicalSquareRoot => assembler.solve_dense_square_root(weighted(), n),
_ => assembler.solve_dense_last_tie(weighted(), n),
};
solution.ok_or(FloatSolveError::SingularGeometry)
}
pub(super) fn normal_equations(
rows: &[Row],
n: usize,
) -> Result<(Vec<Vec<f64>>, Vec<f64>), FloatSolveError> {
PPP_ASSEMBLER
.assemble_dense(rows.iter().map(Row::as_weighted), n)
.ok_or(FloatSolveError::SingularGeometry)
}
fn submatrix(
matrix: &[Vec<f64>],
row_start: usize,
row_count: usize,
col_start: usize,
col_count: usize,
) -> Vec<Vec<f64>> {
matrix[row_start..row_start + row_count]
.iter()
.map(|row| row[col_start..col_start + col_count].to_vec())
.collect()
}
pub(super) fn ambiguity_covariance_from_normal(
normal: &[Vec<f64>],
start: usize,
n_ambiguities: usize,
) -> Result<Vec<Vec<f64>>, FixedSolveError> {
let a = submatrix(normal, 0, start, 0, start);
let b = submatrix(normal, 0, start, start, n_ambiguities);
let c = submatrix(normal, start, n_ambiguities, start, n_ambiguities);
let a_inv_b = solve_matrix_last_tie(&a, &b)
.ok_or(FixedSolveError::Float(FloatSolveError::SingularGeometry))?;
let b_t = transpose(&b).ok_or(FixedSolveError::Float(FloatSolveError::SingularGeometry))?;
let bt_a_inv_b =
matmul(&b_t, &a_inv_b).ok_or(FixedSolveError::Float(FloatSolveError::SingularGeometry))?;
let schur = matrix_sub(&c, &bt_a_inv_b)
.ok_or(FixedSolveError::Float(FloatSolveError::SingularGeometry))?;
invert_matrix_last_tie(&schur).ok_or(FixedSolveError::Float(FloatSolveError::SingularGeometry))
}