use crate::p_calculator::PCalculator;
use crate::schur_data::SchurData;
use pounce_common::types::Number;
pub fn compute_reduced_hessian<P: PCalculator>(
pcalc: &mut P,
hess_data: &dyn SchurData,
obj_scal: Number,
out: &mut [Number],
) -> bool {
let n = hess_data.nrows() as usize;
if out.len() != n * n {
return false;
}
if !pcalc.schur_matrix(hess_data, out) {
return false;
}
let factor = -obj_scal;
for v in out.iter_mut() {
*v *= factor;
}
true
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backsolver::DenseLuBacksolver;
use crate::p_calculator::IndexPCalculator;
use crate::schur_data::IndexSchurData;
#[test]
fn reduced_hessian_matches_kinv_submatrix() {
#[rustfmt::skip]
let k = vec![
2.0, -1.0, 0.0,
-1.0, 2.0, -1.0,
0.0, -1.0, 2.0,
];
let backsolver = DenseLuBacksolver::from_dense(3, &k).unwrap();
let hess_data = IndexSchurData::from_parts(vec![0, 2], vec![1, 1]).unwrap();
let pcalc_a = IndexSchurData::from_parts(vec![0, 2], vec![1, 1]).unwrap();
let mut pcalc = IndexPCalculator::new(backsolver, pcalc_a);
let mut hr = vec![0.0; 2 * 2];
assert!(compute_reduced_hessian(
&mut pcalc, &hess_data, 1.0, &mut hr
));
assert!((hr[0] - 0.75).abs() < 1e-12, "H_R[0,0] = {}", hr[0]);
assert!((hr[1] - 0.25).abs() < 1e-12, "H_R[1,0] = {}", hr[1]);
assert!((hr[2] - 0.25).abs() < 1e-12, "H_R[0,1] = {}", hr[2]);
assert!((hr[3] - 0.75).abs() < 1e-12, "H_R[1,1] = {}", hr[3]);
}
#[test]
fn reduced_hessian_applies_obj_scal() {
#[rustfmt::skip]
let k = vec![
2.0, -1.0, 0.0,
-1.0, 2.0, -1.0,
0.0, -1.0, 2.0,
];
let backsolver = DenseLuBacksolver::from_dense(3, &k).unwrap();
let hess_data = IndexSchurData::from_parts(vec![1], vec![1]).unwrap();
let pcalc_a = IndexSchurData::from_parts(vec![1], vec![1]).unwrap();
let mut pcalc = IndexPCalculator::new(backsolver, pcalc_a);
let mut hr = vec![0.0; 1];
assert!(compute_reduced_hessian(
&mut pcalc, &hess_data, 2.5, &mut hr
));
assert!((hr[0] - 2.5).abs() < 1e-12, "H_R = {}", hr[0]);
}
#[test]
fn reduced_hessian_rejects_wrong_buffer_size() {
let backsolver = DenseLuBacksolver::from_dense(2, &[1.0, 0.0, 0.0, 1.0]).unwrap();
let hd = IndexSchurData::from_parts(vec![0, 1], vec![1, 1]).unwrap();
let pa = IndexSchurData::from_parts(vec![0, 1], vec![1, 1]).unwrap();
let mut pc = IndexPCalculator::new(backsolver, pa);
let mut wrong = vec![0.0; 3];
assert!(!compute_reduced_hessian(&mut pc, &hd, 1.0, &mut wrong));
}
}