use crate::sparse_dict::{
BlockSparseFit, SparseDictFit, block_gates, block_projections_row,
reconstruct_block_sparse_rows, reconstruct_sparse_rows,
};
use ndarray::{ArrayView2, ArrayView3};
use std::collections::HashSet;
use std::f64::consts::TAU;
const CERT_REL_SLACK: f64 = 1.0e-4;
const LAMBDA_FLOOR: f64 = f32::EPSILON as f64;
const RATIO_QUANTILES: [f64; 4] = [0.5, 0.9, 0.99, 1.0];
#[derive(Clone, Debug)]
pub struct DualCertificateReport {
pub n_rows: usize,
pub frac_certified: f64,
pub optimality_ratio_quantiles: Vec<(f64, f64)>,
pub birth_candidates: Vec<(usize, u32, f64)>,
}
struct RowCertificate {
optimality_ratio: f64,
birth: Option<(u32, f64)>,
}
pub fn harmonic_dual_birth_eta(residual_coeffs: &[(f64, f64)], active_mass: f64) -> f64 {
if residual_coeffs.is_empty() {
return 0.0;
}
let lambda = active_mass.max(LAMBDA_FLOOR);
let (t, _curvature) = harmonic_dual_argmax(residual_coeffs);
let matched_amplitude =
harmonic_dual_value(residual_coeffs, t).max(0.0) / residual_coeffs.len() as f64;
matched_amplitude / lambda
}
fn harmonic_dual_value(coeffs: &[(f64, f64)], t: f64) -> f64 {
let mut acc = 0.0;
for (h, &(c_h, s_h)) in coeffs.iter().enumerate() {
let phase = TAU * (h + 1) as f64 * t;
let (sin_h, cos_h) = phase.sin_cos();
acc += c_h * cos_h + s_h * sin_h;
}
acc
}
fn harmonic_dual_derivative(coeffs: &[(f64, f64)], t: f64) -> f64 {
let mut acc = 0.0;
for (h, &(c_h, s_h)) in coeffs.iter().enumerate() {
let omega = TAU * (h + 1) as f64;
let phase = omega * t;
let (sin_h, cos_h) = phase.sin_cos();
acc += omega * (-c_h * sin_h + s_h * cos_h);
}
acc
}
fn harmonic_dual_second_derivative(coeffs: &[(f64, f64)], t: f64) -> f64 {
let mut acc = 0.0;
for (h, &(c_h, s_h)) in coeffs.iter().enumerate() {
let omega = TAU * (h + 1) as f64;
let phase = omega * t;
let (sin_h, cos_h) = phase.sin_cos();
acc += omega * omega * (-c_h * cos_h - s_h * sin_h);
}
acc
}
fn harmonic_dual_argmax(coeffs: &[(f64, f64)]) -> (f64, f64) {
let harmonics = coeffs.len();
let grid = 4 * harmonics.max(1);
let mut best_t = 0.0;
let mut best_value = f64::NEG_INFINITY;
for idx in 0..grid {
let t = idx as f64 / grid as f64;
let value = harmonic_dual_value(coeffs, t);
if value > best_value {
best_value = value;
best_t = t;
}
}
let tolerance = f64::EPSILON.sqrt();
let iteration_cap = 64;
let mut t = best_t;
let mut converged = false;
for _step_idx in 0..iteration_cap {
let second = harmonic_dual_second_derivative(coeffs, t);
if second.abs() <= f64::MIN_POSITIVE {
break;
}
let step = harmonic_dual_derivative(coeffs, t) / second;
t -= step;
if step.abs() <= tolerance * (1.0 + t.abs()) {
converged = true;
break;
}
}
let polished_t = t.rem_euclid(1.0);
if converged && harmonic_dual_value(coeffs, polished_t) >= best_value {
(
polished_t,
harmonic_dual_second_derivative(coeffs, polished_t),
)
} else {
(best_t, harmonic_dual_second_derivative(coeffs, best_t))
}
}
fn assemble_report(rows: Vec<RowCertificate>, max_candidates: usize) -> DualCertificateReport {
let n_rows = rows.len();
let threshold = 1.0 + CERT_REL_SLACK;
let mut ratios: Vec<f64> = Vec::with_capacity(n_rows);
let mut certified = 0usize;
let mut births: Vec<(usize, u32, f64)> = Vec::new();
for (row_idx, rc) in rows.iter().enumerate() {
ratios.push(rc.optimality_ratio);
if rc.optimality_ratio <= threshold {
certified += 1;
}
if let Some((atom, eta)) = rc.birth {
if eta > threshold {
births.push((row_idx, atom, eta));
}
}
}
let frac_certified = if n_rows == 0 {
1.0
} else {
certified as f64 / n_rows as f64
};
let optimality_ratio_quantiles = quantiles(&mut ratios, &RATIO_QUANTILES);
births.sort_by(|a, b| {
b.2.partial_cmp(&a.2)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| a.0.cmp(&b.0))
.then_with(|| a.1.cmp(&b.1))
});
births.truncate(max_candidates);
DualCertificateReport {
n_rows,
frac_certified,
optimality_ratio_quantiles,
birth_candidates: births,
}
}
fn quantiles(values: &mut [f64], probs: &[f64]) -> Vec<(f64, f64)> {
if values.is_empty() {
return probs.iter().map(|&p| (p, 0.0)).collect();
}
values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let n = values.len();
probs
.iter()
.map(|&p| {
let clamped = p.clamp(0.0, 1.0);
let rank = (clamped * n as f64).ceil().max(1.0) as usize;
let idx = rank.min(n) - 1;
(p, values[idx])
})
.collect()
}
pub fn sparse_dict_dual_certificate(
data: ArrayView2<'_, f32>,
fit: &SparseDictFit,
max_candidates: usize,
) -> Result<DualCertificateReport, String> {
sparse_route_dual_certificate(
data,
fit.decoder.view(),
fit.indices.view(),
fit.codes.view(),
max_candidates,
)
}
pub fn sparse_route_dual_certificate(
data: ArrayView2<'_, f32>,
decoder: ArrayView2<'_, f32>,
indices: ArrayView2<'_, u32>,
codes: ArrayView2<'_, f32>,
max_candidates: usize,
) -> Result<DualCertificateReport, String> {
let (k, p) = decoder.dim();
if k == 0 {
return Err("sparse_route_dual_certificate: dictionary has no atoms".to_string());
}
if data.ncols() != p {
return Err(format!(
"sparse_route_dual_certificate: data has P={} columns but the decoder has P={p}",
data.ncols()
));
}
let n = data.nrows();
if indices.nrows() != n || codes.nrows() != n {
return Err(format!(
"sparse_route_dual_certificate: routing has {} rows but data has {n}",
indices.nrows()
));
}
let s = indices.ncols();
if codes.ncols() != s {
return Err(format!(
"sparse_route_dual_certificate: indices width {s} != codes width {}",
codes.ncols()
));
}
let recon = reconstruct_sparse_rows(decoder, indices, codes)?;
let mut rows: Vec<RowCertificate> = Vec::with_capacity(n);
let mut residual: Vec<f64> = vec![0.0; p];
let mut active: HashSet<u32> = HashSet::new();
for i in 0..n {
for c in 0..p {
residual[c] = data[[i, c]] as f64 - recon[[i, c]] as f64;
}
active.clear();
let mut min_active_mass = f64::INFINITY;
for j in 0..s {
let code = codes[[i, j]] as f64;
if code == 0.0 {
continue;
}
active.insert(indices[[i, j]]);
let mass = code.abs();
if mass < min_active_mass {
min_active_mass = mass;
}
}
let implied_lambda = if min_active_mass.is_finite() {
min_active_mass.max(LAMBDA_FLOOR)
} else {
LAMBDA_FLOOR
};
let mut max_off_gate = 0.0f64;
let mut argmax_atom: Option<u32> = None;
for (atom_idx, atom) in decoder.outer_iter().enumerate() {
if active.contains(&(atom_idx as u32)) {
continue;
}
let mut dot = 0.0f64;
for c in 0..p {
dot += residual[c] * atom[c] as f64;
}
let gate = dot.abs();
if gate > max_off_gate {
max_off_gate = gate;
argmax_atom = Some(atom_idx as u32);
}
}
let optimality_ratio = max_off_gate / implied_lambda;
let birth = argmax_atom.map(|a| (a, max_off_gate / implied_lambda));
rows.push(RowCertificate {
optimality_ratio,
birth,
});
}
Ok(assemble_report(rows, max_candidates))
}
pub fn block_dual_certificate(
data: ArrayView2<'_, f32>,
fit: &BlockSparseFit,
max_candidates: usize,
) -> Result<DualCertificateReport, String> {
block_route_dual_certificate_scaled(
data,
fit.decoder.view(),
fit.blocks.view(),
fit.codes.view(),
fit.block_size,
fit.gamma as f64,
max_candidates,
)
}
pub fn block_route_dual_certificate(
data: ArrayView2<'_, f32>,
decoder: ArrayView2<'_, f32>,
blocks: ArrayView2<'_, u32>,
codes: ArrayView3<'_, f32>,
block_size: usize,
max_candidates: usize,
) -> Result<DualCertificateReport, String> {
block_route_dual_certificate_scaled(
data,
decoder,
blocks,
codes,
block_size,
1.0,
max_candidates,
)
}
fn block_route_dual_certificate_scaled(
data: ArrayView2<'_, f32>,
decoder: ArrayView2<'_, f32>,
blocks: ArrayView2<'_, u32>,
codes: ArrayView3<'_, f32>,
block_size: usize,
dual_scale: f64,
max_candidates: usize,
) -> Result<DualCertificateReport, String> {
let (k, p) = decoder.dim();
let b = block_size;
if b == 0 || k == 0 {
return Err("block_route_dual_certificate: empty dictionary or block size".to_string());
}
if k % b != 0 {
return Err(format!(
"block_route_dual_certificate: decoder has K={k} rows, not a multiple of block size {b}"
));
}
if !(dual_scale.is_finite() && dual_scale > 0.0) {
return Err(format!(
"block_route_dual_certificate: dual scale must be finite and positive, got {dual_scale}"
));
}
let n_blocks = k / b;
if data.ncols() != p {
return Err(format!(
"block_route_dual_certificate: data has P={} columns but the decoder has P={p}",
data.ncols()
));
}
let n = data.nrows();
if blocks.nrows() != n || codes.shape()[0] != n {
return Err(format!(
"block_route_dual_certificate: routing has {} rows but data has {n}",
blocks.nrows()
));
}
let topk = blocks.ncols();
if codes.shape() != [n, topk, b] {
return Err(format!(
"block_route_dual_certificate: codes shape {:?} does not match blocks {:?} and block size {b}",
codes.shape(),
blocks.dim()
));
}
let recon = reconstruct_block_sparse_rows(decoder, blocks, codes, b)?;
let mut rows: Vec<RowCertificate> = Vec::with_capacity(n);
let mut residual = ndarray::Array1::<f32>::zeros(p);
let mut active: HashSet<u32> = HashSet::new();
for i in 0..n {
for c in 0..p {
residual[c] = data[[i, c]] - recon[[i, c]];
}
active.clear();
let mut min_active_gate = f64::INFINITY;
for j in 0..topk {
let mut gate2 = 0.0_f64;
for r in 0..b {
let code = codes[[i, j, r]] as f64;
gate2 += code * code;
}
let gate = gate2.sqrt();
if gate == 0.0 {
continue;
}
active.insert(blocks[[i, j]]);
if gate < min_active_gate {
min_active_gate = gate;
}
}
let implied_lambda = if min_active_gate.is_finite() {
min_active_gate.max(LAMBDA_FLOOR)
} else {
LAMBDA_FLOOR
};
let w = block_projections_row(residual.view(), decoder, n_blocks, b);
let residual_gates = block_gates(w.view());
let mut max_off_gate = 0.0f64;
let mut argmax_block: Option<u32> = None;
for (g, &rg) in residual_gates.iter().enumerate() {
if active.contains(&(g as u32)) {
continue;
}
let gate = dual_scale * rg as f64;
if gate > max_off_gate {
max_off_gate = gate;
argmax_block = Some(g as u32);
}
}
let optimality_ratio = max_off_gate / implied_lambda;
let birth = argmax_block.map(|g| (g * b as u32, optimality_ratio));
rows.push(RowCertificate {
optimality_ratio,
birth,
});
}
Ok(assemble_report(rows, max_candidates))
}