capability_grower_configuration_comparison/
compare_level_specific.rs

1// ---------------- [ File: capability-grower-configuration-comparison/src/compare_level_specific.rs ]
2crate::ix!();
3
4pub trait CompareLevelSpecific {
5    fn compare_level_specific(&self, other: &GrowerTreeConfiguration) -> CompareOutcome;
6}
7
8impl CompareLevelSpecific for GrowerTreeConfiguration {
9    fn compare_level_specific(&self, other: &GrowerTreeConfiguration) -> CompareOutcome {
10        match (self.level_specific(), other.level_specific()) {
11            (None, None) => CompareOutcome::Exact,
12            (None, Some(_)) | (Some(_), None) => CompareOutcome::Partial(0.5),
13            (Some(a), Some(b)) => {
14                // If length differs => test expects Incompatible
15                let ab = a.breadth_per_level();
16                let bb = b.breadth_per_level();
17                let ad = a.density_per_level();
18                let bd = b.density_per_level();
19
20                if ab.len() != bb.len() || ad.len() != bd.len() {
21                    return CompareOutcome::Incompatible;
22                }
23
24                let mut total_score = 1.0;
25
26                // compare breadth
27                let len_min = ab.len(); // == bb.len()
28                for i in 0..len_min {
29                    let diff = (ab[i] as i32 - bb[i] as i32).abs();
30                    if diff > 10 {
31                        total_score *= 0.5;
32                    } else if diff > 2 {
33                        total_score *= 0.8;
34                    }
35                }
36                // compare density
37                let len_min_d = ad.len(); // == bd.len()
38                for i in 0..len_min_d {
39                    let diff = (ad[i] as i32 - bd[i] as i32).abs();
40                    if diff > 10 {
41                        total_score *= 0.5;
42                    } else if diff > 2 {
43                        total_score *= 0.8;
44                    }
45                }
46
47                if total_score < 0.2 {
48                    CompareOutcome::Incompatible
49                } else if total_score < 1.0 {
50                    CompareOutcome::Partial(total_score)
51                } else {
52                    CompareOutcome::Exact
53                }
54            }
55        }
56    }
57}
58
59#[cfg(test)]
60mod compare_level_specific_tests {
61    use super::*;
62    use traced_test::traced_test;
63
64    #[traced_test]
65    fn both_none() {
66        let a = GrowerTreeConfiguration::default();
67        let b = a.clone();
68        assert_eq!(a.compare_level_specific(&b), CompareOutcome::Exact);
69    }
70
71    #[traced_test]
72    fn same_arrays_exact() {
73        let lsc = TreeLevelSpecificConfigurationBuilder::default()
74            .breadth_per_level(vec![2,3])
75            .density_per_level(vec![1,1])
76            .build().unwrap();
77        let a = GrowerTreeConfiguration::default()
78            .to_builder().level_specific(Some(lsc.clone())).build().unwrap();
79        let b = a.clone();
80        assert_eq!(a.compare_level_specific(&b), CompareOutcome::Exact);
81    }
82
83    #[traced_test]
84    fn partial_mismatch() {
85        let lsc1 = TreeLevelSpecificConfigurationBuilder::default()
86            .breadth_per_level(vec![2,3,4])
87            .density_per_level(vec![1,1,2])
88            .build().unwrap();
89        let lsc2 = TreeLevelSpecificConfigurationBuilder::default()
90            .breadth_per_level(vec![2,3,9])
91            .density_per_level(vec![1,1,2])
92            .build().unwrap();
93        let a = GrowerTreeConfiguration::default()
94            .to_builder().level_specific(Some(lsc1)).build().unwrap();
95        let b = a.to_builder().level_specific(Some(lsc2)).build().unwrap();
96        match a.compare_level_specific(&b) {
97            CompareOutcome::Partial(_) => {},
98            other => panic!("expected partial, got {:?}", other),
99        }
100    }
101
102    #[traced_test]
103    fn different_length_incompatible() {
104        let lsc1 = TreeLevelSpecificConfigurationBuilder::default()
105            .breadth_per_level(vec![2,3])
106            .density_per_level(vec![1,1])
107            .build().unwrap();
108        let lsc2 = TreeLevelSpecificConfigurationBuilder::default()
109            .breadth_per_level(vec![2,3,4])
110            .density_per_level(vec![1,1,1])
111            .build().unwrap();
112        let a = GrowerTreeConfiguration::default()
113            .to_builder().level_specific(Some(lsc1)).build().unwrap();
114        let b = a.to_builder().level_specific(Some(lsc2)).build().unwrap();
115
116        let got = a.compare_level_specific(&b);
117        assert_eq!(got, CompareOutcome::Incompatible, "length mismatch => Incompatible");
118    }
119}