whitaker_common/test_support/
decomposition_label_propagation.rs1use crate::decomposition_advice::{
4 MethodProfileBuilder, build_feature_vector,
5 community::{
6 LabelPropagationReport as RuntimeLabelPropagationReport,
7 propagate_labels_report as runtime_propagate_labels_report,
8 },
9};
10
11use super::adjacency::{AdjacencyError, EdgeInput, validate_edges};
12
13#[derive(Clone, Debug, Eq, PartialEq)]
36pub struct LabelPropagationReport {
37 runtime: RuntimeLabelPropagationReport,
38 has_active_nodes: bool,
39}
40
41impl LabelPropagationReport {
42 #[must_use]
44 pub fn labels(&self) -> &[usize] {
45 &self.runtime.labels
46 }
47
48 #[must_use]
51 pub fn label_of(&self, node: usize) -> Option<usize> {
52 self.labels().get(node).copied()
53 }
54
55 #[must_use]
57 pub fn iteration_count(&self) -> usize {
58 self.runtime.iteration_count
59 }
60
61 #[must_use]
63 pub fn has_active_nodes(&self) -> bool {
64 self.has_active_nodes
65 }
66
67 #[must_use]
69 pub fn all_labels_in_bounds(&self) -> bool {
70 self.runtime
71 .labels
72 .iter()
73 .all(|&label| label < self.runtime.labels.len())
74 }
75}
76
77pub fn label_propagation_report(
84 method_names: &[&str],
85 edges: &[EdgeInput],
86 max_iterations: usize,
87) -> Result<LabelPropagationReport, AdjacencyError> {
88 let similarity_edges = validate_edges(method_names.len(), edges)?;
89 let adjacency = crate::decomposition_advice::community::build_adjacency(
90 method_names.len(),
91 &similarity_edges,
92 );
93 let vectors = method_names
94 .iter()
95 .map(|method_name| build_feature_vector(&MethodProfileBuilder::new(*method_name).build()))
96 .collect::<Vec<_>>();
97 let has_active_nodes = adjacency.iter().any(|neighbours| !neighbours.is_empty());
98 let runtime = runtime_propagate_labels_report(&vectors, &adjacency, max_iterations);
99
100 Ok(LabelPropagationReport {
101 runtime,
102 has_active_nodes,
103 })
104}