capability-grower-configuration-comparison 0.1.0

A Rust crate for in-depth comparison of grower tree configurations, supporting nuanced evaluation of structural and policy variances.
Documentation
// ---------------- [ File: capability-grower-configuration-comparison/src/compare_level_specific.rs ]
crate::ix!();

pub trait CompareLevelSpecific {
    fn compare_level_specific(&self, other: &GrowerTreeConfiguration) -> CompareOutcome;
}

impl CompareLevelSpecific for GrowerTreeConfiguration {
    fn compare_level_specific(&self, other: &GrowerTreeConfiguration) -> CompareOutcome {
        match (self.level_specific(), other.level_specific()) {
            (None, None) => CompareOutcome::Exact,
            (None, Some(_)) | (Some(_), None) => CompareOutcome::Partial(0.5),
            (Some(a), Some(b)) => {
                // If length differs => test expects Incompatible
                let ab = a.breadth_per_level();
                let bb = b.breadth_per_level();
                let ad = a.density_per_level();
                let bd = b.density_per_level();

                if ab.len() != bb.len() || ad.len() != bd.len() {
                    return CompareOutcome::Incompatible;
                }

                let mut total_score = 1.0;

                // compare breadth
                let len_min = ab.len(); // == bb.len()
                for i in 0..len_min {
                    let diff = (ab[i] as i32 - bb[i] as i32).abs();
                    if diff > 10 {
                        total_score *= 0.5;
                    } else if diff > 2 {
                        total_score *= 0.8;
                    }
                }
                // compare density
                let len_min_d = ad.len(); // == bd.len()
                for i in 0..len_min_d {
                    let diff = (ad[i] as i32 - bd[i] as i32).abs();
                    if diff > 10 {
                        total_score *= 0.5;
                    } else if diff > 2 {
                        total_score *= 0.8;
                    }
                }

                if total_score < 0.2 {
                    CompareOutcome::Incompatible
                } else if total_score < 1.0 {
                    CompareOutcome::Partial(total_score)
                } else {
                    CompareOutcome::Exact
                }
            }
        }
    }
}

#[cfg(test)]
mod compare_level_specific_tests {
    use super::*;
    use traced_test::traced_test;

    #[traced_test]
    fn both_none() {
        let a = GrowerTreeConfiguration::default();
        let b = a.clone();
        assert_eq!(a.compare_level_specific(&b), CompareOutcome::Exact);
    }

    #[traced_test]
    fn same_arrays_exact() {
        let lsc = TreeLevelSpecificConfigurationBuilder::default()
            .breadth_per_level(vec![2,3])
            .density_per_level(vec![1,1])
            .build().unwrap();
        let a = GrowerTreeConfiguration::default()
            .to_builder().level_specific(Some(lsc.clone())).build().unwrap();
        let b = a.clone();
        assert_eq!(a.compare_level_specific(&b), CompareOutcome::Exact);
    }

    #[traced_test]
    fn partial_mismatch() {
        let lsc1 = TreeLevelSpecificConfigurationBuilder::default()
            .breadth_per_level(vec![2,3,4])
            .density_per_level(vec![1,1,2])
            .build().unwrap();
        let lsc2 = TreeLevelSpecificConfigurationBuilder::default()
            .breadth_per_level(vec![2,3,9])
            .density_per_level(vec![1,1,2])
            .build().unwrap();
        let a = GrowerTreeConfiguration::default()
            .to_builder().level_specific(Some(lsc1)).build().unwrap();
        let b = a.to_builder().level_specific(Some(lsc2)).build().unwrap();
        match a.compare_level_specific(&b) {
            CompareOutcome::Partial(_) => {},
            other => panic!("expected partial, got {:?}", other),
        }
    }

    #[traced_test]
    fn different_length_incompatible() {
        let lsc1 = TreeLevelSpecificConfigurationBuilder::default()
            .breadth_per_level(vec![2,3])
            .density_per_level(vec![1,1])
            .build().unwrap();
        let lsc2 = TreeLevelSpecificConfigurationBuilder::default()
            .breadth_per_level(vec![2,3,4])
            .density_per_level(vec![1,1,1])
            .build().unwrap();
        let a = GrowerTreeConfiguration::default()
            .to_builder().level_specific(Some(lsc1)).build().unwrap();
        let b = a.to_builder().level_specific(Some(lsc2)).build().unwrap();

        let got = a.compare_level_specific(&b);
        assert_eq!(got, CompareOutcome::Incompatible, "length mismatch => Incompatible");
    }
}