Skip to content
Snippets Groups Projects
Commit 90c5b9db authored by Éloïs's avatar Éloïs
Browse files

Merge branch '65-impl-distance-variant-of-stress-centrality-algo' into 'dev'

Resolve "impl distance variant of stress centrality algo"

Closes #65

See merge request !55
parents 8264643c e717c03d
Branches
Tags
1 merge request!55Resolve "impl distance variant of stress centrality algo"
[package] [package]
name = "duniter-wotb" name = "duniter-wotb"
version = "0.8.0-a0.5" version = "0.8.0-a0.6"
authors = ["nanocryk <nanocryk@duniter.org>", "elois <elois@duniter.org>"] authors = ["nanocryk <nanocryk@duniter.org>", "elois <elois@duniter.org>"]
description = "Makes Web of Trust computations for the Duniter project." description = "Makes Web of Trust computations for the Duniter project."
repository = "https://git.duniter.org/nodes/rust/duniter-rs" repository = "https://git.duniter.org/nodes/rust/duniter-rs"
......
...@@ -589,37 +589,19 @@ mod tests { ...@@ -589,37 +589,19 @@ mod tests {
0, 9, 55, 216, 865, 0, 9, 55, 216, 865,
] ]
); );
/*let wot_size = wot3.size();
let members_count = wot3.get_enabled().len() as u64; // Test distance stress centralities computation in g1_genesis wot
assert_eq!(members_count, 59); let distance_stress_centralities =
let oriented_couples_count: u64 = members_count * (members_count - 1); centralities_calculator.distance_stress_centralities(&wot3, 5);
let mut centralities = vec![0; wot_size]; assert_eq!(distance_stress_centralities.len(), 59);
for i in 0..wot_size { assert_eq!(
for j in 0..wot_size { distance_stress_centralities,
let paths = path_finder.find_paths(&wot3, NodeId(i), NodeId(j), 5); vec![
let mut intermediate_members: Vec<NodeId> = Vec::new(); 848, 240, 955, 80, 416, 203, 290, 645, 166, 908, 313, 231, 101, 202, 487, 769, 984,
for path in paths { 0, 154, 534, 105, 697, 260, 700, 496, 1726, 711, 160, 217, 192, 89, 430, 636, 1276,
if path.len() > 2 { 41, 420, 310, 0, 357, 125, 50, 15, 0, 12, 275, 170, 215, 1199, 0, 0, 0, 0, 201, 31,
for node_id in &path[1..path.len() - 1] { 0, 9, 55, 216, 865,
if !intermediate_members.contains(node_id) { ]
intermediate_members.push(*node_id); );
}
}
}
}
let centralities_copy = centralities.clone();
for node_id in intermediate_members {
let centrality = &centralities_copy[node_id.0];
if let Some(tmp) = centralities.get_mut(node_id.0) {
*tmp = *centrality + 1;
}
}
}
}
let mut relative_centralities = Vec::with_capacity(wot_size);
for centrality in centralities {
relative_centralities.push((centrality * 100_000 / oriented_couples_count) as usize);
}
assert_eq!(relative_centralities.len(), 59);*/
} }
} }
...@@ -25,9 +25,11 @@ pub trait CentralitiesCalculator<T: WebOfTrust> { ...@@ -25,9 +25,11 @@ pub trait CentralitiesCalculator<T: WebOfTrust> {
fn betweenness_centralities(&self, wot: &T) -> Vec<u64>; fn betweenness_centralities(&self, wot: &T) -> Vec<u64>;
/// Compute stress centrality of all members. /// Compute stress centrality of all members.
fn stress_centralities(&self, wot: &T) -> Vec<u64>; fn stress_centralities(&self, wot: &T) -> Vec<u64>;
/// Compute distance stress centrality of all members.
fn distance_stress_centralities(&self, wot: &T, step_max: usize) -> Vec<u64>;
} }
/// A new "rusty-er" implementation of `WoT` path finding. /// An implementation based on "Ulrik brandes" algo.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct UlrikBrandesCentralityCalculator; pub struct UlrikBrandesCentralityCalculator;
...@@ -138,4 +140,59 @@ impl<T: WebOfTrust> CentralitiesCalculator<T> for UlrikBrandesCentralityCalculat ...@@ -138,4 +140,59 @@ impl<T: WebOfTrust> CentralitiesCalculator<T> for UlrikBrandesCentralityCalculat
} }
centralities.into_iter().map(|c| c as u64).collect() centralities.into_iter().map(|c| c as u64).collect()
} }
fn distance_stress_centralities(&self, wot: &T, step_max: usize) -> Vec<u64> {
let wot_size = wot.size();
let mut centralities = vec![0.0; wot_size];
let enabled_nodes = wot.get_enabled();
// The source of any path belongs to enabled_nodes
for s in enabled_nodes.clone() {
let mut stack: Vec<NodeId> = Vec::with_capacity(wot_size);
let mut paths: HashMap<NodeId, Vec<NodeId>> = HashMap::with_capacity(wot_size);
let mut sigma = vec![0.0; wot_size];
let mut d: Vec<isize> = vec![-1; wot_size];
let mut q: VecDeque<NodeId> = VecDeque::with_capacity(wot_size);
sigma[s.0] = 1.0;
d[s.0] = 0;
q.push_back(s);
while !q.is_empty() {
let v = q.pop_front().unwrap();
stack.push(v);
if d[v.0] < step_max as isize {
for w in wot.get_links_source(v).expect("v don't have any source !") {
// w found for the first time ?
if d[w.0] < 0 {
q.push_back(w);
d[w.0] = d[v.0] + 1;
}
// Shortest path to w via v
if d[w.0] == d[v.0] + 1 {
sigma[w.0] += sigma[v.0];
paths.entry(w).or_insert_with(Vec::new).push(v);
}
}
}
}
let mut delta = vec![0.0; wot_size];
// stack returns vertices in order of non-increasing distance from s
while !stack.is_empty() {
let w = stack.pop().unwrap();
if paths.contains_key(&w) {
for v in paths.get(&w).expect("Not found w in p !") {
if enabled_nodes.contains(&w) {
delta[v.0] += sigma[v.0] * (1.0 + (delta[w.0] / sigma[w.0]));
} else {
// If w not in enabled_nodes, no path can end at w
delta[v.0] += sigma[v.0] * (delta[w.0] / sigma[w.0]);
}
}
}
if w != s {
centralities[w.0] += delta[w.0];
}
}
}
centralities.into_iter().map(|c| c as u64).collect()
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment