converge-prism-analytics 2.0.0

Closed-form analytics and inference for Converge agents: feature extraction, inference packs, and fuzzy inference. Training-pipeline concerns live in converge-crucible-models.
Documentation
use std::collections::BTreeMap;

use converge_pack::gate::GateResult as Result;
use converge_pack::gate::{ProblemSpec, ReplayEnvelope, SolverReport};

use super::types::*;

pub struct FuzzyInferenceEngine;

impl FuzzyInferenceEngine {
    pub fn solve(
        &self,
        input: &FuzzyInferenceInput,
        spec: &ProblemSpec,
    ) -> Result<(FuzzyInferenceOutput, SolverReport)> {
        input.validate()?;

        let input_memberships = evaluate_input_memberships(&input.inputs, &input.variables);
        let mut memberships: BTreeMap<String, f64> = BTreeMap::new();
        let mut activated_rules = Vec::new();

        for (idx, rule) in input.rules.iter().enumerate() {
            let antecedent_strength = evaluate_expression(&rule.when, &input_memberships)?;
            let weight = rule.weight();
            let strength = (antecedent_strength * weight).clamp(0.0, 1.0);
            let consequent = rule.then.key();

            memberships
                .entry(consequent.clone())
                .and_modify(|current| *current = current.max(strength))
                .or_insert(strength);

            if strength > 0.0 {
                activated_rules.push(ActivatedRule {
                    id: rule
                        .id
                        .clone()
                        .unwrap_or_else(|| format!("rule-{}", idx + 1)),
                    antecedent_strength,
                    weight,
                    strength,
                    consequent,
                });
            }
        }

        let confidence = memberships.values().copied().fold(0.0, f64::max);
        let output = FuzzyInferenceOutput {
            input_memberships,
            memberships,
            activated_rules,
            confidence,
            total_rules: input.rules.len(),
        };

        let replay = ReplayEnvelope::minimal(spec.seed());
        let report = SolverReport::optimal("fuzzy-inference-v1", confidence, replay);

        Ok((output, report))
    }
}