use crate::inference::steering::SteerPlan;
use crate::manifold::SaeManifoldTerm;
use gam_problem::RowMetric;
use gam_terms::inference::structure_evidence::{ClaimKind, ProbePlan, StructureLedger};
#[derive(Clone, Debug)]
pub struct RealizedProbe {
pub plan: ProbePlan,
pub steer: SteerPlan,
pub realized_nats: Option<f64>,
}
pub struct ProbeRunner<'a> {
pub term: &'a SaeManifoldTerm,
pub metric: &'a RowMetric,
}
impl<'a> ProbeRunner<'a> {
pub fn absorb(&self, ledger: &mut StructureLedger, probe: &RealizedProbe, realized_nats: f64) {
let Ok((claim_idx, _)) = self.claim_for_steer(ledger, &probe.steer) else {
return;
};
if let Err(err) = ledger.absorb_probe_outcome(claim_idx, realized_nats, 0.0) {
log::debug!("probe outcome for claim {claim_idx} was not absorbed: {err}");
}
}
fn claim_for_steer(
&self,
ledger: &StructureLedger,
steer: &SteerPlan,
) -> Result<(usize, usize), String> {
let mut best: Option<(usize, f64)> = None;
for (idx, claim) in ledger.claims().iter().enumerate() {
if steerable_atom(&claim.kind) != Some(steer.atom) {
continue;
}
let log_e = claim.evidence.current_e_value_log();
match best {
Some((_, best_log_e)) if best_log_e <= log_e => {}
_ => best = Some((idx, log_e)),
}
}
best.map(|(idx, _)| (idx, steer.atom))
.ok_or_else(|| format!("ProbeRunner: no claim names steered atom {}", steer.atom))
}
}
fn steerable_atom(kind: &ClaimKind) -> Option<usize> {
match kind {
ClaimKind::AtomExists { atom } | ClaimKind::GeometryKind { atom, .. } => Some(*atom),
ClaimKind::BindingEdge { .. } | ClaimKind::Custom { .. } => None,
}
}