raphtory/algorithms/
algorithm_result.rs

1use crate::prelude::NodeViewOps;
2use ordered_float::OrderedFloat;
3use std::{
4    collections::{hash_map::Iter, HashMap},
5    hash::Hash,
6    marker::PhantomData,
7};
8
9pub trait AsOrd<T: ?Sized + Ord> {
10    /// Converts reference of this type into reference of an ordered Type.
11    ///
12    /// This is the same as AsRef (with the additional constraint that the target type needs to be ordered).
13    ///
14    /// Importantly, unlike AsRef, this blanket-implements the trivial conversion from a type to itself!
15    fn as_ord(&self) -> &T;
16}
17
18impl<T: Ord> AsOrd<T> for T {
19    fn as_ord(&self) -> &T {
20        self
21    }
22}
23
24impl<T: FloatCore> AsOrd<OrderedFloat<T>> for T {
25    fn as_ord(&self) -> &OrderedFloat<T> {
26        self.into()
27    }
28}
29
30impl<T: FloatCore> AsOrd<(OrderedFloat<T>, OrderedFloat<T>)> for (T, T) {
31    fn as_ord(&self) -> &(OrderedFloat<T>, OrderedFloat<T>) {
32        // Safety: OrderedFloat is #[repr(transparent)] and has no invalid values, i.e. there is no physical difference between OrderedFloat and Float.
33        unsafe { &*(self as *const (T, T) as *const (OrderedFloat<T>, OrderedFloat<T>)) }
34    }
35}
36
37impl<T: FloatCore> AsOrd<Vec<OrderedFloat<T>>> for Vec<T> {
38    fn as_ord(&self) -> &Vec<OrderedFloat<T>> {
39        // Safety: OrderedFloat is #[repr(transparent)] and has no invalid values, i.e. there is no physical difference between OrderedFloat and Float.
40        unsafe { &*(self as *const Vec<T> as *const Vec<OrderedFloat<T>>) }
41    }
42}
43
44/// An 'AlgorithmRepr' struct that represents the string output in the terminal after running an algorithm.
45///
46/// It returns the algorithm name, number of nodes in the graph, and the result type.
47///
48pub struct AlgorithmRepr {
49    pub algo_name: String,
50    pub result_type: String,
51}
52
53/// A generic `AlgorithmResult` struct that represents the result of an algorithm computation.
54///
55/// The `AlgorithmResult` contains a hashmap, where keys (`H`) are cloneable, hashable, and comparable,
56/// and values (`Y`) are cloneable. The keys and values can be of any type that satisfies the specified
57/// trait bounds.
58///
59/// This `AlgorithmResult` is returned for all algorithms that return a HashMap
60///
61pub struct AlgorithmResult<G, V, O = V> {
62    /// The result hashmap that stores keys of type `H` and values of type `Y`.
63    pub algo_repr: AlgorithmRepr,
64    pub graph: G,
65    pub result: HashMap<usize, V>,
66    marker: PhantomData<O>,
67}
68
69// use pyo3::{prelude::*, types::IntoPyDict};
70
71impl<'graph, G, V, O> AlgorithmResult<G, V, O>
72where
73    G: GraphViewOps<'graph>,
74    V: Clone,
75{
76    /// Creates a new instance of `AlgorithmResult` with the provided hashmap.
77    ///
78    /// Arguments:
79    ///
80    /// * `algo_name`: The name of the algorithm.
81    /// * `result_type`: The type of the result.
82    /// * `result`: A `Vec` with values of type `V`.
83    /// * `graph`: The Raphtory Graph object
84    pub fn new(graph: G, algo_name: &str, result_type: &str, result: HashMap<usize, V>) -> Self {
85        // let result_type = type_name::<V>();
86        Self {
87            algo_repr: AlgorithmRepr {
88                algo_name: algo_name.to_string(),
89                result_type: result_type.to_string(),
90            },
91            graph,
92            result,
93            marker: PhantomData,
94        }
95    }
96
97    /// Returns a reference to the entire `result` vector of values.
98    pub fn get_all_values(&self) -> Vec<V> {
99        self.result.clone().into_values().collect()
100    }
101
102    /// Returns the value corresponding to the provided key in the `result` hashmap.
103    ///
104    /// Arguments:
105    ///     `key`: The key of the node, can be the node object, or name.
106    pub fn get<T: AsNodeRef>(&self, name: T) -> Option<&V> {
107        let v = name.as_node_ref();
108        if self.graph.has_node(v) {
109            let internal_id = self.graph.node(v).unwrap().node.0;
110            self.result.get(&internal_id)
111        } else {
112            None
113        }
114    }
115
116    /// Returns a hashmap with node names and values
117    ///
118    /// Returns:
119    ///     a hashmap with node names and values
120    pub fn get_all_with_names(&self) -> HashMap<String, V> {
121        self.result
122            .iter()
123            .map(|(k, v)| (self.graph.node_name(VID(*k)), v.clone()))
124            .collect()
125    }
126
127    /// Returns a `HashMap` containing `NodeView<G>` keys and `Option<V>` values.
128    ///
129    /// Returns:
130    ///     a `HashMap` containing `NodeView<G>` keys and `Option<V>` values.
131    pub fn get_all(&self) -> HashMap<NodeView<G, G>, V> {
132        self.result
133            .iter()
134            .map(|(k, v)| {
135                (
136                    NodeView::new_internal(self.graph.clone(), VID(*k)),
137                    v.clone(),
138                )
139            })
140            .collect()
141    }
142
143    /// Sorts the `AlgorithmResult` by its node id in ascending or descending order.
144    ///
145    /// Arguments:
146    ///
147    /// * `reverse`: If `true`, sorts the result in descending order; otherwise, sorts in ascending order.
148    ///
149    /// Returns:
150    ///
151    /// A sorted vector of tuples containing node names and values.
152    pub fn sort_by_node(&self, reverse: bool) -> Vec<(NodeView<G, G>, V)> {
153        let mut sorted: Vec<(NodeView<G, G>, V)> = self.get_all().into_iter().collect();
154        sorted.sort_by(|(a, _), (b, _)| if reverse { b.cmp(a) } else { a.cmp(b) });
155        sorted
156    }
157
158    /// Sorts a collection of node views by their names in either ascending or descending order.
159    ///
160    /// Arguments:
161    ///
162    /// * `reverse`: A boolean value indicating whether the sorting should be in reverse order or not. If
163    /// `reverse` is `true`, the sorting will be in reverse order (descending), otherwise it will be in
164    /// ascending order.
165    ///
166    /// Returns:
167    ///
168    /// The function `sort_by_node_name` returns a vector of tuples, where each tuple contains a
169    /// `NodeView<G>` and an optional `V` value.
170    pub fn sort_by_node_name(&self, reverse: bool) -> Vec<(NodeView<G, G>, V)> {
171        let mut sorted: Vec<(NodeView<G, G>, V)> = self.get_all().into_iter().collect();
172        sorted.sort_by(|(a, _), (b, _)| {
173            if reverse {
174                b.name().cmp(&a.name())
175            } else {
176                a.name().cmp(&b.name())
177            }
178        });
179        sorted
180    }
181
182    /// The `iter` function returns an iterator over the elements of the `result` field.
183    ///
184    /// Returns:
185    ///
186    /// The `iter` method returns an iterator over the elements of the `result` field of the struct. The
187    /// iterator yields references to tuples containing a `usize` key and a `V` value.
188    pub fn iter(&self) -> Iter<'_, usize, V> {
189        self.result.iter()
190    }
191
192    /// Sorts the `AlgorithmResult` by its values in ascending or descending order.
193    ///
194    /// Arguments:
195    ///
196    /// * `reverse`: If `true`, sorts the result in descending order; otherwise, sorts in ascending order.
197    ///
198    /// Returns:
199    ///
200    /// A sorted vector of tuples containing node names and values.
201    pub fn sort_by_values<F: FnMut(&V, &V) -> std::cmp::Ordering>(
202        &self,
203        mut cmp: F,
204        reverse: bool,
205    ) -> Vec<(NodeView<G, G>, V)> {
206        let mut all_as_vec: Vec<(NodeView<G, G>, V)> = self.get_all().into_iter().collect();
207        all_as_vec.sort_by(|a, b| {
208            let order = cmp(&a.1, &b.1);
209            // Reverse the order if `reverse` is true
210            if reverse {
211                order.reverse()
212            } else {
213                order
214            }
215        });
216        all_as_vec
217    }
218
219    /// Retrieves the top-k elements from the `AlgorithmResult` based on its values.
220    ///
221    /// Arguments:
222    ///
223    /// * `k`: The number of elements to retrieve.
224    /// * `percentage`: If `true`, the `k` parameter is treated as a percentage of total elements.
225    /// * `reverse`: If `true`, retrieves the elements in descending order; otherwise, in ascending order.
226    ///
227    /// Returns:
228    ///
229    /// An `a vector of tuples with keys of type `H` and values of type `Y`.
230    /// If `percentage` is `true`, the returned vector contains the top `k` percentage of elements.
231    /// If `percentage` is `false`, the returned vector contains the top `k` elements.
232    /// Returns empty vec if the result is empty or if `k` is 0.
233    pub fn top_k_by<F: FnMut(&V, &V) -> std::cmp::Ordering>(
234        &self,
235        cmp: F,
236        k: usize,
237        percentage: bool,
238        reverse: bool,
239    ) -> Vec<(NodeView<G, G>, V)> {
240        let k = if percentage {
241            let total_count = self.result.len();
242            (total_count as f64 * (k as f64 / 100.0)) as usize
243        } else {
244            k
245        };
246        self.sort_by_values(cmp, reverse)
247            .into_iter()
248            .take(k)
249            .collect()
250    }
251
252    pub fn min_by<F: FnMut(&V, &V) -> std::cmp::Ordering>(
253        &self,
254        mut cmp: F,
255    ) -> Option<(NodeView<G, G>, V)> {
256        let min_element = self
257            .get_all()
258            .into_iter()
259            .min_by(|(_, a_value), (_, b_value)| cmp(a_value, b_value));
260
261        // Clone the key and value
262        min_element.map(|(k, v)| (k.clone(), v.clone()))
263    }
264
265    pub fn max_by<F: FnMut(&V, &V) -> std::cmp::Ordering>(
266        &self,
267        mut cmp: F,
268    ) -> Option<(NodeView<G, G>, V)> {
269        let max_element = self
270            .get_all()
271            .into_iter()
272            .max_by(|(_, a_value), (_, b_value)| cmp(a_value, b_value));
273
274        // Clone the key and value
275        max_element.map(|(k, v)| (k.clone(), v.clone()))
276    }
277
278    pub fn median_by<F: FnMut(&V, &V) -> std::cmp::Ordering>(
279        &self,
280        mut cmp: F,
281    ) -> Option<(NodeView<G, G>, V)> {
282        // Assuming self.result is Vec<(String, Option<V>)>
283        let mut items: Vec<(NodeView<G, G>, V)> = self.get_all().into_iter().collect();
284        let len = items.len();
285        if len == 0 {
286            return None;
287        }
288
289        items.sort_by(|(_, a_value), (_, b_value)| cmp(a_value, b_value));
290        let median_index = len / 2;
291
292        Some((items[median_index].0.clone(), items[median_index].1.clone()))
293    }
294
295    pub fn len(&self) -> usize {
296        self.result.len()
297    }
298}
299
300impl<'graph, G, V, O> AlgorithmResult<G, V, O>
301where
302    G: GraphViewOps<'graph>,
303    V: Clone,
304    O: Ord,
305    V: AsOrd<O>,
306{
307    pub fn group_by(&self) -> HashMap<V, Vec<String>>
308    where
309        V: Eq + Hash,
310    {
311        let mut groups: HashMap<V, Vec<String>> = HashMap::new();
312
313        for node in self.graph.nodes() {
314            if let Some(value) = self.result.get(&node.node.0) {
315                let entry = groups.entry(value.clone()).or_default();
316                entry.push(node.name().to_string());
317            }
318        }
319        groups
320    }
321
322    /// Sorts the `AlgorithmResult` by its values in ascending or descending order.
323    ///
324    /// Arguments:
325    ///
326    /// * `reverse`: If `true`, sorts the result in descending order; otherwise, sorts in ascending order.
327    ///
328    /// Returns:
329    ///
330    /// A sorted vector of tuples containing keys of type `H` and values of type `Y`.
331    pub fn sort_by_value(&self, reverse: bool) -> Vec<(NodeView<G, G>, V)> {
332        self.sort_by_values(|a, b| O::cmp(a.as_ord(), b.as_ord()), reverse)
333    }
334
335    /// Retrieves the top-k elements from the `AlgorithmResult` based on its values.
336    ///
337    /// Arguments:
338    ///
339    /// * `k`: The number of elements to retrieve.
340    /// * `percentage`: If `true`, the `k` parameter is treated as a percentage of total elements.
341    /// * `reverse`: If `true`, retrieves the elements in descending order; otherwise, in ascending order.
342    ///
343    /// Returns:
344    ///
345    /// An `a vector of tuples with keys of type `H` and values of type `Y`.
346    /// If `percentage` is `true`, the returned vector contains the top `k` percentage of elements.
347    /// If `percentage` is `false`, the returned vector contains the top `k` elements.
348    /// Returns empty vec if the result is empty or if `k` is 0.
349    pub fn top_k(&self, k: usize, percentage: bool, reverse: bool) -> Vec<(NodeView<G, G>, V)> {
350        self.top_k_by(
351            |a, b| O::cmp(a.as_ord(), b.as_ord()),
352            k,
353            percentage,
354            reverse,
355        )
356    }
357
358    /// Returns a tuple of the min result with its key
359    pub fn min(&self) -> Option<(NodeView<G, G>, V)> {
360        self.min_by(|a, b| O::cmp(a.as_ord(), b.as_ord()))
361    }
362
363    /// Returns a tuple of the max result with its key
364    pub fn max(&self) -> Option<(NodeView<G, G>, V)> {
365        self.max_by(|a, b| O::cmp(a.as_ord(), b.as_ord()))
366    }
367
368    /// Returns a tuple of the median result with its key
369    pub fn median(&self) -> Option<(NodeView<G, G>, V)> {
370        self.median_by(|a, b| O::cmp(a.as_ord(), b.as_ord()))
371    }
372}
373
374use crate::{
375    core::entities::{nodes::node_ref::AsNodeRef, VID},
376    db::graph::node::NodeView,
377    prelude::GraphViewOps,
378};
379use num_traits::float::FloatCore;
380use std::fmt;
381
382impl<'graph, G: GraphViewOps<'graph>, V: fmt::Debug, O> fmt::Display for AlgorithmResult<G, V, O> {
383    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384        writeln!(f, "AlgorithmResultNew {{")?;
385        writeln!(f, "  Algorithm Name: {}", self.algo_repr.algo_name)?;
386        writeln!(f, "  Result Type: {}", self.algo_repr.result_type)?;
387        writeln!(f, "  Number of Nodes: {}", self.result.len())?;
388        writeln!(f, "  Results: [")?;
389
390        for node in self.graph.nodes().iter() {
391            let value = self.result.get(&node.node.0);
392            writeln!(f, "    {}: {:?}", node.name(), value)?;
393        }
394
395        writeln!(f, "  ]")?;
396        writeln!(f, "}}")
397    }
398}
399
400impl<'graph, G: GraphViewOps<'graph>, V: fmt::Debug, O> fmt::Debug for AlgorithmResult<G, V, O> {
401    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402        writeln!(f, "AlgorithmResultNew {{")?;
403        writeln!(f, "  Algorithm Name: {:?}", self.algo_repr.algo_name)?;
404        writeln!(f, "  Result Type: {:?}", self.algo_repr.result_type)?;
405        writeln!(f, "  Number of Nodes: {:?}", self.result.len())?;
406        writeln!(f, "  Results: [")?;
407
408        for node in self.graph.nodes().iter() {
409            let value = self.result.get(&node.node.0);
410            writeln!(f, "    {:?}: {:?}", node.name(), value)?;
411        }
412
413        writeln!(f, "  ]")?;
414        writeln!(f, "}}")
415    }
416}
417
418/// Add tests for all functions
419#[cfg(test)]
420mod algorithm_result_test {
421    use super::*;
422    use crate::{
423        algorithms::components::weakly_connected_components,
424        db::{api::mutation::AdditionOps, graph::graph::Graph},
425        prelude::{NO_PROPS, *},
426    };
427    use ordered_float::OrderedFloat;
428    use raphtory_api::core::{entities::GID, utils::logging::global_info_logger};
429    use tracing::info;
430
431    fn create_algo_result_u64() -> AlgorithmResult<Graph, u64> {
432        let g = create_graph();
433        let mut map: HashMap<usize, u64> = HashMap::new();
434        map.insert(g.node("A").unwrap().node.0, 10);
435        map.insert(g.node("B").unwrap().node.0, 20);
436        map.insert(g.node("C").unwrap().node.0, 30);
437        let results_type = std::any::type_name::<u64>();
438        AlgorithmResult::new(g, "create_algo_result_u64_test", results_type, map)
439    }
440
441    fn create_graph() -> Graph {
442        let g = Graph::new();
443        g.add_node(0, "A", NO_PROPS, None)
444            .expect("Could not add node to graph");
445        g.add_node(0, "B", NO_PROPS, None)
446            .expect("Could not add node to graph");
447        g.add_node(0, "C", NO_PROPS, None)
448            .expect("Could not add node to graph");
449        g.add_node(0, "D", NO_PROPS, None)
450            .expect("Could not add node to graph");
451        g
452    }
453
454    fn group_by_test() -> AlgorithmResult<Graph, u64> {
455        let g = create_graph();
456        let mut map: HashMap<usize, u64> = HashMap::new();
457        map.insert(g.node("A").unwrap().node.0, 10);
458        map.insert(g.node("B").unwrap().node.0, 20);
459        map.insert(g.node("C").unwrap().node.0, 30);
460        map.insert(g.node("D").unwrap().node.0, 10);
461        let results_type = std::any::type_name::<u64>();
462        AlgorithmResult::new(g, "group_by_test", results_type, map)
463    }
464
465    fn create_algo_result_f64() -> AlgorithmResult<Graph, f64, OrderedFloat<f64>> {
466        let g = Graph::new();
467        g.add_node(0, "A", NO_PROPS, None)
468            .expect("Could not add node to graph");
469        g.add_node(0, "B", NO_PROPS, None)
470            .expect("Could not add node to graph");
471        g.add_node(0, "C", NO_PROPS, None)
472            .expect("Could not add node to graph");
473        g.add_node(0, "D", NO_PROPS, None)
474            .expect("Could not add node to graph");
475        let mut map: HashMap<usize, f64> = HashMap::new();
476        map.insert(g.node("A").unwrap().node.0, 10.0);
477        map.insert(g.node("B").unwrap().node.0, 20.0);
478        map.insert(g.node("C").unwrap().node.0, 30.0);
479        let results_type = std::any::type_name::<f64>();
480        AlgorithmResult::new(g, "create_algo_result_u64_test", results_type, map)
481    }
482
483    fn create_algo_result_tuple(
484    ) -> AlgorithmResult<Graph, (f32, f32), (OrderedFloat<f32>, OrderedFloat<f32>)> {
485        let g = create_graph();
486        let mut res: HashMap<usize, (f32, f32)> = HashMap::new();
487        res.insert(g.node("A").unwrap().node.0, (10.0, 20.0));
488        res.insert(g.node("B").unwrap().node.0, (20.0, 30.0));
489        res.insert(g.node("C").unwrap().node.0, (30.0, 40.0));
490        let results_type = std::any::type_name::<(f32, f32)>();
491        AlgorithmResult::new(g, "create_algo_result_tuple", results_type, res)
492    }
493
494    fn create_algo_result_hashmap_vec() -> AlgorithmResult<Graph, Vec<(i32, String)>> {
495        let g = create_graph();
496        let mut res: HashMap<usize, Vec<(i32, String)>> = HashMap::new();
497        res.insert(g.node("A").unwrap().node.0, vec![(11, "H".to_string())]);
498        res.insert(g.node("B").unwrap().node.0, vec![]);
499        res.insert(
500            g.node("C").unwrap().node.0,
501            vec![(22, "E".to_string()), (33, "F".to_string())],
502        );
503        let results_type = std::any::type_name::<(i32, String)>();
504        AlgorithmResult::new(g, "create_algo_result_hashmap_vec", results_type, res)
505    }
506
507    #[test]
508    fn test_min_max_value() {
509        let algo_result = create_algo_result_u64();
510        let v_a = algo_result.graph.node("A".to_string()).unwrap();
511        let v_b = algo_result.graph.node("B".to_string()).unwrap();
512        let v_c = algo_result.graph.node("C".to_string()).unwrap();
513        assert_eq!(algo_result.min(), Some((v_a.clone(), 10u64)));
514        assert_eq!(algo_result.max(), Some((v_c.clone(), 30u64)));
515        assert_eq!(algo_result.median(), Some((v_b.clone(), 20u64)));
516        let algo_result = create_algo_result_f64();
517        assert_eq!(algo_result.min(), Some((v_a, 10.0)));
518        assert_eq!(algo_result.max(), Some((v_c, 30.0)));
519        assert_eq!(algo_result.median(), Some((v_b, 20.0)));
520    }
521
522    #[test]
523    fn test_get() {
524        let algo_result = create_algo_result_u64();
525        let node_c = algo_result.graph.node("C").unwrap();
526        let node_d = algo_result.graph.node("D").unwrap();
527        assert_eq!(algo_result.get(node_c.clone()), Some(&30u64));
528        assert_eq!(algo_result.get(node_d.clone()), None);
529        let algo_result = create_algo_result_f64();
530        assert_eq!(algo_result.get(node_c.clone()), Some(&30.0f64));
531        let algo_result = create_algo_result_tuple();
532        assert_eq!(algo_result.get(node_c.clone()).unwrap().0, 30.0f32);
533        let algo_result = create_algo_result_hashmap_vec();
534        let answer = algo_result.get(node_c.clone()).unwrap().first().unwrap().0;
535        assert_eq!(answer, 22i32);
536    }
537
538    #[test]
539    fn test_sort() {
540        let algo_result = create_algo_result_u64();
541        let sorted = algo_result.sort_by_value(true);
542        let v_c = algo_result.graph.node("C").unwrap();
543        let v_b = algo_result.graph.node("B").unwrap();
544        let v_a = algo_result.graph.node("A").unwrap();
545        assert_eq!(sorted[0].0, v_c.clone());
546        let sorted = algo_result.sort_by_value(false);
547        assert_eq!(sorted[0].0, v_a.clone());
548
549        let algo_result = create_algo_result_f64();
550        let sorted = algo_result.sort_by_value(true);
551        assert_eq!(sorted[0].0, v_c.clone());
552        let sorted = algo_result.sort_by_value(false);
553        assert_eq!(sorted[0].0, v_a);
554        assert_eq!(sorted[1].0, v_b);
555
556        let algo_result = create_algo_result_tuple();
557        assert_eq!(algo_result.sort_by_value(true)[0].0, v_c.clone());
558
559        let algo_result = create_algo_result_hashmap_vec();
560        assert_eq!(algo_result.sort_by_value(true)[0].0, v_c);
561    }
562
563    #[test]
564    fn test_top_k() {
565        let algo_result = create_algo_result_u64();
566        let v_c = algo_result.graph.node("C").unwrap();
567        let v_a = algo_result.graph.node("A").unwrap();
568        let v_b = algo_result.graph.node("B").unwrap();
569
570        let top_k = algo_result.top_k(2, false, false);
571        assert_eq!(top_k[0].0, v_a.clone());
572        let top_k = algo_result.top_k(2, false, true);
573        assert_eq!(top_k[0].0, v_c.clone());
574
575        let algo_result = create_algo_result_f64();
576        let top_k = algo_result.top_k(2, false, false);
577        assert_eq!(top_k[0].0, v_a.clone());
578        assert_eq!(top_k[1].0, v_b.clone());
579        let top_k = algo_result.top_k(2, false, true);
580        assert_eq!(top_k[0].0, v_c);
581
582        let algo_result = create_algo_result_tuple();
583        assert_eq!(algo_result.top_k(2, false, false)[0].0, v_a.clone());
584        assert_eq!(algo_result.top_k(2, false, false)[1].0, v_b.clone());
585
586        let algo_result = create_algo_result_hashmap_vec();
587        assert_eq!(algo_result.top_k(2, false, false)[0].0, v_b);
588        assert_eq!(algo_result.top_k(2, false, false)[1].0, v_a);
589    }
590
591    #[test]
592    fn test_group_by() {
593        let algo_result = group_by_test();
594        let grouped = algo_result.group_by();
595        assert_eq!(grouped.get(&10).unwrap().len(), 2);
596        assert!(grouped.get(&10).unwrap().contains(&"A".to_string()));
597        assert!(!grouped.get(&10).unwrap().contains(&"B".to_string()));
598
599        let algo_result = create_algo_result_hashmap_vec();
600        assert_eq!(
601            algo_result
602                .group_by()
603                .get(&vec![(11, "H".to_string())])
604                .unwrap()
605                .len(),
606            1
607        );
608    }
609
610    #[test]
611    fn test_get_all_with_names() {
612        let algo_result = create_algo_result_u64();
613        let all = algo_result.get_all_values();
614        assert_eq!(all.len(), 3);
615
616        let algo_result = create_algo_result_f64();
617        let all = algo_result.get_all_values();
618        assert_eq!(all.len(), 3);
619
620        let algo_result = create_algo_result_tuple();
621        let algo_results_hashmap = algo_result.get_all_with_names();
622        let tuple_result = algo_results_hashmap.get("A").unwrap();
623        assert_eq!(tuple_result.0, 10.0);
624        assert_eq!(algo_result.get_all_values().len(), 3);
625
626        let algo_result = create_algo_result_hashmap_vec();
627        let algo_results_hashmap = algo_result.get_all_with_names();
628        let tuple_result = algo_results_hashmap.get("A").unwrap();
629        assert_eq!(tuple_result.clone().first().unwrap().0, 11);
630        assert_eq!(algo_result.get_all_values().len(), 3);
631    }
632
633    #[test]
634    fn test_sort_by_node() {
635        let algo_result = create_algo_result_u64();
636        let v_c = algo_result.graph.node("C").unwrap();
637        let v_a = algo_result.graph.node("A").unwrap();
638        let v_b = algo_result.graph.node("B").unwrap();
639        let sorted = algo_result.sort_by_node(true);
640        let my_array: Vec<(NodeView<Graph, Graph>, u64)> =
641            vec![(v_c, 30u64), (v_b, 20u64), (v_a, 10u64)];
642        assert_eq!(my_array, sorted);
643
644        let algo_result = create_algo_result_f64();
645        let v_c = algo_result.graph.node("C").unwrap();
646        let v_a = algo_result.graph.node("A").unwrap();
647        let v_b = algo_result.graph.node("B").unwrap();
648        let sorted = algo_result.sort_by_node(true);
649        let my_array: Vec<(NodeView<Graph, Graph>, f64)> =
650            vec![(v_c, 30.0), (v_b, 20.0), (v_a, 10.0)];
651        assert_eq!(my_array, sorted);
652
653        let algo_result = create_algo_result_tuple();
654        let v_c = algo_result.graph.node("C").unwrap();
655        let v_a = algo_result.graph.node("A").unwrap();
656        let v_b = algo_result.graph.node("B").unwrap();
657
658        let sorted = algo_result.sort_by_node(true);
659        let my_array: Vec<(NodeView<Graph, Graph>, (f32, f32))> = vec![
660            (v_c, (30.0, 40.0)),
661            (v_b, (20.0, 30.0)),
662            (v_a, (10.0, 20.0)),
663        ];
664        assert_eq!(my_array, sorted);
665        //
666        let algo_result = create_algo_result_hashmap_vec();
667        let v_c = algo_result.graph.node("C").unwrap();
668        let v_a = algo_result.graph.node("A").unwrap();
669        let v_b = algo_result.graph.node("B").unwrap();
670
671        let sorted = algo_result.sort_by_node(true);
672        let vec_c = vec![(22, "E".to_string()), (33, "F".to_string())];
673        let vec_b = vec![];
674        let vec_a = vec![(11, "H".to_string())];
675        let my_array: Vec<(NodeView<Graph, Graph>, Vec<(i32, String)>)> =
676            vec![(v_c, vec_c), (v_b, vec_b), (v_a, vec_a)];
677        assert_eq!(my_array, sorted);
678    }
679
680    #[test]
681    fn test_get_all() {
682        global_info_logger();
683        let algo_result = create_algo_result_u64();
684        let gotten_all = algo_result.get_all();
685        let names: Vec<String> = gotten_all.keys().map(|vv| vv.name()).collect();
686        info!("{:?}", names)
687    }
688
689    #[test]
690    fn test_windowed_graph() {
691        let g = Graph::new();
692        g.add_edge(0, 1, 2, NO_PROPS, Some("ZERO-TWO"))
693            .expect("Unable to add edge");
694        g.add_edge(1, 1, 3, NO_PROPS, Some("ZERO-TWO"))
695            .expect("Unable to add edge");
696        g.add_edge(2, 4, 5, NO_PROPS, Some("ZERO-TWO"))
697            .expect("Unable to add edge");
698        g.add_edge(3, 6, 7, NO_PROPS, Some("THREE-FIVE"))
699            .expect("Unable to add edge");
700        g.add_edge(4, 8, 9, NO_PROPS, Some("THREE-FIVE"))
701            .expect("Unable to add edge");
702        let g_layer = g.layers(vec!["ZERO-TWO"]).unwrap();
703        let res_window = weakly_connected_components(&g_layer, 20, None);
704        let mut expected_result = HashMap::new();
705        expected_result.insert("8".to_string(), GID::U64(8));
706        expected_result.insert("1".to_string(), GID::U64(1));
707        expected_result.insert("3".to_string(), GID::U64(1));
708        expected_result.insert("2".to_string(), GID::U64(1));
709        expected_result.insert("5".to_string(), GID::U64(4));
710        expected_result.insert("6".to_string(), GID::U64(6));
711        expected_result.insert("7".to_string(), GID::U64(7));
712        expected_result.insert("4".to_string(), GID::U64(4));
713        expected_result.insert("9".to_string(), GID::U64(9));
714        assert_eq!(res_window.get_all_with_names(), expected_result);
715    }
716}