use crate::ils::{lambda_ils_search, IlsError, IlsResult};
#[inline]
pub(crate) fn resolve_integer_lattice(
float_cycles: &[f64],
covariance: &[Vec<f64>],
ratio_threshold: f64,
) -> Result<IlsResult, IlsError> {
if let Some(covariance) = symmetrized_square(covariance) {
lambda_ils_search(float_cycles, &covariance, ratio_threshold)
} else {
lambda_ils_search(float_cycles, covariance, ratio_threshold)
}
}
fn symmetrized_square(covariance: &[Vec<f64>]) -> Option<Vec<Vec<f64>>> {
let n = covariance.len();
if n == 0 || covariance.iter().any(|row| row.len() != n) {
return None;
}
let mut out = vec![vec![0.0_f64; n]; n];
for i in 0..n {
out[i][i] = covariance[i][i];
for j in (i + 1)..n {
let value = 0.5 * (covariance[i][j] + covariance[j][i]);
out[i][j] = value;
out[j][i] = value;
}
}
Some(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolver_matches_direct_lambda_call() {
let floats = [0.2_f64, -0.9, 1.1];
let covariance = vec![
vec![0.04_f64, 0.001, 0.0],
vec![0.001, 0.05, 0.002],
vec![0.0, 0.002, 0.03],
];
let ratio = 3.0;
let direct = lambda_ils_search(&floats, &covariance, ratio).unwrap();
let routed = resolve_integer_lattice(&floats, &covariance, ratio).unwrap();
assert_eq!(direct.fixed, routed.fixed);
assert_eq!(direct.fixed_status, routed.fixed_status);
assert_eq!(direct.ratio.to_bits(), routed.ratio.to_bits());
assert_eq!(direct.best_score.to_bits(), routed.best_score.to_bits());
assert_eq!(direct.candidates_evaluated, routed.candidates_evaluated);
}
}