Skip to content
Snippets Groups Projects
Commit 014aa88d authored by nanocryk's avatar nanocryk
Browse files

Merge branch '39-rustywot-get_paths-is-stuck-in-an-infinite-loop' into 'dev'

Resolve "RustyWot : get_paths is stuck in an infinite loop !"

Closes #39

See merge request !29
parents 20dc0a62 bcc296f5
No related branches found
No related tags found
1 merge request!29Resolve "RustyWot : get_paths is stuck in an infinite loop !"
...@@ -107,7 +107,7 @@ dependencies = [ ...@@ -107,7 +107,7 @@ dependencies = [
[[package]] [[package]]
name = "duniter-wotb" name = "duniter-wotb"
version = "0.7.0" version = "0.7.1"
dependencies = [ dependencies = [
"bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
......
[package] [package]
name = "duniter-wotb" name = "duniter-wotb"
version = "0.7.0" version = "0.7.1"
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"
......
...@@ -828,5 +828,39 @@ mod tests { ...@@ -828,5 +828,39 @@ mod tests {
outdistanced: false, outdistanced: false,
},) },)
); );
// Test centralities computation in g1_genesis wot
let wot_size = wot3.size();
let members_count = wot3.get_enabled().len() as u64;
assert_eq!(members_count, 59);
let oriented_couples_count: u64 = members_count * (members_count - 1);
let mut centralities = vec![0; wot_size];
for i in 0..wot_size {
for j in 0..wot_size {
let paths = wot3.get_paths(NodeId(i), NodeId(j), 5);
let mut intermediate_members: Vec<NodeId> = Vec::new();
for path in paths {
if path.len() > 2 {
for node_id in &path[1..path.len() - 1] {
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);
} }
} }
...@@ -219,34 +219,68 @@ impl WebOfTrust for RustyWebOfTrust { ...@@ -219,34 +219,68 @@ impl WebOfTrust for RustyWebOfTrust {
} }
fn get_paths(&self, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>> { fn get_paths(&self, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>> {
if from == to { // 1. We explore the k_max area around `to`, and only remember backward
vec![vec![to]] // links of the smallest distance.
} else if k_max > 0 {
self.nodes[to.0] // Stores for each node its distance to `to` node and its backward links.
.links_source // By default all nodes are out of range (`k_max + 1`) and links are known.
.par_iter() let mut graph: Vec<(u32, Vec<usize>)> =
.map(|&source| self.get_paths(from, source, k_max - 1)) self.nodes.iter().map(|_| (k_max + 1, vec![])).collect();
.map(|paths| { // `to` node is at distance 0, and have no backward links.
paths graph[to.0] = (0, vec![]);
.iter() // Explored zone border.
.map(|path| { let mut border = HashSet::new();
let mut path = path.clone(); border.insert(to.0);
path.push(to);
path for distance in 1..(k_max + 1) {
}) let mut next_border = HashSet::new();
.collect::<Vec<Vec<NodeId>>>()
}) for node in border {
.reduce( for source in &self.nodes[node].links_source {
|| vec![], if graph[source.0].0 > distance {
|mut acc, mut paths| { // shorter path, we replace
acc.append(&mut paths); graph[source.0] = (distance, vec![node]);
acc next_border.insert(source.0);
}, } else if graph[source.0].0 == distance {
) // same length, we combine
graph[source.0].1.push(node);
next_border.insert(source.0);
}
}
}
border = next_border;
}
// 2. If `from` is found, we follow the backward links and build paths.
// For each path, we look at the last element sources and build new paths with them.
let mut paths = vec![vec![from]];
for _ in 1..(k_max + 1) {
let mut new_paths = vec![];
for path in &paths {
let node = path.last().unwrap();
if node == &to {
// If path is complete, we keep it.
new_paths.push(path.clone())
} else { } else {
vec![] // If not complete we comlete paths
let sources = &graph[node.0];
for source in &sources.1 {
let mut new_path = path.clone();
new_path.push(NodeId(*source));
new_paths.push(new_path);
} }
} }
}
paths = new_paths;
}
paths
}
fn compute_distance(&self, params: WotDistanceParameters) -> Option<WotDistance> { fn compute_distance(&self, params: WotDistanceParameters) -> Option<WotDistance> {
let WotDistanceParameters { let WotDistanceParameters {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment