phago_runtime/
curriculum.rs1use crate::community::CommunityResult;
9use crate::export::WeightedTriple;
10use serde::Serialize;
11
12#[derive(Debug, Clone, Serialize)]
14pub struct Curriculum {
15 pub foundation: Vec<WeightedTriple>,
16 pub bridges: Vec<WeightedTriple>,
17 pub periphery: Vec<WeightedTriple>,
18}
19
20impl Curriculum {
21 pub fn total(&self) -> usize {
23 self.foundation.len() + self.bridges.len() + self.periphery.len()
24 }
25
26 pub fn ordered(&self) -> Vec<&WeightedTriple> {
28 self.foundation.iter()
29 .chain(self.bridges.iter())
30 .chain(self.periphery.iter())
31 .collect()
32 }
33}
34
35pub fn build_curriculum(
41 triples: &[WeightedTriple],
42 communities: &CommunityResult,
43) -> Curriculum {
44 if triples.is_empty() {
45 return Curriculum {
46 foundation: Vec::new(),
47 bridges: Vec::new(),
48 periphery: Vec::new(),
49 };
50 }
51
52 let mut weights: Vec<f64> = triples.iter().map(|t| t.weight).collect();
54 weights.sort_by(|a, b| a.partial_cmp(b).unwrap());
55 let median = weights[weights.len() / 2];
56
57 let mut foundation = Vec::new();
58 let mut bridges = Vec::new();
59 let mut periphery = Vec::new();
60
61 for triple in triples {
62 let subj_community = communities.assignments.get(&triple.subject);
63 let obj_community = communities.assignments.get(&triple.object);
64
65 match (subj_community, obj_community) {
66 (Some(sc), Some(oc)) if sc != oc => {
67 bridges.push(triple.clone());
68 }
69 _ => {
70 if triple.weight > median {
71 foundation.push(triple.clone());
72 } else {
73 periphery.push(triple.clone());
74 }
75 }
76 }
77 }
78
79 foundation.sort_by(|a, b| b.weight.partial_cmp(&a.weight).unwrap_or(std::cmp::Ordering::Equal));
81 bridges.sort_by(|a, b| b.weight.partial_cmp(&a.weight).unwrap_or(std::cmp::Ordering::Equal));
82 periphery.sort_by(|a, b| b.weight.partial_cmp(&a.weight).unwrap_or(std::cmp::Ordering::Equal));
83
84 Curriculum {
85 foundation,
86 bridges,
87 periphery,
88 }
89}