From 608d4004d7d6c88293097ac59835adfb90fb1ff0 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Tue, 28 Nov 2023 12:23:57 +0000 Subject: [PATCH 1/8] temporal bipartite working --- python/src/lib.rs | 1 + raphtory/Cargo.toml | 1 + raphtory/src/algorithms/mod.rs | 1 + .../temporal_bipartite_projection.rs | 107 ++++++++++++++++++ raphtory/src/python/packages/algorithms.rs | 9 +- 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 raphtory/src/algorithms/temporal_bipartite_projection.rs diff --git a/python/src/lib.rs b/python/src/lib.rs index 1f84aadf4e..2416f8a23e 100644 --- a/python/src/lib.rs +++ b/python/src/lib.rs @@ -94,6 +94,7 @@ fn raphtory(py: Python<'_>, m: &PyModule) -> PyResult<()> { single_source_shortest_path, global_clustering_coefficient, temporally_reachable_nodes, + temporal_bipartite_graph_projection, local_clustering_coefficient, weakly_connected_components, strongly_connected_components, diff --git a/raphtory/Cargo.toml b/raphtory/Cargo.toml index 6cc541577d..b3becec763 100644 --- a/raphtory/Cargo.toml +++ b/raphtory/Cargo.toml @@ -22,6 +22,7 @@ futures = {version = "0.3", features = ["thread-pool"] } genawaiter = "0.99" itertools="0.10" num-traits = "0.2" +num-integer = "0.1" parking_lot = { version = "0.12" , features = ["serde", "arc_lock", "send_guard"] } quickcheck = "1" quickcheck_macros = "1" diff --git a/raphtory/src/algorithms/mod.rs b/raphtory/src/algorithms/mod.rs index 803de28f74..363f50a1a9 100644 --- a/raphtory/src/algorithms/mod.rs +++ b/raphtory/src/algorithms/mod.rs @@ -33,4 +33,5 @@ pub mod cores; pub mod metrics; pub mod motifs; pub mod pathing; +pub mod temporal_bipartite_projection; pub mod usecases; diff --git a/raphtory/src/algorithms/temporal_bipartite_projection.rs b/raphtory/src/algorithms/temporal_bipartite_projection.rs new file mode 100644 index 0000000000..263202868e --- /dev/null +++ b/raphtory/src/algorithms/temporal_bipartite_projection.rs @@ -0,0 +1,107 @@ +use itertools::Itertools; +use num_integer::average_floor; +// use num::integer::average_floor; +extern crate num_integer; + +use crate::{ + db::{ + api::{mutation::AdditionOps, view::*}, + graph::graph::Graph, + }, + core::entities::vertices::vertex_ref::VertexRef, + prelude::{EdgeListOps, EdgeViewOps, GraphViewOps, VertexViewOps, NO_PROPS, PropUnwrap}, db::api::view::internal::{GraphOps, DynamicGraph}, +}; + +#[derive(Clone)] +struct Visitor { + name: String, + time: i64, +} + +pub fn temporal_bipartite_projection(graph:&G, delta:i64, pivot_type:String) -> Graph { + let new_graph = Graph::new(); + let nodes = graph.vertices().iter().filter(|v| v.properties().get("Type").unwrap_str()==pivot_type); + for v in nodes {populate_edges(graph, &new_graph, v, delta)}; + new_graph +} + +fn populate_edges>(g: &G, new_graph:&Graph, v: V, delta:i64) { + if let Some(vertex) = g.vertex(v) { + // get vector of vertices which need connecting up + let mut visitors = vertex + .in_edges() + .explode() + .map(|e| Visitor { + name: e.src().name(), + time: e.time().unwrap(), + }) + .collect_vec(); + visitors.sort_by_key(|vis| vis.time); + + let mut start = 0; + let mut to_process: Vec = vec![]; + for nb in visitors.iter() { + while visitors[start].time + delta < nb.time { + to_process.remove(0); + start+=1 + } + for node in &to_process { + let new_time = average_floor(nb.time, node.time); + new_graph.add_edge(new_time, node.name.clone(), nb.name.clone(), NO_PROPS, None).unwrap(); + } + to_process.push(nb.clone()); + } + } else { + return; + } +} + +#[cfg(test)] +mod bipartite_graph_tests { + use itertools::Itertools; + + use super::temporal_bipartite_projection; + use crate::{ + db::{ + api::{mutation::AdditionOps, view::*}, + graph::graph::Graph, + }, + prelude::{NO_PROPS, Prop}, + }; + + #[test] + fn small_delta_test() { + let g = Graph::new(); + let vs = vec![(1,"A","1"), (3,"A","2"), (3,"B","2"), (4,"C","3"),(6,"B","3"),(8,"A","3"),(10,"C","4"),(11,"B","4")]; + for (t, src, dst) in &vs { + g.add_vertex(*t, *src, [("Type",Prop::Str("Left".into()))]).unwrap(); + g.add_vertex(*t, *dst, [("Type",Prop::Str("Right".into()))]).unwrap(); + g.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap(); + } + let new_graph = temporal_bipartite_projection(&g, 1, "Right".to_string()); + assert!(new_graph.has_edge("A", "B", Layer::All)); + assert_eq!(new_graph.edge("A", "B").unwrap().latest_time(),Some(3)); + assert!(new_graph.has_edge("C", "B", Layer::All)); + assert_eq!(new_graph.edge("C", "B").unwrap().latest_time(),Some(10)); + assert!(!new_graph.has_edge("A", "C", Layer::All)); + } + + #[test] + fn larger_delta_test() { + let g = Graph::new(); + let vs = vec![(1,"A","1"), (3,"A","2"), (3,"B","2"), (4,"C","3"),(6,"B","3"),(8,"A","3"),(10,"C","4"),(11,"B","4")]; + for (t, src, dst) in &vs { + g.add_vertex(*t, *src, [("Type",Prop::Str("Left".into()))]).unwrap(); + g.add_vertex(*t, *dst, [("Type",Prop::Str("Right".into()))]).unwrap(); + g.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap(); + } + let new_graph = temporal_bipartite_projection(&g, 3, "Right".to_string()); + assert!(new_graph.has_edge("A", "B", Layer::All)); + assert_eq!(new_graph.edge("A", "B").unwrap().earliest_time(),Some(3)); + assert_eq!(new_graph.edge("B", "A").unwrap().latest_time(),Some(7)); + assert!(new_graph.has_edge("C", "B", Layer::All)); + assert_eq!(new_graph.edge("C", "B").unwrap().earliest_time(),Some(5)); + assert_eq!(new_graph.edge("C", "B").unwrap().latest_time(),Some(10)); + assert!(!new_graph.has_edge("A", "C", Layer::All)); + } +} diff --git a/raphtory/src/python/packages/algorithms.rs b/raphtory/src/python/packages/algorithms.rs index f6790bda79..f511545329 100644 --- a/raphtory/src/python/packages/algorithms.rs +++ b/raphtory/src/python/packages/algorithms.rs @@ -42,9 +42,10 @@ use crate::{ temporal_reachability::temporally_reachable_nodes as temporal_reachability_rs, }, usecases::netflow_one_path_vertex::netflow_one_path_vertex as netflow_one_path_vertex_rs, + temporal_bipartite_projection::temporal_bipartite_projection as temporal_bipartite_rs, }, core::entities::vertices::vertex_ref::VertexRef, - python::{graph::views::graph_view::PyGraphView, utils::PyInputVertex}, + python::{graph::{views::graph_view::PyGraphView, graph::PyGraph}, utils::PyInputVertex}, }; use crate::{ core::Prop, @@ -389,6 +390,12 @@ pub fn global_temporal_three_node_motif(g: &PyGraphView, delta: i64) -> [usize; global_temporal_three_node_motif_rs(&g.graph, delta, None) } +#[pyfunction] +#[pyo3(signature = (g, delta, pivot_type))] +pub fn temporal_bipartite_graph_projection(g: &PyGraphView, delta: i64, pivot_type: String) -> PyGraphView{ + temporal_bipartite_rs(&g.graph, delta, pivot_type).into() +} + /// Computes the global counts of three-edge up-to-three node temporal motifs for a range of timescales. See `global_temporal_three_node_motif` for an interpretation of each row returned. /// /// Arguments: From 35c8723d602f4b14d16c8074bc554c050c265825 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Tue, 28 Nov 2023 13:31:45 +0000 Subject: [PATCH 2/8] fmt --- .../temporal_bipartite_projection.rs | 83 ++++++++++++++----- raphtory/src/python/packages/algorithms.rs | 13 ++- 2 files changed, 71 insertions(+), 25 deletions(-) diff --git a/raphtory/src/algorithms/temporal_bipartite_projection.rs b/raphtory/src/algorithms/temporal_bipartite_projection.rs index 263202868e..17da3b6966 100644 --- a/raphtory/src/algorithms/temporal_bipartite_projection.rs +++ b/raphtory/src/algorithms/temporal_bipartite_projection.rs @@ -4,12 +4,18 @@ use num_integer::average_floor; extern crate num_integer; use crate::{ + core::entities::vertices::vertex_ref::VertexRef, db::{ - api::{mutation::AdditionOps, view::*}, + api::{ + mutation::AdditionOps, + view::{ + internal::{DynamicGraph, GraphOps}, + *, + }, + }, graph::graph::Graph, }, - core::entities::vertices::vertex_ref::VertexRef, - prelude::{EdgeListOps, EdgeViewOps, GraphViewOps, VertexViewOps, NO_PROPS, PropUnwrap}, db::api::view::internal::{GraphOps, DynamicGraph}, + prelude::{EdgeListOps, EdgeViewOps, GraphViewOps, PropUnwrap, VertexViewOps, NO_PROPS}, }; #[derive(Clone)] @@ -18,14 +24,23 @@ struct Visitor { time: i64, } -pub fn temporal_bipartite_projection(graph:&G, delta:i64, pivot_type:String) -> Graph { +pub fn temporal_bipartite_projection( + graph: &G, + delta: i64, + pivot_type: String, +) -> Graph { let new_graph = Graph::new(); - let nodes = graph.vertices().iter().filter(|v| v.properties().get("Type").unwrap_str()==pivot_type); - for v in nodes {populate_edges(graph, &new_graph, v, delta)}; + let nodes = graph + .vertices() + .iter() + .filter(|v| v.properties().get("Type").unwrap_str() == pivot_type); + for v in nodes { + populate_edges(graph, &new_graph, v, delta) + } new_graph } -fn populate_edges>(g: &G, new_graph:&Graph, v: V, delta:i64) { +fn populate_edges>(g: &G, new_graph: &Graph, v: V, delta: i64) { if let Some(vertex) = g.vertex(v) { // get vector of vertices which need connecting up let mut visitors = vertex @@ -43,11 +58,13 @@ fn populate_edges>(g: &G, new_graph:&Graph, for nb in visitors.iter() { while visitors[start].time + delta < nb.time { to_process.remove(0); - start+=1 + start += 1 } for node in &to_process { let new_time = average_floor(nb.time, node.time); - new_graph.add_edge(new_time, node.name.clone(), nb.name.clone(), NO_PROPS, None).unwrap(); + new_graph + .add_edge(new_time, node.name.clone(), nb.name.clone(), NO_PROPS, None) + .unwrap(); } to_process.push(nb.clone()); } @@ -66,42 +83,64 @@ mod bipartite_graph_tests { api::{mutation::AdditionOps, view::*}, graph::graph::Graph, }, - prelude::{NO_PROPS, Prop}, + prelude::{Prop, NO_PROPS}, }; #[test] fn small_delta_test() { let g = Graph::new(); - let vs = vec![(1,"A","1"), (3,"A","2"), (3,"B","2"), (4,"C","3"),(6,"B","3"),(8,"A","3"),(10,"C","4"),(11,"B","4")]; + let vs = vec![ + (1, "A", "1"), + (3, "A", "2"), + (3, "B", "2"), + (4, "C", "3"), + (6, "B", "3"), + (8, "A", "3"), + (10, "C", "4"), + (11, "B", "4"), + ]; for (t, src, dst) in &vs { - g.add_vertex(*t, *src, [("Type",Prop::Str("Left".into()))]).unwrap(); - g.add_vertex(*t, *dst, [("Type",Prop::Str("Right".into()))]).unwrap(); + g.add_vertex(*t, *src, [("Type", Prop::Str("Left".into()))]) + .unwrap(); + g.add_vertex(*t, *dst, [("Type", Prop::Str("Right".into()))]) + .unwrap(); g.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap(); } let new_graph = temporal_bipartite_projection(&g, 1, "Right".to_string()); assert!(new_graph.has_edge("A", "B", Layer::All)); - assert_eq!(new_graph.edge("A", "B").unwrap().latest_time(),Some(3)); + assert_eq!(new_graph.edge("A", "B").unwrap().latest_time(), Some(3)); assert!(new_graph.has_edge("C", "B", Layer::All)); - assert_eq!(new_graph.edge("C", "B").unwrap().latest_time(),Some(10)); + assert_eq!(new_graph.edge("C", "B").unwrap().latest_time(), Some(10)); assert!(!new_graph.has_edge("A", "C", Layer::All)); } #[test] fn larger_delta_test() { let g = Graph::new(); - let vs = vec![(1,"A","1"), (3,"A","2"), (3,"B","2"), (4,"C","3"),(6,"B","3"),(8,"A","3"),(10,"C","4"),(11,"B","4")]; + let vs = vec![ + (1, "A", "1"), + (3, "A", "2"), + (3, "B", "2"), + (4, "C", "3"), + (6, "B", "3"), + (8, "A", "3"), + (10, "C", "4"), + (11, "B", "4"), + ]; for (t, src, dst) in &vs { - g.add_vertex(*t, *src, [("Type",Prop::Str("Left".into()))]).unwrap(); - g.add_vertex(*t, *dst, [("Type",Prop::Str("Right".into()))]).unwrap(); + g.add_vertex(*t, *src, [("Type", Prop::Str("Left".into()))]) + .unwrap(); + g.add_vertex(*t, *dst, [("Type", Prop::Str("Right".into()))]) + .unwrap(); g.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap(); } let new_graph = temporal_bipartite_projection(&g, 3, "Right".to_string()); assert!(new_graph.has_edge("A", "B", Layer::All)); - assert_eq!(new_graph.edge("A", "B").unwrap().earliest_time(),Some(3)); - assert_eq!(new_graph.edge("B", "A").unwrap().latest_time(),Some(7)); + assert_eq!(new_graph.edge("A", "B").unwrap().earliest_time(), Some(3)); + assert_eq!(new_graph.edge("B", "A").unwrap().latest_time(), Some(7)); assert!(new_graph.has_edge("C", "B", Layer::All)); - assert_eq!(new_graph.edge("C", "B").unwrap().earliest_time(),Some(5)); - assert_eq!(new_graph.edge("C", "B").unwrap().latest_time(),Some(10)); + assert_eq!(new_graph.edge("C", "B").unwrap().earliest_time(), Some(5)); + assert_eq!(new_graph.edge("C", "B").unwrap().latest_time(), Some(10)); assert!(!new_graph.has_edge("A", "C", Layer::All)); } } diff --git a/raphtory/src/python/packages/algorithms.rs b/raphtory/src/python/packages/algorithms.rs index f511545329..227b3774e6 100644 --- a/raphtory/src/python/packages/algorithms.rs +++ b/raphtory/src/python/packages/algorithms.rs @@ -41,11 +41,14 @@ use crate::{ single_source_shortest_path::single_source_shortest_path as single_source_shortest_path_rs, temporal_reachability::temporally_reachable_nodes as temporal_reachability_rs, }, - usecases::netflow_one_path_vertex::netflow_one_path_vertex as netflow_one_path_vertex_rs, temporal_bipartite_projection::temporal_bipartite_projection as temporal_bipartite_rs, + usecases::netflow_one_path_vertex::netflow_one_path_vertex as netflow_one_path_vertex_rs, }, core::entities::vertices::vertex_ref::VertexRef, - python::{graph::{views::graph_view::PyGraphView, graph::PyGraph}, utils::PyInputVertex}, + python::{ + graph::{graph::PyGraph, views::graph_view::PyGraphView}, + utils::PyInputVertex, + }, }; use crate::{ core::Prop, @@ -392,7 +395,11 @@ pub fn global_temporal_three_node_motif(g: &PyGraphView, delta: i64) -> [usize; #[pyfunction] #[pyo3(signature = (g, delta, pivot_type))] -pub fn temporal_bipartite_graph_projection(g: &PyGraphView, delta: i64, pivot_type: String) -> PyGraphView{ +pub fn temporal_bipartite_graph_projection( + g: &PyGraphView, + delta: i64, + pivot_type: String, +) -> PyGraphView { temporal_bipartite_rs(&g.graph, delta, pivot_type).into() } From 28ac88753250c5afb5f060b6b4f730da4953c64d Mon Sep 17 00:00:00 2001 From: narnolddd Date: Fri, 16 Feb 2024 16:54:56 +0000 Subject: [PATCH 3/8] add num-integer crate --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 4494752b95..b93fb1772f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2914,6 +2914,7 @@ dependencies = [ "lock_api", "neo4rs", "num", + "num-integer", "num-traits", "once_cell", "ordered-float 3.7.0", From 101555ac714da01272e996545ac0f0702764d257 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Fri, 16 Feb 2024 17:26:49 +0000 Subject: [PATCH 4/8] refactor to nodes etc --- raphtory/src/algorithms/mod.rs | 2 +- .../temporal_bipartite_projection.rs | 46 ++++++++++--------- raphtory/src/python/packages/algorithms.rs | 2 +- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/raphtory/src/algorithms/mod.rs b/raphtory/src/algorithms/mod.rs index 0ddddcfa26..d6efd708e2 100644 --- a/raphtory/src/algorithms/mod.rs +++ b/raphtory/src/algorithms/mod.rs @@ -37,4 +37,4 @@ pub mod layout; pub mod metrics; pub mod motifs; pub mod pathing; -pub mod temporal_bipartite_projection; \ No newline at end of file +pub mod temporal_bipartite_projection; diff --git a/raphtory/src/algorithms/temporal_bipartite_projection.rs b/raphtory/src/algorithms/temporal_bipartite_projection.rs index 17da3b6966..3e70837d1b 100644 --- a/raphtory/src/algorithms/temporal_bipartite_projection.rs +++ b/raphtory/src/algorithms/temporal_bipartite_projection.rs @@ -1,10 +1,12 @@ +use std::any::Any; + use itertools::Itertools; use num_integer::average_floor; // use num::integer::average_floor; extern crate num_integer; use crate::{ - core::entities::vertices::vertex_ref::VertexRef, + core::entities::nodes::node_ref::NodeRef, db::{ api::{ mutation::AdditionOps, @@ -15,7 +17,7 @@ use crate::{ }, graph::graph::Graph, }, - prelude::{EdgeListOps, EdgeViewOps, GraphViewOps, PropUnwrap, VertexViewOps, NO_PROPS}, + prelude::*, }; #[derive(Clone)] @@ -24,28 +26,34 @@ struct Visitor { time: i64, } -pub fn temporal_bipartite_projection( +pub fn temporal_bipartite_projection( graph: &G, delta: i64, pivot_type: String, ) -> Graph { let new_graph = Graph::new(); let nodes = graph - .vertices() + .nodes() .iter() - .filter(|v| v.properties().get("Type").unwrap_str() == pivot_type); + .filter(|v| v.node_type().unwrap() == pivot_type); for v in nodes { populate_edges(graph, &new_graph, v, delta) } new_graph } -fn populate_edges>(g: &G, new_graph: &Graph, v: V, delta: i64) { - if let Some(vertex) = g.vertex(v) { +fn populate_edges>( + g: &G, + new_graph: &Graph, + v: V, + delta: i64, +) { + if let Some(vertex) = g.node(v) { // get vector of vertices which need connecting up let mut visitors = vertex .in_edges() .explode() + .iter() .map(|e| Visitor { name: e.src().name(), time: e.time().unwrap(), @@ -100,18 +108,16 @@ mod bipartite_graph_tests { (11, "B", "4"), ]; for (t, src, dst) in &vs { - g.add_vertex(*t, *src, [("Type", Prop::Str("Left".into()))]) - .unwrap(); - g.add_vertex(*t, *dst, [("Type", Prop::Str("Right".into()))]) - .unwrap(); + g.add_node(*t, *src, NO_PROPS, Some("Left")).unwrap(); + g.add_node(*t, *dst, NO_PROPS, Some("Right")).unwrap(); g.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap(); } let new_graph = temporal_bipartite_projection(&g, 1, "Right".to_string()); - assert!(new_graph.has_edge("A", "B", Layer::All)); + assert!(new_graph.has_edge("A", "B")); assert_eq!(new_graph.edge("A", "B").unwrap().latest_time(), Some(3)); - assert!(new_graph.has_edge("C", "B", Layer::All)); + assert!(new_graph.has_edge("C", "B")); assert_eq!(new_graph.edge("C", "B").unwrap().latest_time(), Some(10)); - assert!(!new_graph.has_edge("A", "C", Layer::All)); + assert!(!new_graph.has_edge("A", "C")); } #[test] @@ -128,19 +134,17 @@ mod bipartite_graph_tests { (11, "B", "4"), ]; for (t, src, dst) in &vs { - g.add_vertex(*t, *src, [("Type", Prop::Str("Left".into()))]) - .unwrap(); - g.add_vertex(*t, *dst, [("Type", Prop::Str("Right".into()))]) - .unwrap(); + g.add_node(*t, *src, NO_PROPS, Some("Left")).unwrap(); + g.add_node(*t, *dst, NO_PROPS, Some("Right")).unwrap(); g.add_edge(*t, *src, *dst, NO_PROPS, None).unwrap(); } let new_graph = temporal_bipartite_projection(&g, 3, "Right".to_string()); - assert!(new_graph.has_edge("A", "B", Layer::All)); + assert!(new_graph.has_edge("A", "B")); assert_eq!(new_graph.edge("A", "B").unwrap().earliest_time(), Some(3)); assert_eq!(new_graph.edge("B", "A").unwrap().latest_time(), Some(7)); - assert!(new_graph.has_edge("C", "B", Layer::All)); + assert!(new_graph.has_edge("C", "B")); assert_eq!(new_graph.edge("C", "B").unwrap().earliest_time(), Some(5)); assert_eq!(new_graph.edge("C", "B").unwrap().latest_time(), Some(10)); - assert!(!new_graph.has_edge("A", "C", Layer::All)); + assert!(!new_graph.has_edge("A", "C")); } } diff --git a/raphtory/src/python/packages/algorithms.rs b/raphtory/src/python/packages/algorithms.rs index 9e4d50d783..657002fee3 100644 --- a/raphtory/src/python/packages/algorithms.rs +++ b/raphtory/src/python/packages/algorithms.rs @@ -45,7 +45,7 @@ use crate::{ single_source_shortest_path::single_source_shortest_path as single_source_shortest_path_rs, temporal_reachability::temporally_reachable_nodes as temporal_reachability_rs, }, - temporal_bipartite_projection::temporal_bipartite_projection as temporal_bipartite_rs + temporal_bipartite_projection::temporal_bipartite_projection as temporal_bipartite_rs, }, core::{entities::nodes::node_ref::NodeRef, Prop}, db::{api::view::internal::DynamicGraph, graph::node::NodeView}, From 1d7abfde24079edcac8e70d20ffcd46a562f6b3d Mon Sep 17 00:00:00 2001 From: narnolddd Date: Thu, 11 Apr 2024 17:56:40 +0100 Subject: [PATCH 5/8] add some py docs and dependency into cargo --- Cargo.toml | 1 + .../src/algorithms/temporal_bipartite_projection.rs | 5 +---- raphtory/src/python/packages/algorithms.rs | 10 ++++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 28978a3017..299048e2f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ flate2 = "1.0.28" regex = "1.10.3" genawaiter = "0.99.1" num-traits = "0.2.18" +num-integer = "0.1" rand_distr = "0.4.3" rustc-hash = "1.1.0" twox-hash = "1.6.3" diff --git a/raphtory/src/algorithms/temporal_bipartite_projection.rs b/raphtory/src/algorithms/temporal_bipartite_projection.rs index 3e70837d1b..917e8f8f4c 100644 --- a/raphtory/src/algorithms/temporal_bipartite_projection.rs +++ b/raphtory/src/algorithms/temporal_bipartite_projection.rs @@ -10,10 +10,7 @@ use crate::{ db::{ api::{ mutation::AdditionOps, - view::{ - internal::{DynamicGraph, GraphOps}, - *, - }, + view::{internal, *}, }, graph::graph::Graph, }, diff --git a/raphtory/src/python/packages/algorithms.rs b/raphtory/src/python/packages/algorithms.rs index 8ae084fd23..3ff929701a 100644 --- a/raphtory/src/python/packages/algorithms.rs +++ b/raphtory/src/python/packages/algorithms.rs @@ -410,6 +410,16 @@ pub fn global_temporal_three_node_motif(g: &PyGraphView, delta: i64) -> [usize; global_temporal_three_node_motif_rs(&g.graph, delta, None) } +/// Projects a temporal bipartite graph into an undirected temporal graph over the pivot node type. Let G be a bipartite graph with node types A and B. Given delta > 0, the projection graph G' pivoting over type B nodes, +/// will make a connection between nodes n1 and n2 (of type A) at time (t1 + t2)/2 if they respectively have an edge at time t1, t2 with the same node of type B in G, and |t2-t1| < delta. +/// +/// Arguments: +/// g (raphtory graph) : A directed raphtory graph +/// delta (int): Time period +/// pivot (string) : node type to pivot over. If a bipartite graph has types A and B, and B is the pivot type, the new graph will consist of type A nodes. +/// +/// Returns: +/// raphtory graph : Projected (unipartite) temporal graph. #[pyfunction] #[pyo3(signature = (g, delta, pivot_type))] pub fn temporal_bipartite_graph_projection( From 21de546a38ce20025bb91b110e150e89cec286cc Mon Sep 17 00:00:00 2001 From: narnolddd Date: Tue, 7 May 2024 13:34:54 +0100 Subject: [PATCH 6/8] refactor using nbr and put in directory --- raphtory/src/algorithms/mod.rs | 2 +- raphtory/src/algorithms/projections/mod.rs | 1 + .../{ => projections}/temporal_bipartite_projection.rs | 4 ++-- raphtory/src/python/packages/algorithms.rs | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 raphtory/src/algorithms/projections/mod.rs rename raphtory/src/algorithms/{ => projections}/temporal_bipartite_projection.rs (98%) diff --git a/raphtory/src/algorithms/mod.rs b/raphtory/src/algorithms/mod.rs index d6efd708e2..7003b83617 100644 --- a/raphtory/src/algorithms/mod.rs +++ b/raphtory/src/algorithms/mod.rs @@ -37,4 +37,4 @@ pub mod layout; pub mod metrics; pub mod motifs; pub mod pathing; -pub mod temporal_bipartite_projection; +pub mod projections; diff --git a/raphtory/src/algorithms/projections/mod.rs b/raphtory/src/algorithms/projections/mod.rs new file mode 100644 index 0000000000..b2264faa2a --- /dev/null +++ b/raphtory/src/algorithms/projections/mod.rs @@ -0,0 +1 @@ +pub mod temporal_bipartite_projection; diff --git a/raphtory/src/algorithms/temporal_bipartite_projection.rs b/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs similarity index 98% rename from raphtory/src/algorithms/temporal_bipartite_projection.rs rename to raphtory/src/algorithms/projections/temporal_bipartite_projection.rs index 917e8f8f4c..1bad17e81d 100644 --- a/raphtory/src/algorithms/temporal_bipartite_projection.rs +++ b/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs @@ -48,11 +48,11 @@ fn populate_edges>( if let Some(vertex) = g.node(v) { // get vector of vertices which need connecting up let mut visitors = vertex - .in_edges() + .edges() .explode() .iter() .map(|e| Visitor { - name: e.src().name(), + name: e.nbr().name(), time: e.time().unwrap(), }) .collect_vec(); diff --git a/raphtory/src/python/packages/algorithms.rs b/raphtory/src/python/packages/algorithms.rs index 3ff929701a..d1e8463e76 100644 --- a/raphtory/src/python/packages/algorithms.rs +++ b/raphtory/src/python/packages/algorithms.rs @@ -45,7 +45,7 @@ use crate::{ single_source_shortest_path::single_source_shortest_path as single_source_shortest_path_rs, temporal_reachability::temporally_reachable_nodes as temporal_reachability_rs, }, - temporal_bipartite_projection::temporal_bipartite_projection as temporal_bipartite_rs, + projections::temporal_bipartite_projection::temporal_bipartite_projection as temporal_bipartite_rs, }, core::{entities::nodes::node_ref::NodeRef, Prop}, db::{api::view::internal::DynamicGraph, graph::node::NodeView}, From 0a1983d9d2be11fbf8a8a37cad33b1e7f3742436 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Tue, 28 May 2024 15:55:10 +0100 Subject: [PATCH 7/8] change to asnoderef --- .../algorithms/projections/temporal_bipartite_projection.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs b/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs index 1bad17e81d..b06f918466 100644 --- a/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs +++ b/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs @@ -6,7 +6,7 @@ use num_integer::average_floor; extern crate num_integer; use crate::{ - core::entities::nodes::node_ref::NodeRef, + core::entities::nodes::node_ref::{AsNodeRef, NodeRef}, db::{ api::{ mutation::AdditionOps, @@ -39,7 +39,7 @@ pub fn temporal_bipartite_projection( new_graph } -fn populate_edges>( +fn populate_edges( g: &G, new_graph: &Graph, v: V, From b25a5fa0ff2dd386f85cf9cc99e5e894d1c43eb4 Mon Sep 17 00:00:00 2001 From: narnolddd Date: Tue, 28 May 2024 15:55:42 +0100 Subject: [PATCH 8/8] cargo fmt --- .../projections/temporal_bipartite_projection.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs b/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs index b06f918466..c9f9f4d53a 100644 --- a/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs +++ b/raphtory/src/algorithms/projections/temporal_bipartite_projection.rs @@ -39,12 +39,7 @@ pub fn temporal_bipartite_projection( new_graph } -fn populate_edges( - g: &G, - new_graph: &Graph, - v: V, - delta: i64, -) { +fn populate_edges(g: &G, new_graph: &Graph, v: V, delta: i64) { if let Some(vertex) = g.node(v) { // get vector of vertices which need connecting up let mut visitors = vertex