ratio_graph/datasets/
mod.rs

1use phf::phf_map;
2
3use crate::Graph;
4use crate::serialize::CompactGraph;
5
6/// Datasets as raw JSON encoded CompactGraphs.
7const DATASETS_JSON: phf::Map<&'static str, &'static str> = phf_map! {
8    "aircraft_engine" => include_str!("./aircraft_engine.json"),
9    "architecture_integral" => include_str!("./architecture_integral.json"),
10    "architecture_mix" => include_str!("./architecture_mix.json"),
11    "architecture_modular" => include_str!("./architecture_modular.json"),
12    "climate_control_mg" => include_str!("./climate_control_mg.json"),
13    "climate_control" => include_str!("./climate_control.json"),
14    "compatibility" => include_str!("./compatibility.json"),
15    "design" => include_str!("./design.json"),
16    "eefde_lock" => include_str!("./eefde_lock.json"),
17    "elevator45" => include_str!("./elevator45.json"),
18    "elevator175" => include_str!("./elevator175.json"),
19    "ford_hood" => include_str!("./ford_hood.json"),
20    "kodak3d" => include_str!("./kodak3d.json"),
21    "ledsip" => include_str!("./ledsip.json"),
22    "localbus" => include_str!("./localbus.json"),
23    "overlap" => include_str!("./overlap.json"),
24    "pathfinder" => include_str!("./pathfinder.json"),
25    "shaja8" => include_str!("./shaja8.json"),
26    "similarity" => include_str!("./similarity.json"),
27    "tarjans8" => include_str!("./tarjans8.json"),
28    "ucav" => include_str!("./ucav.json"),
29};
30
31/// Enumerate all available datasets.
32pub fn enumerate_datasets() -> Vec<&'static str> {
33    let mut keys: Vec<&'static str> = DATASETS_JSON.keys().copied().collect();
34    keys.sort();
35    keys
36}
37
38/// Get a dataset as the CompactGraph it is encoded as.
39fn get_compact(key: &str) -> Option<CompactGraph> {
40    DATASETS_JSON
41        .get(key)
42        .and_then(|&contents| serde_json::from_str(contents).ok())
43}
44
45/// Get a dataset as a Graph instance.
46pub fn get_dataset(key: &str) -> Option<Graph> {
47    get_compact(key).and_then(|c| c.try_into().ok())
48}
49
50/// Get the info regarding a dataset.
51pub fn get_dataset_info(key: &str) -> Option<String> {
52    get_compact(key).and_then(|c| {
53        c.metadata
54            .annotations
55            .get("info")
56            .and_then(|info| info.as_str())
57            .map(|s| s.into())
58    })
59}
60
61#[cfg(test)]
62mod tests {
63    use std::collections::{BTreeMap, BTreeSet};
64
65    #[allow(unused_imports)]
66    use pretty_assertions::{assert_eq, assert_ne, assert_str_eq};
67    use uuid::Uuid;
68
69    #[allow(unused_imports)]
70    use super::*;
71    use crate::mdm::{NodeSelectionMode, mdm_axis_nodes};
72    use crate::{EdgeStore, HasNodeStore, NodeStore};
73
74    #[test]
75    fn test_dataset_keys() {
76        assert!(
77            DATASETS_JSON.contains_key("aircraft_engine"),
78            "definitely should have this"
79        );
80        assert_eq!(DATASETS_JSON.len(), 21);
81    }
82
83    #[test]
84    fn test_dataset_info() {
85        let info = get_dataset_info("localbus").unwrap();
86        assert_eq!("Example graph containing a local bus.", info.as_str());
87    }
88
89    #[test]
90    fn test_dataset_graphs() {
91        for key in enumerate_datasets() {
92            assert!(get_compact(key).is_some());
93            assert!(get_dataset_info(key).is_some());
94            let graph = get_dataset(key).unwrap_or_else(|| panic!("a valid graph for {}", key));
95            for node in graph.all_nodes() {
96                graph.check_node(node).expect("valid node");
97            }
98            for edge in graph.all_edges() {
99                graph
100                    .check_edge(edge, graph.node_store())
101                    .expect("valid edge");
102            }
103        }
104    }
105
106    #[test]
107    fn test_ucav_contents() {
108        let mut g = get_dataset("ucav").expect("valid graph");
109        let node_agg = g.node_aggregate();
110        assert_eq!(node_agg.kinds, BTreeMap::from([("node".to_string(), 14)]));
111        assert_eq!(
112            node_agg.labels,
113            BTreeMap::from([("default".to_string(), 14)])
114        );
115        let weight_keys = node_agg
116            .weights
117            .keys()
118            .map(|x| x.to_owned())
119            .collect::<BTreeSet<String>>();
120        let reference_keys = BTreeSet::from([
121            "min_cost".to_string(),
122            "max_cost".to_string(),
123            "mean_cost".to_string(),
124            "min_duration".to_string(),
125            "mean_duration".to_string(),
126            "max_duration".to_string(),
127            "improvement_curve".to_string(),
128        ]);
129        assert_eq!(weight_keys, reference_keys);
130        assert_eq!(g.max_node_depth(), 0);
131    }
132
133    #[test]
134    fn test_climate_control_mg() {
135        let compact: CompactGraph = DATASETS_JSON
136            .get("climate_control_mg")
137            .map(|&contents| serde_json::from_str(contents).expect("a correctly encoded dataset"))
138            .expect("valid compact graph");
139
140        let mut graph: Result<Graph, _> = compact.try_into();
141        match graph.as_mut() {
142            Ok(graph) => assert_eq!(graph.max_node_depth(), 3),
143            Err(err) => panic!("{:?}", err),
144        }
145
146        // Do some descendant/ascendant checks.
147        let graph = graph.unwrap();
148
149        // node_node6's ID from the JSON. Le root.
150        let node_id = graph.root_ids().next().unwrap();
151        assert_eq!(graph.node_height(&node_id, true, None, None).unwrap(), 3);
152        assert_eq!(graph.node_depth(&node_id, true, None, None).unwrap(), 0);
153        assert_eq!(graph.node_depth(&node_id, true, None, Some(0)).unwrap(), 0);
154
155        assert_eq!(graph.leaf_ids().count(), 16);
156
157        // Now cap this search at 2 levels.
158        assert_eq!(graph.node_height(&node_id, true, None, Some(2)).unwrap(), 2);
159
160        // Now cap it at it's children.
161        let leaf_ids: BTreeSet<Uuid> = graph
162            .get_node(&node_id)
163            .unwrap()
164            .children
165            .clone()
166            .into_iter()
167            .collect();
168        assert_eq!(
169            graph
170                .node_height(&node_id, true, Some(&leaf_ids), Some(10))
171                .unwrap(),
172            1
173        );
174
175        // Check the height of one of the leafs.
176        let node_id = graph.leaf_ids().next().unwrap();
177        assert_eq!(graph.node_depth(&node_id, true, None, None).unwrap(), 3);
178
179        // Now check the axis node functions.
180        let ax_only_root = mdm_axis_nodes(
181            &graph,
182            &Default::default(),
183            &Default::default(),
184            None,
185            Some(0),
186            &NodeSelectionMode::Independent,
187        )
188        .unwrap();
189        assert_eq!(ax_only_root.len(), 1);
190
191        let ax_full_depth = mdm_axis_nodes(
192            &graph,
193            &Default::default(),
194            &Default::default(),
195            None,
196            Some(3),
197            &NodeSelectionMode::Independent,
198        )
199        .unwrap();
200        assert_eq!(ax_full_depth.len(), 16);
201
202        let ax_in_between = mdm_axis_nodes(
203            &graph,
204            &Default::default(),
205            &Default::default(),
206            None,
207            Some(2),
208            &NodeSelectionMode::Independent,
209        )
210        .unwrap();
211        assert_eq!(ax_in_between.len(), 10);
212
213        // There's only one kind here, but should still work.
214        let kinds = graph
215            .node_aggregate()
216            .kinds
217            .to_owned()
218            .into_keys()
219            .collect::<BTreeSet<_>>();
220        assert_eq!(kinds.len(), 1);
221        let ax_fake_dependent = mdm_axis_nodes(
222            &graph,
223            &Default::default(),
224            &Default::default(),
225            None,
226            Some(2),
227            &NodeSelectionMode::Dependent(kinds),
228        )
229        .unwrap();
230        assert_eq!(ax_fake_dependent.len(), 10);
231    }
232
233    #[test]
234    fn test_ledsip_mdm() {
235        let compact: CompactGraph = DATASETS_JSON
236            .get("ledsip")
237            .map(|&contents| serde_json::from_str(contents).expect("a correctly encoded dataset"))
238            .expect("valid compact graph");
239
240        let graph: Graph = compact.try_into().unwrap();
241        let axis = mdm_axis_nodes(
242            &graph,
243            &Default::default(),
244            &Default::default(),
245            Default::default(),
246            Default::default(),
247            &Default::default(),
248        )
249        .unwrap();
250
251        assert_eq!(axis.len(), 1200);
252    }
253
254    #[test]
255    fn test_compatibility_mdm() {
256        let compact: CompactGraph = DATASETS_JSON
257            .get("compatibility")
258            .map(|&contents| serde_json::from_str(contents).expect("a correctly encoded dataset"))
259            .expect("valid compact graph");
260
261        let graph: Graph = compact.try_into().unwrap();
262
263        let axis = mdm_axis_nodes(
264            &graph,
265            &Default::default(),
266            &Default::default(),
267            Default::default(),
268            Default::default(),
269            &NodeSelectionMode::Dependent(BTreeSet::from(["A".to_string()])),
270        )
271        .unwrap();
272        assert_eq!(graph.leaf_ids().count(), 6);
273        assert_eq!(axis.len(), 5); // C1 is not connected to A.
274    }
275}