//! Galdr - Rank-1 Fisher Information State for Anti-Forgetting.
//!
//! Implements the structural criticality metrics from Wang et al. 2509.23593.

use mimirs_core::{DensityMemory, ScrambleScore};
use nalgebra::DVector;

/// Galdr - The Rank-1 Fisher Information State.
///
/// Encapsulates the importance of memory dimensions based on their
/// contribution to the system's structural integrity (OTOC scrambling).
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Galdr {
    /// Diagonal Fisher Information Matrix (FIM) components.
    pub fim_diag: Vec<f64>,
}

impl Galdr {
    /// Estimates the Fisher Information for a given memory based on its
    /// density matrix and scrambling score.
    pub fn estimate(rho: &DensityMemory, score: ScrambleScore) -> Self {
        let diag = rho.diagonal();
        let _n = rho.dimension();
        
        // DERIVATION: Diagonal Fisher Information approximation F_ii ∝ S(M) * ρ_ii.
        // Derived from EWC Rank-1 approximation (Wang et al. 2025) where 
        // structural criticality scales the elastic constraint.
        let fim_diag = diag.into_iter()
            .map(|val| {
                let w = (score.value() as f64) * val;
                debug_assert!(w.is_finite());
                w
            })
            .collect();

        Self { fim_diag }
    }

    /// Returns a weight vector for consolidation.
    pub fn weights(&self) -> DVector<f64> {
        DVector::from_vec(self.fim_diag.clone())
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use mimirs_core::{DensityMemory, ScrambleScore};

    #[test]
    fn test_fisher_creation() {
        let dm = DensityMemory::from_pure(&[1.0, 0.0]).unwrap();
        let score = ScrambleScore::new(0.5);
        let galdr = Galdr::estimate(&dm, score);
        
        assert_eq!(galdr.fim_diag.len(), 2);
        assert!(galdr.weights().iter().any(|&w| w > 0.0));
    }
}
