From 3ab293050fc34f70c8ea9888c9444f9e2661e5dc Mon Sep 17 00:00:00 2001 From: narnolddd Date: Tue, 28 Mar 2023 18:37:09 +0100 Subject: [PATCH 1/9] Counter objects ported over from old Raphtory --- docbrown/db/src/algorithms.rs | 1 + .../db/src/algorithms/three_node_motifs.rs | 168 ++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 docbrown/db/src/algorithms/three_node_motifs.rs diff --git a/docbrown/db/src/algorithms.rs b/docbrown/db/src/algorithms.rs index 7974500a..9d1b8815 100644 --- a/docbrown/db/src/algorithms.rs +++ b/docbrown/db/src/algorithms.rs @@ -4,3 +4,4 @@ pub mod global_triangle_count; pub mod local_clustering_coefficient; pub mod local_triangle_count; pub mod reciprocity; +pub mod three_node_motifs; diff --git a/docbrown/db/src/algorithms/three_node_motifs.rs b/docbrown/db/src/algorithms/three_node_motifs.rs new file mode 100644 index 00000000..d78709fe --- /dev/null +++ b/docbrown/db/src/algorithms/three_node_motifs.rs @@ -0,0 +1,168 @@ +use std::ops::Index; + +use itertools::enumerate; + +use crate::view_api::*; + +const incoming: usize = 0; +const outgoing: usize = 1; +const dirs2D: [(usize,usize);4] = [(0,0),(0,1),(1,0),(1,1)]; + +fn map2D(d1:usize, d2:usize) -> usize { + 2*d1 + d2 +} +fn map3D(d1:usize, d2:usize, d3:usize) -> usize { + 4*d1 + 2*d2 + d3 +} + +// Two Node Motifs +struct TwoNodeEvent{ + dir:usize, + time:usize, +} +struct TwoNodeCounter { + count1d:[u64;2], + count2d:[u64;4], + count3d:[u64;8], +} +impl TwoNodeCounter { + + fn execute(&mut self, events:&[TwoNodeEvent], delta: usize) { + let mut start = 0; + for item in enumerate(events) { + let (end, event): (usize, &TwoNodeEvent) = item; + while events[start].time + delta < events[end].time { + self.decrement_counts(events[start].dir); + start +=1; + } + self.increment_counts(events[start].dir); + } + } + + fn decrement_counts(&mut self, dir:usize) { + self.count1d[dir]-=1; + self.count2d[map2D(dir, incoming)] -= self.count1d[incoming]; + self.count2d[map2D(dir,outgoing)] -= self.count1d[outgoing]; + } + + fn increment_counts(&mut self, dir:usize) { + // 3d counter + for (d1,d2) in dirs2D { + self.count3d[map3D(d1, d2, dir)] += self.count2d[map2D(d1, d2)]; + } + // 2d counter + self.count2d[map2D(incoming,dir)]+=self.count1d[incoming]; + self.count2d[map2D(outgoing, dir)]+=self.count1d[outgoing]; + // 1d counter + self.count1d[dir]+=1; + } +} + +// Star Motifs +struct StarEvent{ + nb:usize, + dir:usize, + time:usize, +} +struct StarCounter{ + N: usize, + pre_nodes:Vec, + post_nodes:Vec, + pre_sum:[usize;8], + mid_sum:[usize;8], + post_sum:[usize;8], + count_pre:[usize;8], + count_mid:[usize;8], + count_post:[usize;8], + final_counts:[usize;8], +} +impl StarCounter { + fn push_pre(&mut self, cur_edge:&StarEvent) { + self.pre_sum[map2D(incoming, cur_edge.dir)] += self.pre_nodes[incoming*self.N + cur_edge.nb]; + self.pre_sum[map2D(outgoing, cur_edge.dir)] += self.pre_nodes[outgoing*self.N + cur_edge.nb]; + self.pre_nodes[cur_edge.dir*self.N + cur_edge.nb] += 1; + } + + fn push_post(&mut self, cur_edge:&StarEvent) { + self.post_sum[map2D(incoming, cur_edge.dir)] += self.post_nodes[incoming*self.N + cur_edge.nb]; + self.post_sum[map2D(outgoing, cur_edge.dir)] += self.post_nodes[outgoing*self.N + cur_edge.nb]; + self.post_nodes[cur_edge.dir*self.N + cur_edge.nb] += 1; + } + + fn pop_pre(&mut self, cur_edge:&StarEvent) { + self.pre_sum[map2D(cur_edge.dir, incoming)] -= self.pre_nodes[incoming*self.N + cur_edge.nb]; + self.pre_sum[map2D(cur_edge.dir, outgoing)] -= self.pre_nodes[outgoing*self.N + cur_edge.nb]; + } + + fn pop_post(&mut self, cur_edge:&StarEvent) { + self.post_sum[map2D(cur_edge.dir, incoming)] -= self.post_nodes[incoming*self.N + cur_edge.nb]; + self.post_sum[map2D(cur_edge.dir, outgoing)] -= self.post_nodes[outgoing*self.N + cur_edge.nb]; + } + + fn process_current(&mut self, &cur_edge:&StarEvent) { + self.mid_sum[map2D(incoming, cur_edge.dir)] -= self.pre_nodes[incoming*self.N + cur_edge.nb]; + self.mid_sum[map2D(outgoing, cur_edge.dir)] -= self.pre_nodes[outgoing*self.N + cur_edge.nb]; + + for (d1,d2) in dirs2D { + self.count_pre[map3D(d1, d2, cur_edge.dir)] += self.pre_sum[map2D(d1, d2)]; + self.count_post[map3D(cur_edge.dir, d1, d2)] += self.mid_sum[map2D(d1, d2)]; + self.count_mid[map3D(d1, cur_edge.dir, d2)] += self.mid_sum[map2D(d1, d2)]; + } + + self.mid_sum[map2D(cur_edge.dir, incoming)] += self.post_nodes[incoming*self.N + cur_edge.nb]; + self.mid_sum[map2D(cur_edge.dir, outgoing)] += self.post_nodes[outgoing*self.N + cur_edge.nb]; + } + + fn execute(&mut self, edges:&[StarEvent], delta:usize) { + let L = edges.len(); + if L < 3 { + return; + } + let mut start = 0; + let mut end = 0; + for j in 0..L { + while start < L && edges[start].time + delta < edges[j].time { + self.pop_pre(&edges[start]); + start+=1; + } + while (end < L) && edges[end].time <= edges[j].time + delta { + self.push_post(&edges[end]); + end+=1; + } + self.pop_post(&edges[j]); + self.process_current(&edges[j]); + self.push_pre(&edges[j]) + } + } + + fn concat_counts(&self) -> Vec { + [self.count_pre,self.count_mid,self.count_post].concat() + } +} +fn init_star_count(neighbours:Vec) -> StarCounter { + let N = neighbours.len(); + StarCounter {N:N, pre_nodes: vec![0;2*N], post_nodes: vec![0;2*N], pre_sum: [0;8], mid_sum: [0;8], post_sum: [0;8], + count_pre:[0;8], count_mid:[0;8], count_post:[0;8], final_counts: [0;8] } +} + +// Triad Motifs + +#[cfg(test)] +mod three_node_motifs_test { +use super::{map2D, TwoNodeEvent,incoming,outgoing, TwoNodeCounter}; + + #[test] + fn map_test() { + assert_eq!(map2D(1,1),3); + } + + #[test] + fn two_node_test() { + let events = [TwoNodeEvent{dir:outgoing,time:1}, TwoNodeEvent{dir:outgoing,time:2}, TwoNodeEvent{dir:outgoing,time:3}]; + let mut twonc = TwoNodeCounter{count1d:[0;2],count2d:[0;4],count3d:[0;8]}; + twonc.execute(&events, 5); + println!("motifs are {:?}",twonc.count3d); + } + + +} \ No newline at end of file From 4dbd8f1f8b8ce09c4112307acf649837176d403e Mon Sep 17 00:00:00 2001 From: narnolddd Date: Wed, 29 Mar 2023 16:01:00 +0100 Subject: [PATCH 2/9] interface classes for motif counting complete --- .../db/src/algorithms/three_node_motifs.rs | 86 +++++++++++++++++-- 1 file changed, 79 insertions(+), 7 deletions(-) diff --git a/docbrown/db/src/algorithms/three_node_motifs.rs b/docbrown/db/src/algorithms/three_node_motifs.rs index d78709fe..c729d0b2 100644 --- a/docbrown/db/src/algorithms/three_node_motifs.rs +++ b/docbrown/db/src/algorithms/three_node_motifs.rs @@ -18,7 +18,7 @@ fn map3D(d1:usize, d2:usize, d3:usize) -> usize { // Two Node Motifs struct TwoNodeEvent{ dir:usize, - time:usize, + time:i64, } struct TwoNodeCounter { count1d:[u64;2], @@ -27,11 +27,10 @@ struct TwoNodeCounter { } impl TwoNodeCounter { - fn execute(&mut self, events:&[TwoNodeEvent], delta: usize) { + fn execute(&mut self, events:&[TwoNodeEvent], delta: i64) { let mut start = 0; - for item in enumerate(events) { - let (end, event): (usize, &TwoNodeEvent) = item; - while events[start].time + delta < events[end].time { + for event in events.iter() { + while events[start].time + delta < event.time { self.decrement_counts(events[start].dir); start +=1; } @@ -99,7 +98,7 @@ impl StarCounter { self.post_sum[map2D(cur_edge.dir, outgoing)] -= self.post_nodes[outgoing*self.N + cur_edge.nb]; } - fn process_current(&mut self, &cur_edge:&StarEvent) { + fn process_current(&mut self, cur_edge:&StarEvent) { self.mid_sum[map2D(incoming, cur_edge.dir)] -= self.pre_nodes[incoming*self.N + cur_edge.nb]; self.mid_sum[map2D(outgoing, cur_edge.dir)] -= self.pre_nodes[outgoing*self.N + cur_edge.nb]; @@ -145,7 +144,80 @@ fn init_star_count(neighbours:Vec) -> StarCounter { count_pre:[0;8], count_mid:[0;8], count_post:[0;8], final_counts: [0;8] } } -// Triad Motifs +// Triangle Motifs +struct TriangleEdge{ + uv_edge:bool, + uorv:usize, + nb:usize, + dir:usize, +} +struct TriangleCounter { + N:usize, + pre_nodes:Vec, + post_nodes:Vec, + pre_sum:[usize;8], + mid_sum:[usize;8], + post_sum:[usize;8], + final_counts:[usize;8], +} + +impl TriangleCounter { + fn push_pre(&mut self,cur_edge:&TriangleEdge) { + let (isUorV, nb, dir) = (cur_edge.uorv, cur_edge.nb, cur_edge.dir); + if !cur_edge.uv_edge { + self.pre_sum[map3D(1-isUorV, incoming, dir)] += self.pre_nodes[self.N * map2D(incoming, 1 - isUorV) + nb]; + self.pre_sum[map3D(1-isUorV, outgoing, dir)] += self.pre_nodes[self.N * map2D(outgoing, 1 - isUorV) + nb]; + self.pre_nodes[self.N*map2D(dir, isUorV) + nb] +=1; + } + } + + fn push_post(&mut self,cur_edge:&TriangleEdge) { + let (isUorV, nb, dir) = (cur_edge.uorv, cur_edge.nb, cur_edge.dir); + if !cur_edge.uv_edge { + self.post_sum[map3D(1-isUorV, incoming, dir)] += self.post_nodes[self.N * map2D(incoming, 1 - isUorV) + nb]; + self.post_sum[map3D(1-isUorV, outgoing, dir)] += self.post_nodes[self.N * map2D(outgoing, 1 - isUorV) + nb]; + self.post_nodes[self.N*map2D(dir, isUorV) + nb] +=1; + } + } + + fn pop_pre(&mut self, cur_edge:&TriangleEdge) { + let (isUorV, nb, dir) = (cur_edge.uorv, cur_edge.nb, cur_edge.dir); + if !cur_edge.uv_edge { + self.pre_nodes[self.N * map2D(dir, isUorV) + nb] -= 1; + self.pre_sum[map3D(isUorV, dir, incoming)] -= self.pre_nodes[self.N * map2D(incoming, 1-isUorV)]; + self.pre_sum[map3D(isUorV, dir, outgoing)] -= self.pre_nodes[self.N * map2D(outgoing, 1-isUorV)]; + } + } + + fn pop_post(&mut self, cur_edge:&TriangleEdge) { + let (isUorV, nb, dir) = (cur_edge.uorv, cur_edge.nb, cur_edge.dir); + if !cur_edge.uv_edge { + self.post_nodes[self.N * map2D(dir, isUorV) + nb] -= 1; + self.post_sum[map3D(isUorV, dir, incoming)] -= self.post_nodes[self.N * map2D(incoming, 1-isUorV)]; + self.post_sum[map3D(isUorV, dir, outgoing)] -= self.post_nodes[self.N * map2D(outgoing, 1-isUorV)]; + } + } + + fn process_current(&mut self, cur_edge:&TriangleEdge) { + let (isUorV, nb, dir) = (cur_edge.uorv, cur_edge.nb, cur_edge.dir); + if !cur_edge.uv_edge { + self.mid_sum[map3D(1-isUorV, incoming, dir)] -= self.pre_nodes[self.N * map2D(incoming, 1-isUorV) + nb]; + self.mid_sum[map3D(1-isUorV, outgoing, dir)] -= self.pre_nodes[self.N * map2D(outgoing, 1-isUorV) + nb]; + self.mid_sum[map3D(isUorV, dir, incoming)] += self.post_nodes[self.N * map2D(incoming, 1-isUorV) + nb]; + self.mid_sum[map3D(isUorV, dir, outgoing)] += self.post_nodes[self.N * map2D(outgoing, 1-isUorV) + nb]; + } + else { + self.final_counts[0] += self.mid_sum[map3D(dir,0,0)] + self.post_sum[map3D(dir, 0, 1)] + self.pre_sum[map3D(1-dir,1,1)]; + self.final_counts[4] += self.mid_sum[map3D(dir,1,0)] + self.post_sum[map3D(1-dir, 0, 1)] + self.pre_sum[map3D(1-dir,0,1)]; + self.final_counts[2] += self.mid_sum[map3D(1-dir,0,0)] + self.post_sum[map3D(dir, 1, 1)] + self.pre_sum[map3D(1-dir,1,0)]; + self.final_counts[6] += self.mid_sum[map3D(1-dir,1,0)] + self.post_sum[map3D(1-dir, 1, 1)] + self.pre_sum[map3D(1-dir,0,0)]; + self.final_counts[1] += self.mid_sum[map3D(dir,0,1)] + self.post_sum[map3D(dir, 0, 0)] + self.pre_sum[map3D(dir,1,1)]; + self.final_counts[5] += self.mid_sum[map3D(dir,1,1)] + self.post_sum[map3D(1-dir, 0, 0)] + self.pre_sum[map3D(dir,0,1)]; + self.final_counts[3] += self.mid_sum[map3D(1-dir,0,1)] + self.post_sum[map3D(dir, 1, 0)] + self.pre_sum[map3D(dir,1,0)]; + self.final_counts[7] += self.mid_sum[map3D(1-dir,1,1)] + self.post_sum[map3D(1-dir, 1, 0)] + self.pre_sum[map3D(dir,0,0)]; + } + } +} #[cfg(test)] mod three_node_motifs_test { From 040ea0c725f6c13b816e7a937f0883e2448c728d Mon Sep 17 00:00:00 2001 From: narnolddd Date: Wed, 29 Mar 2023 17:03:40 +0100 Subject: [PATCH 3/9] clear up unused imports --- docbrown/db/src/algorithms/three_node_motifs.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docbrown/db/src/algorithms/three_node_motifs.rs b/docbrown/db/src/algorithms/three_node_motifs.rs index c729d0b2..3af547be 100644 --- a/docbrown/db/src/algorithms/three_node_motifs.rs +++ b/docbrown/db/src/algorithms/three_node_motifs.rs @@ -1,9 +1,3 @@ -use std::ops::Index; - -use itertools::enumerate; - -use crate::view_api::*; - const incoming: usize = 0; const outgoing: usize = 1; const dirs2D: [(usize,usize);4] = [(0,0),(0,1),(1,0),(1,1)]; From 2606d7f4481dbc7bbde05c602ce6338363fc5861 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Wed, 29 Mar 2023 17:05:49 +0100 Subject: [PATCH 4/9] placeholder algorithm for three node motifs --- docbrown/db/src/algorithms.rs | 1 + docbrown/db/src/algorithms/three_node_local.rs | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 docbrown/db/src/algorithms/three_node_local.rs diff --git a/docbrown/db/src/algorithms.rs b/docbrown/db/src/algorithms.rs index 9d1b8815..3c2512e1 100644 --- a/docbrown/db/src/algorithms.rs +++ b/docbrown/db/src/algorithms.rs @@ -5,3 +5,4 @@ pub mod local_clustering_coefficient; pub mod local_triangle_count; pub mod reciprocity; pub mod three_node_motifs; +pub mod three_node_local; diff --git a/docbrown/db/src/algorithms/three_node_local.rs b/docbrown/db/src/algorithms/three_node_local.rs new file mode 100644 index 00000000..ae71a9f4 --- /dev/null +++ b/docbrown/db/src/algorithms/three_node_local.rs @@ -0,0 +1,2 @@ +use crate::view_api::*; +use crate::algorithms::three_node_motifs::*; From 77d7203164726210c953378554593bb79ae53153 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Tue, 11 Apr 2023 09:43:35 +0100 Subject: [PATCH 5/9] three nodes interface class --- .../db/src/algorithms/three_node_motifs.rs | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/docbrown/db/src/algorithms/three_node_motifs.rs b/docbrown/db/src/algorithms/three_node_motifs.rs index 3af547be..681ce3eb 100644 --- a/docbrown/db/src/algorithms/three_node_motifs.rs +++ b/docbrown/db/src/algorithms/three_node_motifs.rs @@ -106,7 +106,7 @@ impl StarCounter { self.mid_sum[map2D(cur_edge.dir, outgoing)] += self.post_nodes[outgoing*self.N + cur_edge.nb]; } - fn execute(&mut self, edges:&[StarEvent], delta:usize) { + fn execute(&mut self, edges:&Vec, delta:usize) { let L = edges.len(); if L < 3 { return; @@ -144,6 +144,7 @@ struct TriangleEdge{ uorv:usize, nb:usize, dir:usize, + time:i64, } struct TriangleCounter { N:usize, @@ -154,8 +155,30 @@ struct TriangleCounter { post_sum:[usize;8], final_counts:[usize;8], } - impl TriangleCounter { + + fn execute(&mut self, edges:&Vec, delta:i64) { + let L = edges.len(); + if L < 3 { + return; + } + let mut start = 0; + let mut end = 0; + for j in 0..L { + while start < L && edges[start].time + delta < edges[j].time { + self.pop_pre(&edges[start]); + start+=1; + } + while (end < L) && edges[end].time <= edges[j].time + delta { + self.push_post(&edges[end]); + end+=1; + } + self.pop_post(&edges[j]); + self.process_current(&edges[j]); + self.push_pre(&edges[j]) + } + } + fn push_pre(&mut self,cur_edge:&TriangleEdge) { let (isUorV, nb, dir) = (cur_edge.uorv, cur_edge.nb, cur_edge.dir); if !cur_edge.uv_edge { @@ -212,10 +235,14 @@ impl TriangleCounter { } } } +fn init_tri_count(neighbours:Vec) -> TriangleCounter { + let N = neighbours.len(); + TriangleCounter { N: N, pre_nodes: vec![0;4*N], post_nodes: vec![0;4*N], pre_sum: [0;8], mid_sum: [0;8], post_sum: [0;8], final_counts: [0;8] } +} #[cfg(test)] mod three_node_motifs_test { -use super::{map2D, TwoNodeEvent,incoming,outgoing, TwoNodeCounter}; +use super::{map2D, TwoNodeEvent,incoming,outgoing, TwoNodeCounter, TriangleEdge, TriangleCounter, init_tri_count}; #[test] fn map_test() { @@ -230,5 +257,11 @@ use super::{map2D, TwoNodeEvent,incoming,outgoing, TwoNodeCounter}; println!("motifs are {:?}",twonc.count3d); } - + #[test] + fn triad_test() { + let events = vec![(true, 0,1,1,1), (false,1,0,1,2),(false,0,0,0,3)].iter().map(|x| TriangleEdge{uv_edge:x.0,uorv:x.1,nb:x.2,dir:x.3,time:x.4}).collect::>(); + let mut triangle_count = init_tri_count(vec![0,1,2]); + triangle_count.execute(&events, 5); + println!("triangle motifs are {:?}",triangle_count.final_counts); + } } \ No newline at end of file From e5b526020edb8438a8ab7ca444fad6e4f9fc5727 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Wed, 19 Apr 2023 15:15:23 +0100 Subject: [PATCH 6/9] add three node motifs to path --- docbrown/src/algorithms/mod.rs | 3 +- docbrown/src/algorithms/three_node_local.rs | 44 +++++++++++++++++++ .../{db => }/algorithms/three_node_motifs.rs | 0 .../src/db/algorithms/three_node_local.rs | 2 - 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 docbrown/src/algorithms/three_node_local.rs rename docbrown/src/{db => }/algorithms/three_node_motifs.rs (100%) delete mode 100644 docbrown/src/db/algorithms/three_node_local.rs diff --git a/docbrown/src/algorithms/mod.rs b/docbrown/src/algorithms/mod.rs index d0f87bff..04fb9a02 100644 --- a/docbrown/src/algorithms/mod.rs +++ b/docbrown/src/algorithms/mod.rs @@ -36,4 +36,5 @@ pub mod pagerank; pub mod reciprocity; pub mod triangle_count; pub mod triplet_count; - +pub mod three_node_motifs; +pub mod three_node_local; \ No newline at end of file diff --git a/docbrown/src/algorithms/three_node_local.rs b/docbrown/src/algorithms/three_node_local.rs new file mode 100644 index 00000000..9545d5ca --- /dev/null +++ b/docbrown/src/algorithms/three_node_local.rs @@ -0,0 +1,44 @@ +use std::collections::{HashMap, HashSet}; + +use crate::db::{ + graph::Graph, + program::{GlobalEvalState, LocalState, Program}, + view_api::*, +}; +use crate::algorithms::three_node_motifs::*; +use rustc_hash::FxHashMap; + +pub fn twonode_motif_count(graph:&G, v:u64) { + if let Some(vertex) = graph.vertex(v) { + let neighMap : HashMap = vertex.neighbours().iter().enumerate().map(|(num,nb)| (nb.id(), num) ).into_iter().collect(); + neighMap.keys().for_each({|nb| let exploded_edges = graph.edge(v, nb, layer);}) + } +} + +#[cfg(test)] +mod local_motif_test { + use crate::db::graph::Graph; + use crate::algorithms::three_node_local::twonode_motif_count; + + #[test] + fn test_init() { + let graph = Graph::new(1); + + let vs = vec![ + (1, 2), + (1, 4), + (2, 3), + (3, 2), + (3, 1), + (4, 3), + (4, 1), + (1, 5), + ]; + + for (src, dst) in &vs { + graph.add_edge(0, *src, *dst, &vec![], None); + } + + twonode_motif_count(&graph, 1); + } +} \ No newline at end of file diff --git a/docbrown/src/db/algorithms/three_node_motifs.rs b/docbrown/src/algorithms/three_node_motifs.rs similarity index 100% rename from docbrown/src/db/algorithms/three_node_motifs.rs rename to docbrown/src/algorithms/three_node_motifs.rs diff --git a/docbrown/src/db/algorithms/three_node_local.rs b/docbrown/src/db/algorithms/three_node_local.rs deleted file mode 100644 index ae71a9f4..00000000 --- a/docbrown/src/db/algorithms/three_node_local.rs +++ /dev/null @@ -1,2 +0,0 @@ -use crate::view_api::*; -use crate::algorithms::three_node_motifs::*; From 68978341820ed1f6e063e15688b0307d2923ee12 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Fri, 21 Apr 2023 17:16:05 +0100 Subject: [PATCH 7/9] Star and two node motifs implemented but no time on edges. --- docbrown/src/algorithms/three_node_local.rs | 79 ++++++++++++++++---- docbrown/src/algorithms/three_node_motifs.rs | 51 +++++++++---- 2 files changed, 98 insertions(+), 32 deletions(-) diff --git a/docbrown/src/algorithms/three_node_local.rs b/docbrown/src/algorithms/three_node_local.rs index 9545d5ca..451e7ccd 100644 --- a/docbrown/src/algorithms/three_node_local.rs +++ b/docbrown/src/algorithms/three_node_local.rs @@ -1,44 +1,91 @@ use std::collections::{HashMap, HashSet}; +use std::iter; use crate::db::{ graph::Graph, program::{GlobalEvalState, LocalState, Program}, - view_api::*, + view_api::*, edge::EdgeView, }; use crate::algorithms::three_node_motifs::*; use rustc_hash::FxHashMap; -pub fn twonode_motif_count(graph:&G, v:u64) { +pub fn star_motif_count(graph:&G, v:u64, delta:i64) { if let Some(vertex) = graph.vertex(v) { - let neighMap : HashMap = vertex.neighbours().iter().enumerate().map(|(num,nb)| (nb.id(), num) ).into_iter().collect(); - neighMap.keys().for_each({|nb| let exploded_edges = graph.edge(v, nb, layer);}) + let neigh_map : HashMap = vertex.neighbours().iter().enumerate().map(|(num,nb)| (nb.id(), num) ).into_iter().collect(); + let exploded_edges = vertex.edges() + .explode() + .map(|edge| if edge.src().id()==v {star_event(neigh_map[&edge.dst().id()],1,edge.start().unwrap())} else {star_event(neigh_map[&edge.src().id()],0,edge.start().unwrap())}) + .collect::>(); + let mut star_count = init_star_count(neigh_map.len()); + star_count.execute(&exploded_edges, 10); + let mut counts = star_count.concat_counts().clone(); } } +pub fn twonode_motif_count(graph:&G, v:u64, delta:i64) -> [u64;8] { + let mut counts = [0;8]; + if let Some(vertex) = graph.vertex(v) { + for nb in vertex.neighbours().iter() { + let nb_id = nb.id(); + println!("edge {} {}",v, nb_id); + let out = graph.edge(vertex.id(), nb_id, None); + let inc = graph.edge(nb_id, vertex.id(),None); + let mut all_exploded = match (out,inc) { + (Some(o),Some(i)) => o.explode() + .chain(i.explode()) + .map(|e| two_node_event(if e.src().id()==v {1} else {0}, e.start().unwrap())) + .collect::>(), + (Some(o), None) => o.explode() + .map(|e| two_node_event(1, e.start().unwrap())) + .collect::>(), + (None, Some(i)) => i.explode() + .map(|e| two_node_event(0, e.start().unwrap())) + .collect::>(), + (None, None) => Vec::new() + }; + all_exploded.sort_by_key(|e| e.time); + for e in &all_exploded { + println!("{} {}",e.dir, e.time); + } + let mut two_node_counter = init_two_node_count(); + two_node_counter.execute(&all_exploded, delta); + let two_node_result = two_node_counter.return_counts(); + for i in 0..8 { + counts[i]+=two_node_result[i]; + } + } + } + counts +} + #[cfg(test)] mod local_motif_test { use crate::db::graph::Graph; - use crate::algorithms::three_node_local::twonode_motif_count; + use crate::algorithms::three_node_local::*; #[test] fn test_init() { let graph = Graph::new(1); let vs = vec![ - (1, 2), - (1, 4), - (2, 3), - (3, 2), - (3, 1), - (4, 3), - (4, 1), - (1, 5), + (1, 2, 0), + (2, 1, 1), + (1, 4, 2), + (2, 3, 3), + (3, 2, 4), + (3, 1, 5), + (4, 3, 6), + (4, 1, 7), + (1, 5, 8), + (3, 1, 9), + (1, 2, 10) ]; - for (src, dst) in &vs { - graph.add_edge(0, *src, *dst, &vec![], None); + for (src, dst, time) in &vs { + graph.add_edge(*time, *src, *dst, &vec![], None); } - twonode_motif_count(&graph, 1); + let counts = twonode_motif_count(&graph, 1, 100); + print!("{:?}",counts) } } \ No newline at end of file diff --git a/docbrown/src/algorithms/three_node_motifs.rs b/docbrown/src/algorithms/three_node_motifs.rs index 681ce3eb..b62c9f46 100644 --- a/docbrown/src/algorithms/three_node_motifs.rs +++ b/docbrown/src/algorithms/three_node_motifs.rs @@ -10,18 +10,23 @@ fn map3D(d1:usize, d2:usize, d3:usize) -> usize { } // Two Node Motifs -struct TwoNodeEvent{ - dir:usize, - time:i64, +pub struct TwoNodeEvent{ + pub dir:usize, + pub time:i64, } -struct TwoNodeCounter { +pub struct TwoNodeCounter { count1d:[u64;2], count2d:[u64;4], - count3d:[u64;8], + pub count3d:[u64;8], +} + +pub fn two_node_event(dir:usize,time:i64) -> TwoNodeEvent { + TwoNodeEvent { dir: dir, time: time } } + impl TwoNodeCounter { - fn execute(&mut self, events:&[TwoNodeEvent], delta: i64) { + pub fn execute(&mut self, events:&Vec, delta: i64) { let mut start = 0; for event in events.iter() { while events[start].time + delta < event.time { @@ -49,15 +54,29 @@ impl TwoNodeCounter { // 1d counter self.count1d[dir]+=1; } + + pub fn return_counts(&self) -> [u64;8]{ + self.count3d + } + +} + +pub fn init_two_node_count() -> TwoNodeCounter { + TwoNodeCounter {count1d:[0;2], count2d:[0;4], count3d:[0;8]} } // Star Motifs -struct StarEvent{ +pub struct StarEvent{ nb:usize, dir:usize, - time:usize, + time:i64, +} + +pub fn star_event(nb:usize, dir:usize, time:i64) -> StarEvent { + StarEvent{nb:nb,dir:dir,time:time} } -struct StarCounter{ + +pub struct StarCounter{ N: usize, pre_nodes:Vec, post_nodes:Vec, @@ -67,7 +86,6 @@ struct StarCounter{ count_pre:[usize;8], count_mid:[usize;8], count_post:[usize;8], - final_counts:[usize;8], } impl StarCounter { fn push_pre(&mut self, cur_edge:&StarEvent) { @@ -83,11 +101,13 @@ impl StarCounter { } fn pop_pre(&mut self, cur_edge:&StarEvent) { + self.pre_nodes[cur_edge.dir*self.N + cur_edge.nb]-=1; self.pre_sum[map2D(cur_edge.dir, incoming)] -= self.pre_nodes[incoming*self.N + cur_edge.nb]; self.pre_sum[map2D(cur_edge.dir, outgoing)] -= self.pre_nodes[outgoing*self.N + cur_edge.nb]; } fn pop_post(&mut self, cur_edge:&StarEvent) { + self.post_nodes[cur_edge.dir*self.N + cur_edge.nb]-=1; self.post_sum[map2D(cur_edge.dir, incoming)] -= self.post_nodes[incoming*self.N + cur_edge.nb]; self.post_sum[map2D(cur_edge.dir, outgoing)] -= self.post_nodes[outgoing*self.N + cur_edge.nb]; } @@ -106,7 +126,7 @@ impl StarCounter { self.mid_sum[map2D(cur_edge.dir, outgoing)] += self.post_nodes[outgoing*self.N + cur_edge.nb]; } - fn execute(&mut self, edges:&Vec, delta:usize) { + pub fn execute(&mut self, edges:&Vec, delta:i64) { let L = edges.len(); if L < 3 { return; @@ -128,14 +148,13 @@ impl StarCounter { } } - fn concat_counts(&self) -> Vec { + pub fn concat_counts(&self) -> Vec { [self.count_pre,self.count_mid,self.count_post].concat() } } -fn init_star_count(neighbours:Vec) -> StarCounter { - let N = neighbours.len(); +pub fn init_star_count(N:usize) -> StarCounter { StarCounter {N:N, pre_nodes: vec![0;2*N], post_nodes: vec![0;2*N], pre_sum: [0;8], mid_sum: [0;8], post_sum: [0;8], - count_pre:[0;8], count_mid:[0;8], count_post:[0;8], final_counts: [0;8] } + count_pre:[0;8], count_mid:[0;8], count_post:[0;8]} } // Triangle Motifs @@ -251,7 +270,7 @@ use super::{map2D, TwoNodeEvent,incoming,outgoing, TwoNodeCounter, TriangleEdge, #[test] fn two_node_test() { - let events = [TwoNodeEvent{dir:outgoing,time:1}, TwoNodeEvent{dir:outgoing,time:2}, TwoNodeEvent{dir:outgoing,time:3}]; + let events = vec![TwoNodeEvent{dir:outgoing,time:1}, TwoNodeEvent{dir:outgoing,time:2}, TwoNodeEvent{dir:outgoing,time:3}]; let mut twonc = TwoNodeCounter{count1d:[0;2],count2d:[0;4],count3d:[0;8]}; twonc.execute(&events, 5); println!("motifs are {:?}",twonc.count3d); From 11f7683fe444db12f5349324a3c430d92b39588f Mon Sep 17 00:00:00 2001 From: narnolddd Date: Fri, 21 Apr 2023 18:22:17 +0100 Subject: [PATCH 8/9] updating to new exploded edge version --- docbrown/src/algorithms/three_node_local.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docbrown/src/algorithms/three_node_local.rs b/docbrown/src/algorithms/three_node_local.rs index 451e7ccd..2dbaa88d 100644 --- a/docbrown/src/algorithms/three_node_local.rs +++ b/docbrown/src/algorithms/three_node_local.rs @@ -1,5 +1,4 @@ -use std::collections::{HashMap, HashSet}; -use std::iter; +use std::collections::{HashMap}; use crate::db::{ graph::Graph, @@ -9,7 +8,7 @@ use crate::db::{ use crate::algorithms::three_node_motifs::*; use rustc_hash::FxHashMap; -pub fn star_motif_count(graph:&G, v:u64, delta:i64) { +pub fn star_motif_count(graph:&G, v:u64, delta:i64) -> [u64;24] { if let Some(vertex) = graph.vertex(v) { let neigh_map : HashMap = vertex.neighbours().iter().enumerate().map(|(num,nb)| (nb.id(), num) ).into_iter().collect(); let exploded_edges = vertex.edges() @@ -18,8 +17,9 @@ pub fn star_motif_count(graph:&G, v:u64, delta:i64) { .collect::>(); let mut star_count = init_star_count(neigh_map.len()); star_count.execute(&exploded_edges, 10); - let mut counts = star_count.concat_counts().clone(); + star_count.concat_counts().clone(); } + [0;24] } pub fn twonode_motif_count(graph:&G, v:u64, delta:i64) -> [u64;8] { @@ -33,13 +33,13 @@ pub fn twonode_motif_count(graph:&G, v:u64, delta:i64) -> [u64;8 let mut all_exploded = match (out,inc) { (Some(o),Some(i)) => o.explode() .chain(i.explode()) - .map(|e| two_node_event(if e.src().id()==v {1} else {0}, e.start().unwrap())) + .map(|e| two_node_event(if e.src().id()==v {1} else {0}, e.time().unwrap())) .collect::>(), (Some(o), None) => o.explode() - .map(|e| two_node_event(1, e.start().unwrap())) + .map(|e| two_node_event(1, e.latest_time().unwrap())) .collect::>(), (None, Some(i)) => i.explode() - .map(|e| two_node_event(0, e.start().unwrap())) + .map(|e| two_node_event(0, e.latest_time().unwrap())) .collect::>(), (None, None) => Vec::new() }; From 2fb07a67756ed87cf1e06c0eadc28efde9669309 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Fri, 21 Apr 2023 19:03:54 +0100 Subject: [PATCH 9/9] stars and two node motifs working --- docbrown/src/algorithms/mod.rs | 1 - docbrown/src/algorithms/three_node_local.rs | 14 +++++++------- docbrown/src/algorithms/three_node_motifs.rs | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/docbrown/src/algorithms/mod.rs b/docbrown/src/algorithms/mod.rs index 5a64bb05..bf0d920e 100644 --- a/docbrown/src/algorithms/mod.rs +++ b/docbrown/src/algorithms/mod.rs @@ -39,7 +39,6 @@ pub mod triangle_count; pub mod triplet_count; pub mod three_node_motifs; pub mod three_node_local; -pub mod hits; use num_traits::{abs, Bounded, Zero}; use std::ops::{Add, AddAssign, Div, Mul, Range, Sub}; diff --git a/docbrown/src/algorithms/three_node_local.rs b/docbrown/src/algorithms/three_node_local.rs index 2dbaa88d..ff87b170 100644 --- a/docbrown/src/algorithms/three_node_local.rs +++ b/docbrown/src/algorithms/three_node_local.rs @@ -8,18 +8,18 @@ use crate::db::{ use crate::algorithms::three_node_motifs::*; use rustc_hash::FxHashMap; -pub fn star_motif_count(graph:&G, v:u64, delta:i64) -> [u64;24] { +pub fn star_motif_count(graph:&G, v:u64, delta:i64) -> [usize;24] { if let Some(vertex) = graph.vertex(v) { let neigh_map : HashMap = vertex.neighbours().iter().enumerate().map(|(num,nb)| (nb.id(), num) ).into_iter().collect(); let exploded_edges = vertex.edges() .explode() - .map(|edge| if edge.src().id()==v {star_event(neigh_map[&edge.dst().id()],1,edge.start().unwrap())} else {star_event(neigh_map[&edge.src().id()],0,edge.start().unwrap())}) + .map(|edge| if edge.src().id()==v {star_event(neigh_map[&edge.dst().id()],1,edge.time().unwrap())} else {star_event(neigh_map[&edge.src().id()],0,edge.time().unwrap())}) .collect::>(); let mut star_count = init_star_count(neigh_map.len()); star_count.execute(&exploded_edges, 10); - star_count.concat_counts().clone(); + star_count.return_counts() } - [0;24] + else {[0;24]} } pub fn twonode_motif_count(graph:&G, v:u64, delta:i64) -> [u64;8] { @@ -36,10 +36,10 @@ pub fn twonode_motif_count(graph:&G, v:u64, delta:i64) -> [u64;8 .map(|e| two_node_event(if e.src().id()==v {1} else {0}, e.time().unwrap())) .collect::>(), (Some(o), None) => o.explode() - .map(|e| two_node_event(1, e.latest_time().unwrap())) + .map(|e| two_node_event(1, e.time().unwrap())) .collect::>(), (None, Some(i)) => i.explode() - .map(|e| two_node_event(0, e.latest_time().unwrap())) + .map(|e| two_node_event(0, e.time().unwrap())) .collect::>(), (None, None) => Vec::new() }; @@ -85,7 +85,7 @@ mod local_motif_test { graph.add_edge(*time, *src, *dst, &vec![], None); } - let counts = twonode_motif_count(&graph, 1, 100); + let counts = star_motif_count(&graph, 1, 100); print!("{:?}",counts) } } \ No newline at end of file diff --git a/docbrown/src/algorithms/three_node_motifs.rs b/docbrown/src/algorithms/three_node_motifs.rs index b62c9f46..793948b7 100644 --- a/docbrown/src/algorithms/three_node_motifs.rs +++ b/docbrown/src/algorithms/three_node_motifs.rs @@ -33,7 +33,7 @@ impl TwoNodeCounter { self.decrement_counts(events[start].dir); start +=1; } - self.increment_counts(events[start].dir); + self.increment_counts(event.dir); } } @@ -48,6 +48,7 @@ impl TwoNodeCounter { for (d1,d2) in dirs2D { self.count3d[map3D(d1, d2, dir)] += self.count2d[map2D(d1, d2)]; } + // 2d counter self.count2d[map2D(incoming,dir)]+=self.count1d[incoming]; self.count2d[map2D(outgoing, dir)]+=self.count1d[outgoing]; @@ -148,9 +149,16 @@ impl StarCounter { } } - pub fn concat_counts(&self) -> Vec { - [self.count_pre,self.count_mid,self.count_post].concat() + pub fn return_counts(&self) -> [usize;24] { + let mut counts = [0;24]; + for i in 0..8 { + counts[i] = self.count_pre[i]; + counts[8+i] = self.count_mid[i]; + counts[16+i] = self.count_post[i]; + } + counts } + } pub fn init_star_count(N:usize) -> StarCounter { StarCounter {N:N, pre_nodes: vec![0;2*N], post_nodes: vec![0;2*N], pre_sum: [0;8], mid_sum: [0;8], post_sum: [0;8], @@ -270,7 +278,7 @@ use super::{map2D, TwoNodeEvent,incoming,outgoing, TwoNodeCounter, TriangleEdge, #[test] fn two_node_test() { - let events = vec![TwoNodeEvent{dir:outgoing,time:1}, TwoNodeEvent{dir:outgoing,time:2}, TwoNodeEvent{dir:outgoing,time:3}]; + let events = vec![TwoNodeEvent{dir:outgoing,time:1}, TwoNodeEvent{dir:incoming,time:2}, TwoNodeEvent{dir:incoming,time:3}]; let mut twonc = TwoNodeCounter{count1d:[0;2],count2d:[0;4],count3d:[0;8]}; twonc.execute(&events, 5); println!("motifs are {:?}",twonc.count3d);