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 = [
[[package]]
name = "duniter-wotb"
version = "0.7.0"
version = "0.7.1"
dependencies = [
"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)",
......
[package]
name = "duniter-wotb"
version = "0.7.0"
version = "0.7.1"
authors = ["nanocryk <nanocryk@duniter.org>", "elois <elois@duniter.org>"]
description = "Makes Web of Trust computations for the Duniter project."
repository = "https://git.duniter.org/nodes/rust/duniter-rs"
......
......@@ -828,5 +828,39 @@ mod tests {
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 {
}
fn get_paths(&self, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>> {
if from == to {
vec![vec![to]]
} else if k_max > 0 {
self.nodes[to.0]
.links_source
.par_iter()
.map(|&source| self.get_paths(from, source, k_max - 1))
.map(|paths| {
paths
.iter()
.map(|path| {
let mut path = path.clone();
path.push(to);
path
})
.collect::<Vec<Vec<NodeId>>>()
})
.reduce(
|| vec![],
|mut acc, mut paths| {
acc.append(&mut paths);
acc
},
)
// 1. We explore the k_max area around `to`, and only remember backward
// links of the smallest distance.
// Stores for each node its distance to `to` node and its backward links.
// By default all nodes are out of range (`k_max + 1`) and links are known.
let mut graph: Vec<(u32, Vec<usize>)> =
self.nodes.iter().map(|_| (k_max + 1, vec![])).collect();
// `to` node is at distance 0, and have no backward links.
graph[to.0] = (0, vec![]);
// Explored zone border.
let mut border = HashSet::new();
border.insert(to.0);
for distance in 1..(k_max + 1) {
let mut next_border = HashSet::new();
for node in border {
for source in &self.nodes[node].links_source {
if graph[source.0].0 > distance {
// shorter path, we replace
graph[source.0] = (distance, vec![node]);
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 {
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> {
let WotDistanceParameters {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment