From 3b6fce4c920586c6ffca692bc325b163ea78a08c Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 19 Dec 2024 11:28:52 +0100 Subject: [PATCH 01/29] initial implementation of group_by --- raphtory/src/db/api/state/group_by.rs | 37 +++++++++++++++++++++ raphtory/src/db/api/state/node_state_ops.rs | 16 +++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index 8b13789179..9a811480ff 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -1 +1,38 @@ +use crate::prelude::NodeStateOps; +use raphtory_api::core::entities::VID; +use rayon::prelude::*; +use std::{collections::HashMap, hash::Hash, sync::Arc}; +#[derive(Clone, Debug)] +pub struct NodeGroups { + groups: Arc>>, + base_graph: G, + graph: GH, +} + +impl NodeGroups { + pub(crate) fn new(values: impl Iterator, base_graph: G, graph: GH) -> Self { + let mut groups: HashMap> = HashMap::new(); + for (node, v) in values { + groups.entry(v).or_insert_with(Vec::new).push(node); + } + let groups = Arc::new(groups.into_iter().map(|(k, v)| (k, v.into())).collect()); + Self { + groups, + base_graph, + graph, + } + } +} +pub trait NodeStateGroupBy<'graph>: NodeStateOps<'graph> { + fn groups(&self) -> NodeGroups; +} + +impl<'graph, S: NodeStateOps<'graph>> NodeStateGroupBy<'graph> for S +where + S::OwnedValue: Hash + Eq, +{ + fn groups(&self) -> NodeGroups { + self.group_by(|v| v.clone()) + } +} diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index dded6bc8d0..f2b36eab0a 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -2,7 +2,7 @@ use crate::{ core::entities::nodes::node_ref::AsNodeRef, db::{ api::{ - state::{node_state::NodeState, node_state_ord_ops, Index}, + state::{group_by::NodeGroups, node_state::NodeState, node_state_ord_ops, Index}, view::internal::CoreGraphOps, }, graph::node::NodeView, @@ -14,7 +14,7 @@ use rayon::{ iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}, prelude::ParallelSliceMut, }; -use std::{borrow::Borrow, iter::Sum}; +use std::{borrow::Borrow, hash::Hash, iter::Sum}; pub trait NodeStateOps<'graph>: IntoIterator { type Graph: GraphViewOps<'graph>; @@ -216,6 +216,18 @@ pub trait NodeStateOps<'graph>: IntoIterator { values.into_iter().nth(median_index) } + fn group_by V + Sync>( + &self, + group_fn: F, + ) -> NodeGroups { + NodeGroups::new( + self.iter() + .map(|(node, v)| (node.node, group_fn(v.borrow()))), + self.base_graph().clone(), + self.graph().clone(), + ) + } + fn sum<'a, S>(&'a self) -> S where 'graph: 'a, From b4a932f70c93734cf1ef19b1a44056f0f22387da Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 20 Dec 2024 09:51:35 +0100 Subject: [PATCH 02/29] change index to use RoaringTreeMap instead so it is more memory efficient --- .../algorithms/components/in_components.rs | 2 +- .../algorithms/components/out_components.rs | 2 +- raphtory/src/db/api/state/lazy_node_state.rs | 5 +- raphtory/src/db/api/state/node_state.rs | 76 ++++++++++--------- raphtory/src/db/api/state/node_state_ops.rs | 6 +- .../db/api/storage/graph/storage_ops/mod.rs | 2 +- raphtory/src/db/api/view/graph.rs | 2 +- raphtory/src/db/api/view/internal/list_ops.rs | 4 +- raphtory/src/db/graph/nodes.rs | 62 +++++++++++---- raphtory/src/db/graph/views/node_subgraph.rs | 9 +-- raphtory/src/db/graph/views/window_graph.rs | 2 +- raphtory/src/python/graph/node.rs | 2 +- 12 files changed, 100 insertions(+), 74 deletions(-) diff --git a/raphtory/src/algorithms/components/in_components.rs b/raphtory/src/algorithms/components/in_components.rs index b5dfc6d89f..bc4225599a 100644 --- a/raphtory/src/algorithms/components/in_components.rs +++ b/raphtory/src/algorithms/components/in_components.rs @@ -135,7 +135,7 @@ pub fn in_component<'graph, G: GraphViewOps<'graph>>( node.graph.clone(), node.graph.clone(), distances, - Some(Index::new(nodes, node.graph.unfiltered_num_nodes())), + Some(Index::new(nodes)), ) } diff --git a/raphtory/src/algorithms/components/out_components.rs b/raphtory/src/algorithms/components/out_components.rs index 26a76a8a83..94d6cd1ce3 100644 --- a/raphtory/src/algorithms/components/out_components.rs +++ b/raphtory/src/algorithms/components/out_components.rs @@ -138,7 +138,7 @@ pub fn out_component<'graph, G: GraphViewOps<'graph>>( node.graph.clone(), node.graph.clone(), distances, - Some(Index::new(nodes, node.graph.unfiltered_num_nodes())), + Some(Index::new(nodes)), ) } diff --git a/raphtory/src/db/api/state/lazy_node_state.rs b/raphtory/src/db/api/state/lazy_node_state.rs index bfd0fc5a13..bb1e4da003 100644 --- a/raphtory/src/db/api/state/lazy_node_state.rs +++ b/raphtory/src/db/api/state/lazy_node_state.rs @@ -97,10 +97,7 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra self.nodes.base_graph.clone(), self.nodes.graph.clone(), values, - Some(Index::new( - keys, - self.nodes.base_graph.unfiltered_num_nodes(), - )), + Some(Index::new(keys)), ) } else { let values = self.collect_vec(); diff --git a/raphtory/src/db/api/state/node_state.rs b/raphtory/src/db/api/state/node_state.rs index 93ca053b2b..0ed9eae548 100644 --- a/raphtory/src/db/api/state/node_state.rs +++ b/raphtory/src/db/api/state/node_state.rs @@ -7,63 +7,66 @@ use crate::{ prelude::GraphViewOps, }; use rayon::{iter::Either, prelude::*}; +use roaring::RoaringTreemap; use std::{fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc}; #[derive(Clone, Debug)] pub struct Index { - keys: Arc<[K]>, - map: Arc<[bool]>, + pub(crate) set: Arc, + len: usize, // cache the len for the set as it is recomputed every time + _phantom: PhantomData, } -impl> Index { - pub fn new(keys: impl Into>, n: usize) -> Self { - let keys = keys.into(); - let mut map = vec![false; n]; - for k in keys.iter().copied() { - map[k.into()] = true; - } +impl + From + Send + Sync> Index { + pub fn new(keys: impl IntoIterator) -> Self { + let set: Arc = + Arc::new(keys.into_iter().map(|k| k.into() as u64).collect()); + let len = set.len() as usize; Self { - keys, - map: map.into(), + set, + len, + _phantom: PhantomData, } } -} - -impl + Send + Sync> Index { - pub fn iter(&self) -> impl Iterator + '_ { - self.keys.iter() + pub fn iter(&self) -> impl Iterator + '_ { + self.set.iter().map(|k| K::from(k as usize)) } pub fn into_par_iter(self) -> impl IndexedParallelIterator { - let keys = self.keys; - (0..keys.len()).into_par_iter().map(move |i| keys[i]) + (0..self.len()) + .into_par_iter() + .map(move |i| self.key(i).unwrap()) } pub fn into_iter(self) -> impl Iterator { - let keys = self.keys; - (0..keys.len()).map(move |i| keys[i]) + (0..self.len()).map(move |i| self.key(i).unwrap()) } pub fn index(&self, key: &K) -> Option { - self.keys.binary_search(key).ok() + let rank = self.set.rank((*key).into() as u64) as usize; + if rank < self.len() { + Some(rank) + } else { + None + } } pub fn key(&self, index: usize) -> Option { - self.keys.get(index).copied() + self.set.select(index as u64).map(|k| K::from(k as usize)) } pub fn len(&self) -> usize { - self.keys.len() + self.len } pub fn contains(&self, key: &K) -> bool { - self.map.get((*key).into()).copied().unwrap_or(false) + self.set.contains((*key).into() as u64) } -} -impl Index { - pub fn par_iter(&self) -> impl IndexedParallelIterator + '_ { - self.keys.par_iter() + pub fn par_iter(&self) -> impl IndexedParallelIterator + '_ { + (0..self.len()) + .into_par_iter() + .map(move |i| self.key(i).unwrap()) } } @@ -160,12 +163,11 @@ impl< { match &self.keys { Some(index) => index - .keys .iter() .zip(self.values.iter()) .map(|(n, v)| { ( - NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, *n), + NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, n), v, ) }) @@ -199,14 +201,14 @@ impl< 'graph: 'a, { match &self.keys { - Some(index) => Either::Left(index.keys.par_iter().zip(self.values.par_iter()).map( - |(n, v)| { + Some(index) => { + Either::Left(index.par_iter().zip(self.values.par_iter()).map(|(n, v)| { ( - NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, *n), + NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, n), v, ) - }, - )), + })) + } None => Either::Right(self.values.par_iter().enumerate().map(|(i, v)| { ( NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, VID(i)), @@ -221,9 +223,9 @@ impl< index: usize, ) -> Option<(NodeView<&Self::BaseGraph, &Self::Graph>, Self::Value<'_>)> { match &self.keys { - Some(node_index) => node_index.keys.get(index).map(|n| { + Some(node_index) => node_index.key(index).map(|n| { ( - NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, *n), + NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, n), &self.values[index], ) }), diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index f2b36eab0a..6d094740c7 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -113,7 +113,7 @@ pub trait NodeStateOps<'graph>: IntoIterator { self.base_graph().clone(), self.graph().clone(), values, - Some(Index::new(keys, self.base_graph().unfiltered_num_nodes())), + Some(Index::new(keys)), ) } } @@ -137,7 +137,7 @@ pub trait NodeStateOps<'graph>: IntoIterator { self.base_graph().clone(), self.graph().clone(), values, - Some(Index::new(keys, self.base_graph().unfiltered_num_nodes())), + Some(Index::new(keys)), ) } @@ -174,7 +174,7 @@ pub trait NodeStateOps<'graph>: IntoIterator { self.base_graph().clone(), self.graph().clone(), values, - Some(Index::new(keys, self.base_graph().unfiltered_num_nodes())), + Some(Index::new(keys)), ) } diff --git a/raphtory/src/db/api/storage/graph/storage_ops/mod.rs b/raphtory/src/db/api/storage/graph/storage_ops/mod.rs index 4e8cde1a4f..0e7aa28f49 100644 --- a/raphtory/src/db/api/storage/graph/storage_ops/mod.rs +++ b/raphtory/src/db/api/storage/graph/storage_ops/mod.rs @@ -305,7 +305,7 @@ impl GraphStorage { let nodes_storage = self.nodes(); nodes .par_iter() - .filter(|vid| view.filter_node(nodes_storage.node(**vid), layer_ids)) + .filter(|&vid| view.filter_node(nodes_storage.node(vid), layer_ids)) .count() } } diff --git a/raphtory/src/db/api/view/graph.rs b/raphtory/src/db/api/view/graph.rs index dbad41f8e1..d7aab4f71c 100644 --- a/raphtory/src/db/api/view/graph.rs +++ b/raphtory/src/db/api/view/graph.rs @@ -403,7 +403,7 @@ impl<'graph, G: BoxableGraphView + Sized + Clone + 'graph> GraphViewOps<'graph> .count(), NodeList::List { nodes } => nodes .par_iter() - .filter(move |&&id| self.filter_node(core_nodes.node_entry(id), layer_ids)) + .filter(move |&id| self.filter_node(core_nodes.node_entry(id), layer_ids)) .count(), } } else { diff --git a/raphtory/src/db/api/view/internal/list_ops.rs b/raphtory/src/db/api/view/internal/list_ops.rs index 3091899086..8040aa91ea 100644 --- a/raphtory/src/db/api/view/internal/list_ops.rs +++ b/raphtory/src/db/api/view/internal/list_ops.rs @@ -38,7 +38,7 @@ impl NodeList { pub fn par_iter(&self) -> impl IndexedParallelIterator + '_ { match self { NodeList::All { num_nodes } => Either::Left((0..*num_nodes).into_par_iter().map(VID)), - NodeList::List { nodes } => Either::Right(nodes.par_iter().copied()), + NodeList::List { nodes } => Either::Right(nodes.par_iter()), } } @@ -56,7 +56,7 @@ impl NodeList { pub fn iter(&self) -> impl Iterator + '_ { match self { NodeList::All { num_nodes } => Either::Left((0..*num_nodes).map(VID)), - NodeList::List { nodes } => Either::Right(nodes.iter().copied()), + NodeList::List { nodes } => Either::Right(nodes.iter()), } } diff --git a/raphtory/src/db/graph/nodes.rs b/raphtory/src/db/graph/nodes.rs index be1431c7dd..5483d0d511 100644 --- a/raphtory/src/db/graph/nodes.rs +++ b/raphtory/src/db/graph/nodes.rs @@ -14,7 +14,11 @@ use crate::{ prelude::*, }; -use crate::db::{api::state::NodeOp, graph::create_node_type_filter}; +use crate::db::{ + api::state::{Index, NodeOp}, + graph::{create_node_type_filter, views::node_subgraph::NodeSubgraph}, +}; +use either::Either; use rayon::iter::ParallelIterator; use std::{ fmt::{Debug, Formatter}, @@ -26,6 +30,7 @@ use std::{ pub struct Nodes<'graph, G, GH = G> { pub(crate) base_graph: G, pub(crate) graph: GH, + pub(crate) nodes: Option>, pub(crate) node_types_filter: Option>, _marker: PhantomData<&'graph ()>, } @@ -49,6 +54,7 @@ where Nodes { base_graph, graph, + nodes: value.nodes, node_types_filter: value.node_types_filter, _marker: PhantomData, } @@ -64,6 +70,7 @@ where Self { base_graph, graph, + nodes: None, node_types_filter: None, _marker: PhantomData, } @@ -92,10 +99,16 @@ where G: GraphViewOps<'graph> + 'graph, GH: GraphViewOps<'graph> + 'graph, { - pub fn new_filtered(base_graph: G, graph: GH, node_types_filter: Option>) -> Self { + pub fn new_filtered( + base_graph: G, + graph: GH, + nodes: Option>, + node_types_filter: Option>, + ) -> Self { Self { base_graph, graph, + nodes, node_types_filter, _marker: PhantomData, } @@ -104,19 +117,36 @@ where pub(crate) fn par_iter_refs(&self) -> impl ParallelIterator + 'graph { let g = self.graph.core_graph().lock(); let node_types_filter = self.node_types_filter.clone(); - g.into_nodes_par(self.graph.clone(), node_types_filter) + match self.nodes.clone() { + None => Either::Left(g.into_nodes_par(self.graph.clone(), node_types_filter)), + Some(nodes) => { + let gs = NodeSubgraph { + graph: self.graph.clone(), + nodes, + }; + Either::Right(g.into_nodes_par(gs, node_types_filter)) + } + } } #[inline] pub(crate) fn iter_refs(&self) -> impl Iterator + Send + Sync + 'graph { let g = self.graph.core_graph().lock(); let node_types_filter = self.node_types_filter.clone(); - g.into_nodes_iter(self.graph.clone(), node_types_filter) + match self.nodes.clone() { + None => g.into_nodes_iter(self.graph.clone(), node_types_filter), + Some(nodes) => { + let gs = NodeSubgraph { + graph: self.graph.clone(), + nodes, + }; + g.into_nodes_iter(gs, node_types_filter) + } + } } - pub fn iter(&self) -> impl Iterator> + '_ { - let cg = self.graph.core_graph().lock(); - cg.into_nodes_iter(&self.graph, self.node_types_filter.clone()) + pub fn iter(&self) -> impl Iterator> + use<'_, 'graph, G, GH> { + self.iter_refs() .map(|v| NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, v)) } @@ -128,19 +158,17 @@ where .into_dyn_boxed() } - pub fn par_iter(&self) -> impl ParallelIterator> + '_ { - let cg = self.graph.core_graph().lock(); - let node_types_filter = self.node_types_filter.clone(); - cg.into_nodes_par(&self.graph, node_types_filter) + pub fn par_iter( + &self, + ) -> impl ParallelIterator> + use<'_, 'graph, G, GH> { + self.par_iter_refs() .map(|v| NodeView::new_one_hop_filtered(&self.base_graph, &self.graph, v)) } pub fn into_par_iter(self) -> impl ParallelIterator> + 'graph { - let cg = self.graph.core_graph().lock(); - cg.into_nodes_par(self.graph.clone(), self.node_types_filter) - .map(move |n| { - NodeView::new_one_hop_filtered(self.base_graph.clone(), self.graph.clone(), n) - }) + self.par_iter_refs().map(move |n| { + NodeView::new_one_hop_filtered(self.base_graph.clone(), self.graph.clone(), n) + }) } /// Returns the number of nodes in the graph. @@ -170,6 +198,7 @@ where Nodes { base_graph: self.base_graph.clone(), graph: self.graph.clone(), + nodes: self.nodes.clone(), node_types_filter, _marker: PhantomData, } @@ -281,6 +310,7 @@ where Nodes { base_graph, graph: filtered_graph, + nodes: self.nodes.clone(), node_types_filter: self.node_types_filter.clone(), _marker: PhantomData, } diff --git a/raphtory/src/db/graph/views/node_subgraph.rs b/raphtory/src/db/graph/views/node_subgraph.rs index 5f66f94ea8..ed2f88f3e6 100644 --- a/raphtory/src/db/graph/views/node_subgraph.rs +++ b/raphtory/src/db/graph/views/node_subgraph.rs @@ -54,14 +54,11 @@ impl<'graph, G: GraphViewOps<'graph>> NodeSubgraph { let nodes = nodes .into_iter() .flat_map(|v| graph.internalise_node(v.as_node_ref())); - let mut nodes: Vec<_> = if graph.nodes_filtered() { - nodes.filter(|n| graph.has_node(*n)).collect() + let nodes = if graph.nodes_filtered() { + Index::new(nodes.filter(|n| graph.has_node(*n))) } else { - nodes.collect() + Index::new(nodes) }; - nodes.sort(); - nodes.dedup(); - let nodes = Index::new(nodes, graph.unfiltered_num_nodes()); Self { graph, nodes } } } diff --git a/raphtory/src/db/graph/views/window_graph.rs b/raphtory/src/db/graph/views/window_graph.rs index 201f40b09f..0413b19e9f 100644 --- a/raphtory/src/db/graph/views/window_graph.rs +++ b/raphtory/src/db/graph/views/window_graph.rs @@ -137,7 +137,7 @@ impl<'graph, G: GraphViewOps<'graph>> ListOps for WindowedGraph { fn node_list(&self) -> NodeList { if self.window_is_empty() { NodeList::List { - nodes: Index::new(vec![], self.graph.unfiltered_num_nodes()), + nodes: Index::new(vec![]), } } else { self.graph.node_list() diff --git a/raphtory/src/python/graph/node.rs b/raphtory/src/python/graph/node.rs index a1589c5047..5b3f2d4ea3 100644 --- a/raphtory/src/python/graph/node.rs +++ b/raphtory/src/python/graph/node.rs @@ -495,7 +495,7 @@ impl let graph = value.graph.into_dynamic(); let base_graph = value.base_graph.into_dynamic(); Self { - nodes: Nodes::new_filtered(base_graph, graph, value.node_types_filter), + nodes: Nodes::new_filtered(base_graph, graph, value.nodes, value.node_types_filter), } } } From 213dd72618b7a0e903e48b2e0c677d8732141dab Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 20 Dec 2024 13:24:26 +0100 Subject: [PATCH 03/29] bring back node list --- raphtory/src/db/api/state/group_by.rs | 21 +++++++++++++++-- raphtory/src/db/api/state/node_state.rs | 31 ++++++++++++------------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index 9a811480ff..34eb1bc5ee 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -1,11 +1,14 @@ -use crate::prelude::NodeStateOps; +use crate::{ + db::{api::state::Index, graph::nodes::Nodes}, + prelude::NodeStateOps, +}; use raphtory_api::core::entities::VID; use rayon::prelude::*; use std::{collections::HashMap, hash::Hash, sync::Arc}; #[derive(Clone, Debug)] pub struct NodeGroups { - groups: Arc>>, + groups: Arc>>, base_graph: G, graph: GH, } @@ -23,6 +26,20 @@ impl NodeGroups { graph, } } + + fn groups(&self) -> impl Iterator)> { + self.groups.iter().map(|(v, nodes)| { + ( + v, + Nodes::new_filtered( + self.base_graph.clone(), + self.graph.clone(), + Some(nodes.clone()), + None, + ), + ) + }) + } } pub trait NodeStateGroupBy<'graph>: NodeStateOps<'graph> { fn groups(&self) -> NodeGroups; diff --git a/raphtory/src/db/api/state/node_state.rs b/raphtory/src/db/api/state/node_state.rs index 0ed9eae548..1350d13f48 100644 --- a/raphtory/src/db/api/state/node_state.rs +++ b/raphtory/src/db/api/state/node_state.rs @@ -12,34 +12,35 @@ use std::{fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc}; #[derive(Clone, Debug)] pub struct Index { + pub(crate) list: Arc<[K]>, pub(crate) set: Arc, - len: usize, // cache the len for the set as it is recomputed every time _phantom: PhantomData, } -impl + From + Send + Sync> Index { +impl + From + Send + Sync> Index { pub fn new(keys: impl IntoIterator) -> Self { - let set: Arc = - Arc::new(keys.into_iter().map(|k| k.into() as u64).collect()); - let len = set.len() as usize; + let mut list: Vec<_> = keys.into_iter().collect(); + list.sort_unstable(); + list.dedup(); + let set: Arc = Arc::new( + RoaringTreemap::from_sorted_iter(list.iter().map(|&k| k.into() as u64)).unwrap(), + ); Self { set, - len, + list: list.into(), _phantom: PhantomData, } } pub fn iter(&self) -> impl Iterator + '_ { - self.set.iter().map(|k| K::from(k as usize)) + self.list.iter().copied() } pub fn into_par_iter(self) -> impl IndexedParallelIterator { - (0..self.len()) - .into_par_iter() - .map(move |i| self.key(i).unwrap()) + (0..self.len()).into_par_iter().map(move |i| self.list[i]) } pub fn into_iter(self) -> impl Iterator { - (0..self.len()).map(move |i| self.key(i).unwrap()) + (0..self.len()).map(move |i| self.list[i]) } pub fn index(&self, key: &K) -> Option { @@ -52,11 +53,11 @@ impl + From + Send + Sync> Index { } pub fn key(&self, index: usize) -> Option { - self.set.select(index as u64).map(|k| K::from(k as usize)) + self.list.get(index).copied() } pub fn len(&self) -> usize { - self.len + self.list.len() } pub fn contains(&self, key: &K) -> bool { @@ -64,9 +65,7 @@ impl + From + Send + Sync> Index { } pub fn par_iter(&self) -> impl IndexedParallelIterator + '_ { - (0..self.len()) - .into_par_iter() - .map(move |i| self.key(i).unwrap()) + self.list.par_iter().copied() } } From 9dd123e16bcc47a5ae742eafb2ec8a693850e51a Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 20 Dec 2024 13:39:41 +0100 Subject: [PATCH 04/29] minor tweaks --- raphtory/src/db/api/state/group_by.rs | 35 +++++++++++-------- raphtory/src/db/api/view/internal/list_ops.rs | 4 +-- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index 34eb1bc5ee..53058b6950 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -13,13 +13,18 @@ pub struct NodeGroups { graph: GH, } -impl NodeGroups { +impl NodeGroups { pub(crate) fn new(values: impl Iterator, base_graph: G, graph: GH) -> Self { let mut groups: HashMap> = HashMap::new(); for (node, v) in values { groups.entry(v).or_insert_with(Vec::new).push(node); } - let groups = Arc::new(groups.into_iter().map(|(k, v)| (k, v.into())).collect()); + let groups = Arc::new( + groups + .into_iter() + .map(|(k, v)| (k, Index::new(v))) + .collect(), + ); Self { groups, base_graph, @@ -27,19 +32,19 @@ impl NodeGroups { } } - fn groups(&self) -> impl Iterator)> { - self.groups.iter().map(|(v, nodes)| { - ( - v, - Nodes::new_filtered( - self.base_graph.clone(), - self.graph.clone(), - Some(nodes.clone()), - None, - ), - ) - }) - } + // fn groups(&self) -> impl Iterator)> { + // self.groups.iter().map(|(v, nodes)| { + // ( + // v, + // Nodes::new_filtered( + // self.base_graph.clone(), + // self.graph.clone(), + // Some(nodes.clone()), + // None, + // ), + // ) + // }) + // } } pub trait NodeStateGroupBy<'graph>: NodeStateOps<'graph> { fn groups(&self) -> NodeGroups; diff --git a/raphtory/src/db/api/view/internal/list_ops.rs b/raphtory/src/db/api/view/internal/list_ops.rs index 8040aa91ea..3f134aaa90 100644 --- a/raphtory/src/db/api/view/internal/list_ops.rs +++ b/raphtory/src/db/api/view/internal/list_ops.rs @@ -46,9 +46,7 @@ impl NodeList { match self { NodeList::All { num_nodes } => Either::Left((0..num_nodes).into_par_iter().map(VID)), NodeList::List { nodes } => Either::Right( - (0..nodes.len()) - .into_par_iter() - .map(move |i| nodes.key(i).unwrap()), + nodes.into_par_iter(), ), } } From d765249c74162f43cd2956cb6ce992f6d80d15b6 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 2 Jan 2025 11:59:20 +0100 Subject: [PATCH 05/29] add multi-path to test --- raphtory/src/algorithms/components/out_components.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/raphtory/src/algorithms/components/out_components.rs b/raphtory/src/algorithms/components/out_components.rs index 94d6cd1ce3..e761b893e0 100644 --- a/raphtory/src/algorithms/components/out_components.rs +++ b/raphtory/src/algorithms/components/out_components.rs @@ -164,6 +164,7 @@ mod components_test { let edges = vec![ (1, 1, 2), (1, 1, 3), + (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 5, 4), @@ -181,7 +182,11 @@ mod components_test { 1, vec![(2, 1), (3, 1), (4, 2), (5, 2), (6, 3), (7, 3), (8, 3)], ); - check_node(&graph, 2, vec![(4, 1), (5, 1), (6, 2), (7, 2), (8, 2)]); + check_node( + &graph, + 2, + vec![(3, 1), (4, 1), (5, 1), (6, 2), (7, 2), (8, 2)], + ); check_node(&graph, 3, vec![]); check_node(&graph, 4, vec![(6, 1), (7, 1)]); check_node(&graph, 5, vec![(4, 1), (6, 2), (7, 2), (8, 1)]); From 0940beb16f9674a2cda915804ec65993dc425ea8 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 2 Jan 2025 12:00:37 +0100 Subject: [PATCH 06/29] basic group by implemented --- examples/custom-gql-apis/Cargo.toml | 1 - examples/custom-gql-apis/pyproject.toml | 1 + python/Cargo.toml | 2 +- raphtory/src/db/api/state/group_by.rs | 113 ++++++++++++------ raphtory/src/db/api/state/node_state_ops.rs | 3 +- raphtory/src/db/api/view/internal/list_ops.rs | 4 +- 6 files changed, 83 insertions(+), 41 deletions(-) diff --git a/examples/custom-gql-apis/Cargo.toml b/examples/custom-gql-apis/Cargo.toml index 37bb1456bb..95c9191c15 100644 --- a/examples/custom-gql-apis/Cargo.toml +++ b/examples/custom-gql-apis/Cargo.toml @@ -7,7 +7,6 @@ authors = ["Pometry"] rust-version = "1.75.0" edition = "2021" -doc = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[lib] [lib] name = "raphtory" diff --git a/examples/custom-gql-apis/pyproject.toml b/examples/custom-gql-apis/pyproject.toml index 95ce621651..500213e42c 100644 --- a/examples/custom-gql-apis/pyproject.toml +++ b/examples/custom-gql-apis/pyproject.toml @@ -10,6 +10,7 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ] +dynamic = ["version"] [tool.maturin] features = ["pyo3/extension-module"] diff --git a/python/Cargo.toml b/python/Cargo.toml index 47a95e7a31..faaf1a92e7 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -11,7 +11,7 @@ repository.workspace = true license.workspace = true readme.workspace = true homepage.workspace = true -doc = false + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] name = "raphtory" diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index 53058b6950..8c108d842a 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -1,60 +1,105 @@ use crate::{ - db::{api::state::Index, graph::nodes::Nodes}, - prelude::NodeStateOps, + db::{ + api::state::Index, + graph::{nodes::Nodes, views::node_subgraph::NodeSubgraph}, + }, + prelude::{GraphViewOps, NodeStateOps}, }; use raphtory_api::core::entities::VID; use rayon::prelude::*; use std::{collections::HashMap, hash::Hash, sync::Arc}; #[derive(Clone, Debug)] -pub struct NodeGroups { - groups: Arc>>, - base_graph: G, - graph: GH, +pub struct NodeGroups { + groups: Arc<[(V, Index)]>, + graph: G, } -impl NodeGroups { - pub(crate) fn new(values: impl Iterator, base_graph: G, graph: GH) -> Self { +impl<'graph, V: Hash + Eq, G: GraphViewOps<'graph>> NodeGroups { + pub(crate) fn new(values: impl Iterator, graph: G) -> Self { let mut groups: HashMap> = HashMap::new(); for (node, v) in values { groups.entry(v).or_insert_with(Vec::new).push(node); } - let groups = Arc::new( - groups - .into_iter() - .map(|(k, v)| (k, Index::new(v))) - .collect(), - ); - Self { - groups, - base_graph, - graph, - } + let groups = groups + .into_iter() + .map(|(k, v)| (k, Index::new(v))) + .collect(); + Self { groups, graph } + } + + pub fn iter(&self) -> impl Iterator)> { + self.groups.iter().map(|(v, nodes)| { + ( + v, + Nodes::new_filtered( + self.graph.clone(), + self.graph.clone(), + Some(nodes.clone()), + None, + ), + ) + }) + } + + pub fn iter_subgraphs(&self) -> impl Iterator)> { + self.groups.iter().map(|(v, nodes)| { + ( + v, + NodeSubgraph { + graph: self.graph.clone(), + nodes: nodes.clone(), + }, + ) + }) + } + + pub fn group(&self, index: usize) -> Option<(&V, Nodes<'graph, G>)> { + self.groups.get(index).map(|(v, nodes)| { + ( + v, + Nodes::new_filtered( + self.graph.clone(), + self.graph.clone(), + Some(nodes.clone()), + None, + ), + ) + }) } - // fn groups(&self) -> impl Iterator)> { - // self.groups.iter().map(|(v, nodes)| { - // ( - // v, - // Nodes::new_filtered( - // self.base_graph.clone(), - // self.graph.clone(), - // Some(nodes.clone()), - // None, - // ), - // ) - // }) - // } + pub fn group_subgraph(&self, index: usize) -> Option<(&V, NodeSubgraph)> { + self.groups.get(index).map(|(v, nodes)| { + ( + v, + NodeSubgraph { + graph: self.graph.clone(), + nodes: nodes.clone(), + }, + ) + }) + } + + pub fn len(&self) -> usize { + self.groups.len() + } + + pub fn is_empty(&self) -> bool { + self.groups.is_empty() + } } pub trait NodeStateGroupBy<'graph>: NodeStateOps<'graph> { - fn groups(&self) -> NodeGroups; + fn groups(&self) -> NodeGroups; } impl<'graph, S: NodeStateOps<'graph>> NodeStateGroupBy<'graph> for S where S::OwnedValue: Hash + Eq, { - fn groups(&self) -> NodeGroups { + fn groups(&self) -> NodeGroups { self.group_by(|v| v.clone()) } } + +#[cfg(test)] +mod tests {} diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index 6d094740c7..a6a2d910db 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -219,11 +219,10 @@ pub trait NodeStateOps<'graph>: IntoIterator { fn group_by V + Sync>( &self, group_fn: F, - ) -> NodeGroups { + ) -> NodeGroups { NodeGroups::new( self.iter() .map(|(node, v)| (node.node, group_fn(v.borrow()))), - self.base_graph().clone(), self.graph().clone(), ) } diff --git a/raphtory/src/db/api/view/internal/list_ops.rs b/raphtory/src/db/api/view/internal/list_ops.rs index 3f134aaa90..8ad69df877 100644 --- a/raphtory/src/db/api/view/internal/list_ops.rs +++ b/raphtory/src/db/api/view/internal/list_ops.rs @@ -45,9 +45,7 @@ impl NodeList { pub fn into_par_iter(self) -> impl IndexedParallelIterator { match self { NodeList::All { num_nodes } => Either::Left((0..num_nodes).into_par_iter().map(VID)), - NodeList::List { nodes } => Either::Right( - nodes.into_par_iter(), - ), + NodeList::List { nodes } => Either::Right(nodes.into_par_iter()), } } From d2b1f0eed23276fd7048fb378aa5a83d65db997a Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 3 Jan 2025 10:10:12 +0100 Subject: [PATCH 07/29] use index map --- Cargo.lock | 3 ++ Cargo.toml | 1 + raphtory-api/Cargo.toml | 7 ++-- raphtory/Cargo.toml | 7 +++- raphtory/src/db/api/state/node_state.rs | 50 ++++++++++++------------- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd9484af9a..d9e43f6747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,6 +72,7 @@ dependencies = [ "const-random", "getrandom", "once_cell", + "serde", "version_check", "zerocopy", ] @@ -4823,6 +4824,7 @@ dependencies = [ name = "raphtory" version = "0.14.0" dependencies = [ + "ahash", "async-openai", "async-trait", "bincode", @@ -4839,6 +4841,7 @@ dependencies = [ "futures-util", "glam", "hashbrown 0.15.2", + "indexmap 2.7.0", "indoc", "itertools 0.13.0", "kdam", diff --git a/Cargo.toml b/Cargo.toml index 13d7956660..042fd83764 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -155,3 +155,4 @@ arrow-buffer = { version = "53.2.0" } arrow-schema = { version = "53.2.0" } arrow-array = { version = "53.2.0" } moka = { version = "0.12.7", features = ["sync"] } +indexmap = "2.7.0" diff --git a/raphtory-api/Cargo.toml b/raphtory-api/Cargo.toml index 72c700aab7..3980d21637 100644 --- a/raphtory-api/Cargo.toml +++ b/raphtory-api/Cargo.toml @@ -23,15 +23,16 @@ dashmap = { workspace = true } rustc-hash = { workspace = true } lock_api = { workspace = true } parking_lot = { workspace = true } -polars-arrow = { workspace = true, optional = true} +polars-arrow = { workspace = true, optional = true } pyo3 = { workspace = true, optional = true } rayon = { workspace = true } rand = { workspace = true } quickcheck_macros = { workspace = true } num-traits = { workspace = true } twox-hash.workspace = true -tracing-subscriber = {workspace = true} -tracing = {workspace = true} +tracing-subscriber = { workspace = true } +tracing = { workspace = true } + [dev-dependencies] proptest.workspace = true quickcheck.workspace = true diff --git a/raphtory/Cargo.toml b/raphtory/Cargo.toml index 0ea9c5ebf1..71a4c70cae 100644 --- a/raphtory/Cargo.toml +++ b/raphtory/Cargo.toml @@ -28,6 +28,7 @@ rand_distr = { workspace = true } rayon = { workspace = true } regex = { workspace = true } rustc-hash = { workspace = true } +indexmap = { workspace = true } serde = { workspace = true } sorted_vector_map = { workspace = true } thiserror = { workspace = true } @@ -40,9 +41,10 @@ quad-rand = { workspace = true } serde_json = { workspace = true } ouroboros = { workspace = true } either = { workspace = true } -kdam = { workspace = true, optional = true} +kdam = { workspace = true, optional = true } bytemuck = { workspace = true } tracing = { workspace = true } +ahash = { workspace = true } # io optional dependencies csv = { workspace = true, optional = true } @@ -77,7 +79,8 @@ pometry-storage = { workspace = true, optional = true } prost = { workspace = true, optional = true } prost-types = { workspace = true, optional = true } -roaring ={ workspace = true } +roaring = { workspace = true } + [dev-dependencies] csv = { workspace = true } diff --git a/raphtory/src/db/api/state/node_state.rs b/raphtory/src/db/api/state/node_state.rs index 1350d13f48..c6a1084b4d 100644 --- a/raphtory/src/db/api/state/node_state.rs +++ b/raphtory/src/db/api/state/node_state.rs @@ -6,66 +6,62 @@ use crate::{ }, prelude::GraphViewOps, }; +use indexmap::IndexSet; use rayon::{iter::Either, prelude::*}; -use roaring::RoaringTreemap; use std::{fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc}; #[derive(Clone, Debug)] pub struct Index { - pub(crate) list: Arc<[K]>, - pub(crate) set: Arc, - _phantom: PhantomData, + index: Arc>, } -impl + From + Send + Sync> Index { +impl + From + Send + Sync> Index { pub fn new(keys: impl IntoIterator) -> Self { - let mut list: Vec<_> = keys.into_iter().collect(); - list.sort_unstable(); - list.dedup(); - let set: Arc = Arc::new( - RoaringTreemap::from_sorted_iter(list.iter().map(|&k| k.into() as u64)).unwrap(), - ); Self { - set, - list: list.into(), - _phantom: PhantomData, + index: Arc::new(IndexSet::from_iter(keys)), } } + + #[inline] pub fn iter(&self) -> impl Iterator + '_ { - self.list.iter().copied() + self.index.iter().copied() } + #[inline] pub fn into_par_iter(self) -> impl IndexedParallelIterator { - (0..self.len()).into_par_iter().map(move |i| self.list[i]) + (0..self.len()) + .into_par_iter() + .map(move |i| *self.index.get_index(i).unwrap()) } pub fn into_iter(self) -> impl Iterator { - (0..self.len()).map(move |i| self.list[i]) + (0..self.len()).map(move |i| *self.index.get_index(i).unwrap()) } + #[inline] pub fn index(&self, key: &K) -> Option { - let rank = self.set.rank((*key).into() as u64) as usize; - if rank < self.len() { - Some(rank) - } else { - None - } + self.index.get_index_of(key) } + #[inline] pub fn key(&self, index: usize) -> Option { - self.list.get(index).copied() + self.index.get_index(index).copied() } + #[inline] pub fn len(&self) -> usize { - self.list.len() + self.index.len() } + #[inline] pub fn contains(&self, key: &K) -> bool { - self.set.contains((*key).into() as u64) + self.index.contains(key) } pub fn par_iter(&self) -> impl IndexedParallelIterator + '_ { - self.list.par_iter().copied() + (0..self.len()) + .into_par_iter() + .map(move |i| *self.index.get_index(i).unwrap()) } } From e43734601524b36714576286541b5b7e0dbfbeb7 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Mon, 6 Jan 2025 15:16:18 +0100 Subject: [PATCH 08/29] rethink the node state python interface --- raphtory-graphql/src/model/graph/node.rs | 16 +-- raphtory/src/db/api/state/lazy_node_state.rs | 12 ++- raphtory/src/db/api/state/node_state.rs | 106 +++++++++++++++++-- raphtory/src/db/api/state/node_state_ops.rs | 15 +-- raphtory/src/db/graph/graph.rs | 10 +- raphtory/src/db/graph/nodes.rs | 12 +++ 6 files changed, 135 insertions(+), 36 deletions(-) diff --git a/raphtory-graphql/src/model/graph/node.rs b/raphtory-graphql/src/model/graph/node.rs index a393414e30..e955b697b8 100644 --- a/raphtory-graphql/src/model/graph/node.rs +++ b/raphtory-graphql/src/model/graph/node.rs @@ -1,5 +1,5 @@ use crate::model::graph::{ - edges::GqlEdges, path_from_node::GqlPathFromNode, property::GqlProperties, + edges::GqlEdges, nodes::GqlNodes, path_from_node::GqlPathFromNode, property::GqlProperties, }; use dynamic_graphql::{ResolvedObject, ResolvedObjectFields}; use raphtory::{ @@ -172,18 +172,12 @@ impl Node { self.vv.in_degree() } - async fn in_component(&self) -> Vec { - in_component(self.vv.clone()) - .nodes() - .map(|n| n.cloned().into()) - .collect() + async fn in_component(&self) -> GqlNodes { + GqlNodes::new(in_component(self.vv.clone()).nodes()) } - async fn out_component(&self) -> Vec { - out_component(self.vv.clone()) - .nodes() - .map(|n| n.cloned().into()) - .collect() + async fn out_component(&self) -> GqlNodes { + GqlNodes::new(out_component(self.vv.clone()).nodes()) } async fn edges(&self) -> GqlEdges { diff --git a/raphtory/src/db/api/state/lazy_node_state.rs b/raphtory/src/db/api/state/lazy_node_state.rs index bb1e4da003..b6e83563f9 100644 --- a/raphtory/src/db/api/state/lazy_node_state.rs +++ b/raphtory/src/db/api/state/lazy_node_state.rs @@ -64,11 +64,15 @@ impl<'graph, Op: NodeOpFilter<'graph>, G: GraphViewOps<'graph>, GH: GraphViewOps impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph>> IntoIterator for LazyNodeState<'graph, Op, G, GH> { - type Item = Op::Output; + type Item = (NodeView, Op::Output); type IntoIter = BoxedLIter<'graph, Self::Item>; fn into_iter(self) -> Self::IntoIter { - self.into_values().into_dyn_boxed() + self.nodes + .clone() + .into_iter() + .zip(self.into_values()) + .into_dyn_boxed() } } @@ -182,6 +186,10 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra .map(move |node| (node, self.op.apply(&storage, node.node))) } + fn nodes(&self) -> Nodes<'graph, Self::BaseGraph, Self::Graph> { + self.nodes.clone() + } + fn par_iter<'a>( &'a self, ) -> impl ParallelIterator< diff --git a/raphtory/src/db/api/state/node_state.rs b/raphtory/src/db/api/state/node_state.rs index c6a1084b4d..c94dfb2f12 100644 --- a/raphtory/src/db/api/state/node_state.rs +++ b/raphtory/src/db/api/state/node_state.rs @@ -1,8 +1,11 @@ use crate::{ core::entities::{nodes::node_ref::AsNodeRef, VID}, db::{ - api::{state::node_state_ops::NodeStateOps, view::IntoDynBoxed}, - graph::node::NodeView, + api::{ + state::node_state_ops::NodeStateOps, + view::{internal::NodeList, DynamicGraph, IntoDynBoxed, IntoDynamic}, + }, + graph::{node::NodeView, nodes::Nodes}, }, prelude::GraphViewOps, }; @@ -15,6 +18,23 @@ pub struct Index { index: Arc>, } +impl Index { + pub fn for_graph<'graph>(graph: impl GraphViewOps<'graph>) -> Option { + if graph.nodes_filtered() { + if graph.node_list_trusted() { + match graph.node_list() { + NodeList::All { .. } => None, + NodeList::List { nodes } => Some(nodes), + } + } else { + Some(Self::new(graph.nodes().iter().map(|node| node.node))) + } + } else { + None + } + } +} + impl + From + Send + Sync> Index { pub fn new(keys: impl IntoIterator) -> Self { Self { @@ -27,7 +47,6 @@ impl + From + Send + Sync> Index { self.index.iter().copied() } - #[inline] pub fn into_par_iter(self) -> impl IndexedParallelIterator { (0..self.len()) .into_par_iter() @@ -73,6 +92,60 @@ pub struct NodeState<'graph, V, G, GH = G> { _marker: PhantomData<&'graph ()>, } +impl<'graph, V, G: IntoDynamic, GH: IntoDynamic> NodeState<'graph, V, G, GH> { + pub fn into_dyn(self) -> NodeState<'graph, V, DynamicGraph> { + NodeState::new( + self.base_graph.into_dynamic(), + self.graph.into_dynamic(), + self.values, + self.keys, + ) + } +} + +impl<'graph, V, G: GraphViewOps<'graph>> NodeState<'graph, V, G> { + /// Construct a node state from an eval result + /// + /// # Arguments + /// - graph: the graph view + /// - values: the unfiltered values (i.e., `values.len() == graph.unfiltered_num_nodes()`). + /// This method handles the filtering. + pub fn new_from_eval(graph: G, values: Vec) -> Self + where + V: Clone, + { + let index = Index::for_graph(graph.clone()); + let values = match &index { + None => values, + Some(index) => index + .iter() + .map(|vid| values[vid.index()].clone()) + .collect(), + }; + Self::new(graph.clone(), graph, values, index) + } + + /// Construct a node state from an eval result, mapping values + /// + /// # Arguments + /// - graph: the graph view + /// - values: the unfiltered values (i.e., `values.len() == graph.unfiltered_num_nodes()`). + /// This method handles the filtering. + /// - map: Closure mapping input to output values + pub fn new_from_eval_mapped(graph: G, values: Vec, map: impl Fn(R) -> V) -> Self { + let index = Index::for_graph(graph.clone()); + let values = match &index { + None => values.into_iter().map(map).collect(), + Some(index) => values + .into_iter() + .enumerate() + .filter_map(|(i, v)| index.contains(&VID(i)).then(|| map(v))) + .collect(), + }; + Self::new(graph.clone(), graph, values, index) + } +} + impl<'graph, V, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph>> NodeState<'graph, V, G, GH> { pub fn new(base_graph: G, graph: GH, values: Vec, keys: Option>) -> Self { Self { @@ -89,14 +162,22 @@ impl<'graph, V, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph>> NodeState<'gr } } -impl<'graph, V: Send + Sync + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph>> - IntoIterator for NodeState<'graph, V, G, GH> +impl< + 'graph, + V: Send + Sync + Clone + 'graph, + G: GraphViewOps<'graph>, + GH: GraphViewOps<'graph>, + > IntoIterator for NodeState<'graph, V, G, GH> { - type Item = V; - type IntoIter = std::vec::IntoIter; + type Item = (NodeView, V); + type IntoIter = Box + 'graph>; fn into_iter(self) -> Self::IntoIter { - self.values.into_iter() + self.nodes() + .clone() + .into_iter() + .zip(self.into_values()) + .into_dyn_boxed() } } @@ -181,6 +262,15 @@ impl< } } + fn nodes(&self) -> Nodes<'graph, Self::BaseGraph, Self::Graph> { + Nodes::new_filtered( + self.base_graph.clone(), + self.graph.clone(), + self.keys.clone(), + None, + ) + } + fn par_iter<'a>( &'a self, ) -> impl ParallelIterator< diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index a6a2d910db..ea6efc4180 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -5,7 +5,7 @@ use crate::{ state::{group_by::NodeGroups, node_state::NodeState, node_state_ord_ops, Index}, view::internal::CoreGraphOps, }, - graph::node::NodeView, + graph::{node::NodeView, nodes::Nodes}, }, prelude::{GraphViewOps, NodeViewOps}, }; @@ -16,7 +16,9 @@ use rayon::{ }; use std::{borrow::Borrow, hash::Hash, iter::Sum}; -pub trait NodeStateOps<'graph>: IntoIterator { +pub trait NodeStateOps<'graph>: + IntoIterator, Self::OwnedValue)> + 'graph +{ type Graph: GraphViewOps<'graph>; type BaseGraph: GraphViewOps<'graph>; type Value<'a>: Send + Sync + Borrow @@ -52,14 +54,7 @@ pub trait NodeStateOps<'graph>: IntoIterator { where 'graph: 'a; - fn nodes<'a>( - &'a self, - ) -> impl Iterator> + 'a - where - 'graph: 'a, - { - self.iter().map(|(n, _)| n) - } + fn nodes(&self) -> Nodes<'graph, Self::BaseGraph, Self::Graph>; fn par_iter<'a>( &'a self, diff --git a/raphtory/src/db/graph/graph.rs b/raphtory/src/db/graph/graph.rs index 7dca250363..923fa3e834 100644 --- a/raphtory/src/db/graph/graph.rs +++ b/raphtory/src/db/graph/graph.rs @@ -2619,7 +2619,7 @@ mod db_tests { } g.nodes() .name() - .into_iter() + .into_values() .map(|name| g.node(name)) .all(|v| v.is_some()) } @@ -2633,7 +2633,7 @@ mod db_tests { assert!(g .nodes() .name() - .into_iter() + .into_values() .map(|name| g.node(name)) .all(|v| v.is_some())) } @@ -2913,7 +2913,7 @@ mod db_tests { g.nodes() .type_filter(&vec!["wallet"]) .name() - .into_iter() + .into_values() .collect_vec(), vec!["1", "4"] ); @@ -3084,7 +3084,7 @@ mod db_tests { g.nodes() .type_filter(&vec!["a"]) .name() - .into_iter() + .into_values() .collect_vec(), vec!["1", "4"] ); @@ -3092,7 +3092,7 @@ mod db_tests { g.nodes() .type_filter(&vec!["a", "c"]) .name() - .into_iter() + .into_values() .collect_vec(), vec!["1", "4", "5"] ); diff --git a/raphtory/src/db/graph/nodes.rs b/raphtory/src/db/graph/nodes.rs index 5483d0d511..6e1ad8d05f 100644 --- a/raphtory/src/db/graph/nodes.rs +++ b/raphtory/src/db/graph/nodes.rs @@ -43,6 +43,18 @@ impl<'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph> + Debug> Debug } } +impl<'graph, G: IntoDynamic, GH: IntoDynamic> Nodes<'graph, G, GH> { + pub fn into_dyn(self) -> Nodes<'graph, DynamicGraph> { + Nodes { + base_graph: self.base_graph.into_dynamic(), + graph: self.graph.into_dynamic(), + nodes: self.nodes, + node_types_filter: self.node_types_filter, + _marker: Default::default(), + } + } +} + impl<'graph, G, GH> From> for Nodes<'graph, DynamicGraph, DynamicGraph> where G: GraphViewOps<'graph> + IntoDynamic, From 0f46a75b16d8d44366e2ec50c997c0eb907e67c9 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Mon, 6 Jan 2025 15:25:55 +0100 Subject: [PATCH 09/29] make NodeState clone --- .../algorithms/components/in_components.rs | 2 +- .../algorithms/components/out_components.rs | 2 +- raphtory/src/db/api/state/lazy_node_state.rs | 9 ++++++--- raphtory/src/db/api/state/node_state.rs | 19 +++++++++++-------- raphtory/src/db/api/state/node_state_ops.rs | 6 +++--- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/raphtory/src/algorithms/components/in_components.rs b/raphtory/src/algorithms/components/in_components.rs index bc4225599a..d26e2c493d 100644 --- a/raphtory/src/algorithms/components/in_components.rs +++ b/raphtory/src/algorithms/components/in_components.rs @@ -134,7 +134,7 @@ pub fn in_component<'graph, G: GraphViewOps<'graph>>( NodeState::new( node.graph.clone(), node.graph.clone(), - distances, + distances.into(), Some(Index::new(nodes)), ) } diff --git a/raphtory/src/algorithms/components/out_components.rs b/raphtory/src/algorithms/components/out_components.rs index e761b893e0..519d46a7c2 100644 --- a/raphtory/src/algorithms/components/out_components.rs +++ b/raphtory/src/algorithms/components/out_components.rs @@ -137,7 +137,7 @@ pub fn out_component<'graph, G: GraphViewOps<'graph>>( NodeState::new( node.graph.clone(), node.graph.clone(), - distances, + distances.into(), Some(Index::new(nodes)), ) } diff --git a/raphtory/src/db/api/state/lazy_node_state.rs b/raphtory/src/db/api/state/lazy_node_state.rs index b6e83563f9..71d5b57416 100644 --- a/raphtory/src/db/api/state/lazy_node_state.rs +++ b/raphtory/src/db/api/state/lazy_node_state.rs @@ -16,7 +16,10 @@ use crate::{ prelude::*, }; use rayon::prelude::*; -use std::fmt::{Debug, Formatter}; +use std::{ + fmt::{Debug, Formatter}, + sync::Arc, +}; #[derive(Clone)] pub struct LazyNodeState<'graph, Op, G, GH = G> { @@ -100,7 +103,7 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra NodeState::new( self.nodes.base_graph.clone(), self.nodes.graph.clone(), - values, + values.into(), Some(Index::new(keys)), ) } else { @@ -108,7 +111,7 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra NodeState::new( self.nodes.base_graph.clone(), self.nodes.graph.clone(), - values, + values.into(), None, ) } diff --git a/raphtory/src/db/api/state/node_state.rs b/raphtory/src/db/api/state/node_state.rs index c94dfb2f12..e04eef867e 100644 --- a/raphtory/src/db/api/state/node_state.rs +++ b/raphtory/src/db/api/state/node_state.rs @@ -84,10 +84,11 @@ impl + From + Send + Sync> Index { } } +#[derive(Clone)] pub struct NodeState<'graph, V, G, GH = G> { base_graph: G, graph: GH, - values: Vec, + values: Arc<[V]>, keys: Option>, _marker: PhantomData<&'graph ()>, } @@ -122,7 +123,7 @@ impl<'graph, V, G: GraphViewOps<'graph>> NodeState<'graph, V, G> { .map(|vid| values[vid.index()].clone()) .collect(), }; - Self::new(graph.clone(), graph, values, index) + Self::new(graph.clone(), graph, values.into(), index) } /// Construct a node state from an eval result, mapping values @@ -147,7 +148,7 @@ impl<'graph, V, G: GraphViewOps<'graph>> NodeState<'graph, V, G> { } impl<'graph, V, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph>> NodeState<'graph, V, G, GH> { - pub fn new(base_graph: G, graph: GH, values: Vec, keys: Option>) -> Self { + pub fn new(base_graph: G, graph: GH, values: Arc<[V]>, keys: Option>) -> Self { Self { base_graph, graph, @@ -157,7 +158,7 @@ impl<'graph, V, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph>> NodeState<'gr } } - pub fn into_inner(self) -> (Vec, Option>) { + pub fn into_inner(self) -> (Arc<[V]>, Option>) { (self.values, self.keys) } } @@ -219,11 +220,13 @@ impl< } fn into_values(self) -> impl Iterator + 'graph { - self.values.into_iter() + (0..self.values.len()).map(move |i| self.values[i].clone()) } fn into_par_values(self) -> impl ParallelIterator + 'graph { - self.values.into_par_iter() + (0..self.values.len()) + .into_par_iter() + .map(move |i| self.values[i].clone()) } fn iter<'a>( @@ -350,7 +353,7 @@ mod test { let float_state = NodeState { base_graph: g.clone(), graph: g.clone(), - values: vec![0.0f64], + values: [0.0f64].into(), keys: None, _marker: Default::default(), }; @@ -358,7 +361,7 @@ mod test { let int_state = NodeState { base_graph: g.clone(), graph: g.clone(), - values: vec![1i64], + values: [1i64].into(), keys: None, _marker: Default::default(), }; diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index ea6efc4180..f84e5972cf 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -107,7 +107,7 @@ pub trait NodeStateOps<'graph>: NodeState::new( self.base_graph().clone(), self.graph().clone(), - values, + values.into(), Some(Index::new(keys)), ) } @@ -131,7 +131,7 @@ pub trait NodeStateOps<'graph>: NodeState::new( self.base_graph().clone(), self.graph().clone(), - values, + values.into(), Some(Index::new(keys)), ) } @@ -168,7 +168,7 @@ pub trait NodeStateOps<'graph>: NodeState::new( self.base_graph().clone(), self.graph().clone(), - values, + values.into(), Some(Index::new(keys)), ) } From d7412b3af7a0f85543cea7084e51aec3da3c8945 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Mon, 6 Jan 2025 18:24:30 +0100 Subject: [PATCH 10/29] rework IntoPyObject for NodeView --- raphtory/src/db/api/view/internal/mod.rs | 33 +++++++++ raphtory/src/disk_graph/graph_impl/interop.rs | 2 +- raphtory/src/python/graph/node.rs | 67 +++++++++---------- 3 files changed, 64 insertions(+), 38 deletions(-) diff --git a/raphtory/src/db/api/view/internal/mod.rs b/raphtory/src/db/api/view/internal/mod.rs index 1ad02c59ba..670871ed0d 100644 --- a/raphtory/src/db/api/view/internal/mod.rs +++ b/raphtory/src/db/api/view/internal/mod.rs @@ -22,6 +22,7 @@ use std::{ sync::Arc, }; +use crate::{db::graph::views::deletion_graph::PersistentGraph, prelude::Graph}; pub use core_deletion_ops::*; pub use core_ops::*; pub use edge_filter_ops::*; @@ -100,6 +101,38 @@ impl From> for DynamicGraph { /// Trait for marking a graph view as immutable to avoid conflicts when implementing conversions for mutable and immutable views pub trait Immutable {} +pub enum DynOrMutableGraph { + Dyn(DynamicGraph), + Mutable(MaterializedGraph), +} +pub trait IntoDynamicOrMutable: IntoDynamic { + fn into_dynamic_or_mutable(self) -> DynOrMutableGraph; +} + +impl IntoDynamicOrMutable for G { + fn into_dynamic_or_mutable(self) -> DynOrMutableGraph { + DynOrMutableGraph::Dyn(self.into_dynamic()) + } +} + +impl IntoDynamicOrMutable for MaterializedGraph { + fn into_dynamic_or_mutable(self) -> DynOrMutableGraph { + DynOrMutableGraph::Mutable(self) + } +} + +impl IntoDynamicOrMutable for Graph { + fn into_dynamic_or_mutable(self) -> DynOrMutableGraph { + DynOrMutableGraph::Mutable(self.into()) + } +} + +impl IntoDynamicOrMutable for PersistentGraph { + fn into_dynamic_or_mutable(self) -> DynOrMutableGraph { + DynOrMutableGraph::Mutable(self.into()) + } +} + #[derive(Clone)] pub struct DynamicGraph(pub(crate) Arc); diff --git a/raphtory/src/disk_graph/graph_impl/interop.rs b/raphtory/src/disk_graph/graph_impl/interop.rs index f0face3db9..a790617d39 100644 --- a/raphtory/src/disk_graph/graph_impl/interop.rs +++ b/raphtory/src/disk_graph/graph_impl/interop.rs @@ -30,7 +30,7 @@ impl GraphLike for Graph { } fn node_names(&self) -> impl Iterator { - self.nodes().name().into_iter() + self.nodes().name().into_values() } fn node_type_ids(&self) -> Option> { diff --git a/raphtory/src/python/graph/node.rs b/raphtory/src/python/graph/node.rs index 5b3f2d4ea3..37b1147a4e 100644 --- a/raphtory/src/python/graph/node.rs +++ b/raphtory/src/python/graph/node.rs @@ -12,7 +12,10 @@ use crate::{ properties::Properties, state::{ops, LazyNodeState, NodeStateOps}, view::{ - internal::{CoreGraphOps, DynamicGraph, Immutable, IntoDynamic, MaterializedGraph}, + internal::{ + CoreGraphOps, DynOrMutableGraph, DynamicGraph, Immutable, IntoDynamic, + IntoDynamicOrMutable, MaterializedGraph, + }, *, }, }, @@ -45,7 +48,7 @@ use pyo3::{ pybacked::PyBackedStr, pyclass, pymethods, types::PyDict, - PyObject, PyResult, Python, + IntoPyObjectExt, PyObject, PyResult, Python, }; use python::{ types::repr::{iterator_repr, Repr}, @@ -320,16 +323,36 @@ impl Repr for PyMutableNode { } impl< 'py, - G: StaticGraphViewOps + IntoDynamic, - GH: StaticGraphViewOps + IntoDynamic + Immutable, + G: StaticGraphViewOps + IntoDynamicOrMutable, + GH: StaticGraphViewOps + IntoDynamicOrMutable, > IntoPyObject<'py> for NodeView { - type Target = PyNode; + type Target = PyAny; type Output = Bound<'py, Self::Target>; - type Error = >::Error; + type Error = PyErr; fn into_pyobject(self, py: Python<'py>) -> Result { - PyNode::from(self).into_pyobject(py) + let graph = self.graph.into_dynamic_or_mutable(); + match graph { + DynOrMutableGraph::Dyn(graph) => { + let base_graph = self.base_graph.into_dynamic(); + PyNode::from(NodeView::new_one_hop_filtered(base_graph, graph, self.node)) + .into_bound_py_any(py) + } + DynOrMutableGraph::Mutable(graph) => { + let base_graph = self.base_graph.into_dynamic_or_mutable(); + match base_graph { + DynOrMutableGraph::Dyn(_) => { + unreachable!() + } + DynOrMutableGraph::Mutable(base_graph) => PyMutableNode::new_bound( + NodeView::new_one_hop_filtered(base_graph, graph, self.node), + py, + )? + .into_bound_py_any(py), + } + } + } } } @@ -341,36 +364,6 @@ impl> From> for PyMutableNode { } } -impl<'py> IntoPyObject<'py> for NodeView { - type Target = PyMutableNode; - type Output = Bound<'py, Self::Target>; - type Error = PyErr; - - fn into_pyobject(self, py: Python<'py>) -> Result { - PyMutableNode::new_bound(self, py) - } -} - -impl<'py> IntoPyObject<'py> for NodeView { - type Target = PyMutableNode; - type Output = Bound<'py, Self::Target>; - type Error = PyErr; - - fn into_pyobject(self, py: Python<'py>) -> Result { - PyMutableNode::new_bound(self, py) - } -} - -impl<'py> IntoPyObject<'py> for NodeView { - type Target = PyMutableNode; - type Output = Bound<'py, Self::Target>; - type Error = PyErr; - - fn into_pyobject(self, py: Python<'py>) -> Result { - PyMutableNode::new_bound(self, py) - } -} - #[pymethods] impl PyMutableNode { /// Set the type on the node. This only works if the type has not been previously set, otherwise will From 873eb301e532a123324b986bbf522bbe9cfe51dd Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 9 Jan 2025 10:56:48 +0100 Subject: [PATCH 11/29] add python group by implementation --- raphtory/src/db/api/state/group_by.rs | 23 ++- raphtory/src/db/api/state/mod.rs | 1 + .../src/python/graph/node_state/group_by.rs | 151 ++++++++++++++++++ raphtory/src/python/graph/node_state/mod.rs | 4 + .../graph/{ => node_state}/node_state.rs | 47 ++++-- 5 files changed, 216 insertions(+), 10 deletions(-) create mode 100644 raphtory/src/python/graph/node_state/group_by.rs create mode 100644 raphtory/src/python/graph/node_state/mod.rs rename raphtory/src/python/graph/{ => node_state}/node_state.rs (91%) diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index 8c108d842a..693abaddb6 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -5,7 +5,7 @@ use crate::{ }, prelude::{GraphViewOps, NodeStateOps}, }; -use raphtory_api::core::entities::VID; +use raphtory_api::{core::entities::VID, iter::BoxedLIter}; use rayon::prelude::*; use std::{collections::HashMap, hash::Hash, sync::Arc}; @@ -42,6 +42,26 @@ impl<'graph, V: Hash + Eq, G: GraphViewOps<'graph>> NodeGroups { }) } + pub fn into_iter_groups(self) -> impl Iterator)> + where + V: Clone, + { + (0..self.len()).map(move |i| { + let (v, nodes) = self.group(i).unwrap(); + (v.clone(), nodes) + }) + } + + pub fn into_iter_subgraphs(self) -> impl Iterator)> + where + V: Clone, + { + (0..self.len()).map(move |i| { + let (v, graph) = self.group_subgraph(i).unwrap(); + (v.clone(), graph) + }) + } + pub fn iter_subgraphs(&self) -> impl Iterator)> { self.groups.iter().map(|(v, nodes)| { ( @@ -88,6 +108,7 @@ impl<'graph, V: Hash + Eq, G: GraphViewOps<'graph>> NodeGroups { self.groups.is_empty() } } + pub trait NodeStateGroupBy<'graph>: NodeStateOps<'graph> { fn groups(&self) -> NodeGroups; } diff --git a/raphtory/src/db/api/state/mod.rs b/raphtory/src/db/api/state/mod.rs index 15230f0493..4e9fe1e083 100644 --- a/raphtory/src/db/api/state/mod.rs +++ b/raphtory/src/db/api/state/mod.rs @@ -5,6 +5,7 @@ mod node_state_ops; mod node_state_ord_ops; pub(crate) mod ops; +pub use group_by::{NodeGroups, NodeStateGroupBy}; pub use lazy_node_state::LazyNodeState; pub(crate) use node_state::Index; pub use node_state::NodeState; diff --git a/raphtory/src/python/graph/node_state/group_by.rs b/raphtory/src/python/graph/node_state/group_by.rs new file mode 100644 index 0000000000..b667ab335e --- /dev/null +++ b/raphtory/src/python/graph/node_state/group_by.rs @@ -0,0 +1,151 @@ +use crate::{ + db::{ + api::{ + state::NodeGroups, + view::{internal::IntoDynamicOrMutable, DynamicGraph, IntoDynamic, StaticGraphViewOps}, + }, + graph::{nodes::Nodes, views::node_subgraph::NodeSubgraph}, + }, + python::utils::PyGenericIterator, +}; +use pyo3::{exceptions::PyIndexError, prelude::*, IntoPyObjectExt}; +use std::{hash::Hash, sync::Arc}; + +trait PyNodeGroupOps: Send + Sync + 'static { + fn iter(&self) -> PyGenericIterator; + + fn iter_subgraphs(&self) -> PyGenericIterator; + + fn group<'py>( + &self, + index: usize, + py: Python<'py>, + ) -> PyResult, Bound<'py, PyAny>)>>; + + fn group_subgraph<'py>( + &self, + index: usize, + py: Python<'py>, + ) -> PyResult, DynamicGraph)>>; + + fn len(&self) -> usize; + + fn is_empty(&self) -> bool; +} + +impl< + V: for<'py> IntoPyObject<'py> + Hash + Eq + Clone + Send + Sync + 'static, + G: StaticGraphViewOps + IntoDynamicOrMutable, + > PyNodeGroupOps for NodeGroups +{ + fn iter(&self) -> PyGenericIterator { + self.clone().into_iter_groups().into() + } + + fn iter_subgraphs(&self) -> PyGenericIterator { + self.clone().into_iter_subgraphs().into() + } + + fn group<'py>( + &self, + index: usize, + py: Python<'py>, + ) -> PyResult, Bound<'py, PyAny>)>> { + let res = match self.group(index) { + Some((v, nodes)) => Some(( + v.clone().into_bound_py_any(py)?, + nodes.into_bound_py_any(py)?, + )), + None => None, + }; + Ok(res) + } + + fn group_subgraph<'py>( + &self, + index: usize, + py: Python<'py>, + ) -> PyResult, DynamicGraph)>> { + let res = match self.group_subgraph(index) { + None => None, + Some((v, graph)) => Some((v.clone().into_bound_py_any(py)?, graph.into_dynamic())), + }; + Ok(res) + } + + fn len(&self) -> usize { + self.len() + } + + fn is_empty(&self) -> bool { + self.is_empty() + } +} + +#[pyclass(name = "NodeGroups", module = "node_state", frozen)] +pub struct PyNodeGroups { + inner: Box, +} + +#[pymethods] +impl PyNodeGroups { + fn __iter__(&self) -> PyGenericIterator { + self.inner.iter() + } + + fn __len__(&self) -> usize { + self.inner.len() + } + + fn __bool__(&self) -> bool { + !self.inner.is_empty() + } + + fn __getitem__<'py>( + &self, + index: usize, + py: Python<'py>, + ) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyAny>)> { + self.inner + .group(index, py)? + .ok_or_else(|| PyIndexError::new_err("group not found")) + } + + fn group<'py>( + &self, + index: usize, + py: Python<'py>, + ) -> PyResult, Bound<'py, PyAny>)>> { + self.inner.group(index, py) + } + + fn group_subgraph<'py>( + &self, + index: usize, + py: Python<'py>, + ) -> PyResult, DynamicGraph)>> { + self.inner.group_subgraph(index, py) + } + + fn iter_subgraphs(&self) -> PyGenericIterator { + self.inner.iter_subgraphs() + } +} + +impl< + 'py, + V: for<'py2> IntoPyObject<'py2> + Hash + Eq + Clone + Send + Sync + 'static, + G: StaticGraphViewOps + IntoDynamicOrMutable, + > IntoPyObject<'py> for NodeGroups +{ + type Target = PyNodeGroups; + type Output = Bound<'py, Self::Target>; + type Error = >::Error; + + fn into_pyobject(self, py: Python<'py>) -> Result { + PyNodeGroups { + inner: Box::new(self), + } + .into_pyobject(py) + } +} diff --git a/raphtory/src/python/graph/node_state/mod.rs b/raphtory/src/python/graph/node_state/mod.rs new file mode 100644 index 0000000000..7842e1b8ed --- /dev/null +++ b/raphtory/src/python/graph/node_state/mod.rs @@ -0,0 +1,4 @@ +mod group_by; +mod node_state; + +pub use node_state::*; diff --git a/raphtory/src/python/graph/node_state.rs b/raphtory/src/python/graph/node_state/node_state.rs similarity index 91% rename from raphtory/src/python/graph/node_state.rs rename to raphtory/src/python/graph/node_state/node_state.rs index e38bc62305..bf1cc1438c 100644 --- a/raphtory/src/python/graph/node_state.rs +++ b/raphtory/src/python/graph/node_state/node_state.rs @@ -1,11 +1,12 @@ -use pyo3::prelude::*; - use crate::{ add_classes, core::entities::nodes::node_ref::{AsNodeRef, NodeRef}, db::{ api::{ - state::{ops, LazyNodeState, NodeOp, NodeState, NodeStateOps, OrderedNodeStateOps}, + state::{ + ops, LazyNodeState, NodeGroups, NodeOp, NodeState, NodeStateGroupBy, NodeStateOps, + OrderedNodeStateOps, + }, view::{ internal::Static, DynamicGraph, GraphViewOps, IntoDynHop, IntoDynamic, StaticGraphViewOps, @@ -16,13 +17,15 @@ use crate::{ prelude::*, py_borrowing_iter, python::{ + graph::node_state::group_by::PyNodeGroups, types::{repr::Repr, wrappers::iterators::PyBorrowingIterator}, - utils::PyNodeRef, + utils::{PyGenericIterator, PyNodeRef}, }, }; use chrono::{DateTime, Utc}; use pyo3::{ exceptions::{PyKeyError, PyTypeError}, + prelude::*, types::PyNotImplemented, }; use raphtory_api::core::{entities::GID, storage::arc_str::ArcStr}; @@ -46,10 +49,8 @@ macro_rules! impl_node_state_ops { /// /// Returns: /// Iterator[Node] - fn nodes(&self) -> PyBorrowingIterator { - py_borrowing_iter!(self.inner.clone(), $inner_t, |inner| { - inner.nodes().map(|n| n.cloned()) - }) + fn nodes(&self) -> PyGenericIterator { + self.inner.nodes().into_iter().into() } fn __iter__(&self) -> PyBorrowingIterator { @@ -108,6 +109,21 @@ macro_rules! impl_node_state_ops { }; } +macro_rules! impl_node_state_group_by_ops { + ($name:ident, $value:ty) => { + #[pymethods] + impl $name { + /// Group by value + /// + /// Returns: + /// NodeGroups: The grouped nodes + fn groups(&self) -> NodeGroups<$value, DynamicGraph> { + self.inner.groups() + } + } + }; +} + macro_rules! impl_node_state_ord_ops { ($name:ident, $value:ty, $to_owned:expr, $computed:literal, $py_value:literal) => { #[pymethods] @@ -420,8 +436,10 @@ impl_lazy_node_state_num!( "int" ); impl_one_hop!(DegreeView, "DegreeView"); +impl_node_state_group_by_ops!(DegreeView, usize); impl_node_state_num!(NodeStateUsize, "NodeStateUsize", "int"); +impl_node_state_group_by_ops!(NodeStateUsize, usize); impl_node_state_num!(NodeStateU64, "NodeStateU64", "int"); @@ -434,20 +452,25 @@ impl_lazy_node_state_ord!( "Optional[int]" ); impl_one_hop!(EarliestTimeView, "EarliestTimeView"); +impl_node_state_group_by_ops!(EarliestTimeView, Option); impl_lazy_node_state_ord!( LatestTimeView>, "NodeStateOptionI64", "Optional[int]" ); impl_one_hop!(LatestTimeView, "LatestTimeView"); +impl_node_state_group_by_ops!(LatestTimeView, Option); impl_node_state_ord!( NodeStateOptionI64>, "NodeStateOptionI64", "Optional[int]" ); +impl_node_state_group_by_ops!(NodeStateOptionI64, Option); impl_lazy_node_state_ord!(NameView, "NodeStateString", "str"); +impl_node_state_group_by_ops!(NameView, String); impl_node_state_ord!(NodeStateString, "NodeStateString", "str"); +impl_node_state_group_by_ops!(NodeStateString, String); type EarliestDateTime = ops::Map, Option>>; impl_lazy_node_state_ord!( @@ -459,6 +482,7 @@ impl_one_hop!( EarliestDateTimeView, "EarliestDateTimeView" ); +impl_node_state_group_by_ops!(EarliestDateTimeView, Option>); type LatestDateTime = ops::Map, Option>>; impl_lazy_node_state_ord!( @@ -467,11 +491,13 @@ impl_lazy_node_state_ord!( "Optional[Datetime]" ); impl_one_hop!(LatestDateTimeView, "LatestDateTimeView"); +impl_node_state_group_by_ops!(LatestDateTimeView, Option>); impl_node_state_ord!( NodeStateOptionDateTime>>, "NodeStateOptionDateTime", "Optional[Datetime]" ); +impl_node_state_group_by_ops!(NodeStateOptionDateTime, Option>); impl_lazy_node_state_ord!( HistoryView>, @@ -499,11 +525,13 @@ impl_lazy_node_state_ord!( "NodeStateOptionStr", "Optional[str]" ); +impl_node_state_group_by_ops!(NodeTypeView, Option); impl_node_state_ord!( NodeStateOptionStr>, "NodeStateOptionStr", "Optional[str]" ); +impl_node_state_group_by_ops!(NodeStateOptionStr, Option); impl_node_state_ord!( NodeStateListDateTime>>, @@ -533,7 +561,8 @@ pub fn base_node_state_module(py: Python<'_>) -> PyResult> { NodeStateOptionListDateTime, NodeTypeView, NodeStateOptionStr, - NodeStateListDateTime + NodeStateListDateTime, + PyNodeGroups ); Ok(m) } From 694dca7abb18f69139d6ec84efa606d7e3d2f62d Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 9 Jan 2025 10:57:30 +0100 Subject: [PATCH 12/29] tidy --- python/python/raphtory/__init__.pyi | 632 +++++++++--------- .../python/raphtory/node_state/__init__.pyi | 232 +++++-- python/python/raphtory/vectors/__init__.pyi | 4 +- 3 files changed, 478 insertions(+), 390 deletions(-) diff --git a/python/python/raphtory/__init__.pyi b/python/python/raphtory/__init__.pyi index 3fea19cd89..11e92ae419 100644 --- a/python/python/raphtory/__init__.pyi +++ b/python/python/raphtory/__init__.pyi @@ -41,6 +41,68 @@ class GraphView(object): def __ge__(self, value): """Return self>=value.""" + def to_pyvis( + self, + explode_edges=False, + edge_color="#000000", + shape=None, + node_image=None, + edge_weight=None, + edge_label=None, + colour_nodes_by_type=False, + notebook=False, + **kwargs + ): + """ + Draw a graph with PyVis. + Pyvis is a required dependency. If you intend to use this function make sure that you install Pyvis + with ``pip install pyvis`` + + Args: + graph (graph): A Raphtory graph. + explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. Defaults to False. + edge_color (str): A string defining the colour of the edges in the graph. Defaults to "#000000". + shape (str): An optional string defining what the node looks like. Defaults to "dot". + There are two types of nodes. One type has the label inside of it and the other type has the label underneath it. + The types with the label inside of it are: ellipse, circle, database, box, text. + The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon. + node_image (str, optional): An optional string defining the url of a custom node image. + edge_weight (str, optional): An optional string defining the name of the property where edge weight is set on your Raphtory graph. + If not provided, the edge weight is set to `1.0` for all edges. + edge_label (str): An optional string defining the name of the property where edge label is set on your Raphtory graph. By default, an empty string as the label is set. + notebook (bool): A boolean that is set to True if using jupyter notebook. Defaults to False + kwargs: Additional keyword arguments that are passed to the pyvis Network class. + + Returns: + A pyvis network + """ + + def to_networkx( + self, + explode_edges: bool = False, + include_node_properties: bool = True, + include_edge_properties: bool = True, + include_update_history: bool = True, + include_property_history: bool = True, + ): + """ + Returns a graph with NetworkX. + + Network X is a required dependency. + If you intend to use this function make sure that + you install Network X with ``pip install networkx`` + + Args: + explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False. + include_node_properties (bool): A boolean that is set to True if you want to include the node properties in the graph. By default this is set to True. + include_edge_properties (bool): A boolean that is set to True if you want to include the edge properties in the graph. By default this is set to True. + include_update_history (bool): A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True. + include_property_history (bool): A boolean that is set to True if you want to include the histories in the graph. By default this is set to True. + + Returns: + A Networkx MultiDiGraph. + """ + def vectorise( self, embedding: Callable[[list], list], @@ -487,85 +549,13 @@ class GraphView(object): GraphIndex - Returns a GraphIndex """ - def to_pyvis( - self, - explode_edges=False, - edge_color="#000000", - shape=None, - node_image=None, - edge_weight=None, - edge_label=None, - colour_nodes_by_type=False, - notebook=False, - **kwargs - ): - """ - Draw a graph with PyVis. - Pyvis is a required dependency. If you intend to use this function make sure that you install Pyvis - with ``pip install pyvis`` - - Args: - graph (graph): A Raphtory graph. - explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. Defaults to False. - edge_color (str): A string defining the colour of the edges in the graph. Defaults to "#000000". - shape (str): An optional string defining what the node looks like. Defaults to "dot". - There are two types of nodes. One type has the label inside of it and the other type has the label underneath it. - The types with the label inside of it are: ellipse, circle, database, box, text. - The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon. - node_image (str, optional): An optional string defining the url of a custom node image. - edge_weight (str, optional): An optional string defining the name of the property where edge weight is set on your Raphtory graph. - If not provided, the edge weight is set to `1.0` for all edges. - edge_label (str): An optional string defining the name of the property where edge label is set on your Raphtory graph. By default, an empty string as the label is set. - notebook (bool): A boolean that is set to True if using jupyter notebook. Defaults to False - kwargs: Additional keyword arguments that are passed to the pyvis Network class. - - Returns: - A pyvis network - """ - - def to_networkx( - self, - explode_edges: bool = False, - include_node_properties: bool = True, - include_edge_properties: bool = True, - include_update_history: bool = True, - include_property_history: bool = True, - ): - """ - Returns a graph with NetworkX. - - Network X is a required dependency. - If you intend to use this function make sure that - you install Network X with ``pip install networkx`` - - Args: - explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False. - include_node_properties (bool): A boolean that is set to True if you want to include the node properties in the graph. By default this is set to True. - include_edge_properties (bool): A boolean that is set to True if you want to include the edge properties in the graph. By default this is set to True. - include_update_history (bool): A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True. - include_property_history (bool): A boolean that is set to True if you want to include the histories in the graph. By default this is set to True. - - Returns: - A Networkx MultiDiGraph. - """ - - @property - def properties(self): - """ - Get all graph properties - - - Returns: - Properties: Properties paired with their names - """ - @property - def latest_date_time(self): + def end(self): """ - DateTime of latest activity in the graph + Gets the latest time that this GraphView is valid. Returns: - Optional[Datetime]: the datetime of the latest activity in the graph + Optional[int]: The latest time that this GraphView is valid or None if the GraphView is valid for all times. """ @property @@ -578,30 +568,30 @@ class GraphView(object): """ @property - def window_size(self): + def nodes(self): """ - Get the window size (difference between start and end) for this GraphView + Gets the nodes in the graph Returns: - Optional[int] + Nodes: the nodes in the graph """ @property - def unique_layers(self): + def edges(self): """ - Return all the layer ids in the graph + Gets all edges in the graph Returns: - list[str] + Edges: the edges in the graph """ @property - def earliest_time(self): + def unique_layers(self): """ - Timestamp of earliest activity in the graph + Return all the layer ids in the graph Returns: - Optional[int]: the timestamp of the earliest activity in the graph + list[str] """ @property @@ -623,21 +613,31 @@ class GraphView(object): """ @property - def edges(self): + def end_date_time(self): """ - Gets all edges in the graph + Gets the latest datetime that this GraphView is valid Returns: - Edges: the edges in the graph + Optional[Datetime]: The latest datetime that this GraphView is valid or None if the GraphView is valid for all times. """ @property - def nodes(self): + def window_size(self): """ - Gets the nodes in the graph + Get the window size (difference between start and end) for this GraphView Returns: - Nodes: the nodes in the graph + Optional[int] + """ + + @property + def properties(self): + """ + Get all graph properties + + + Returns: + Properties: Properties paired with their names """ @property @@ -650,21 +650,21 @@ class GraphView(object): """ @property - def end(self): + def latest_date_time(self): """ - Gets the latest time that this GraphView is valid. + DateTime of latest activity in the graph Returns: - Optional[int]: The latest time that this GraphView is valid or None if the GraphView is valid for all times. + Optional[Datetime]: the datetime of the latest activity in the graph """ @property - def end_date_time(self): + def earliest_time(self): """ - Gets the latest datetime that this GraphView is valid + Timestamp of earliest activity in the graph Returns: - Optional[Datetime]: The latest datetime that this GraphView is valid or None if the GraphView is valid for all times. + Optional[int]: the timestamp of the earliest activity in the graph """ class Graph(GraphView): @@ -2382,44 +2382,33 @@ class Node(object): """ @property - def earliest_date_time(self): + def window_size(self): """ - Returns the earliest datetime that the node exists. + Get the window size (difference between start and end) for this Node Returns: - Datetime: The earliest datetime that the node exists as a Datetime. + Optional[int] """ @property - def name(self): + def properties(self): """ - Returns the name of the node. + The properties of the node Returns: - str: The id of the node as a string. + Properties: A list of properties. """ @property - def end_date_time(self): - """ - Gets the latest datetime that this Node is valid - - Returns: - Optional[Datetime]: The latest datetime that this Node is valid or None if the Node is valid for all times. + def latest_date_time(self): """ + Returns the latest datetime that the node exists. - @property - def node_type(self): - """Returns the type of node""" - - @property - def id(self): - """ - Returns the id of the node. - This is a unique identifier for the node. + Arguments: + None Returns: - (str|int): The id of the node. + Datetime: The latest datetime that the node exists as a Datetime. """ @property @@ -2433,53 +2422,44 @@ class Node(object): """ @property - def latest_date_time(self): + def name(self): """ - Returns the latest datetime that the node exists. - - Arguments: - None + Returns the name of the node. Returns: - Datetime: The latest datetime that the node exists as a Datetime. + str: The id of the node as a string. """ @property - def start_date_time(self): - """ - Gets the earliest datetime that this Node is valid - - Returns: - Optional[Datetime]: The earliest datetime that this Node is valid or None if the Node is valid for all times. - """ + def node_type(self): + """Returns the type of node""" @property - def neighbours(self): + def out_neighbours(self): """ - Get the neighbours of this node. + Get the neighbours of this node that point out of this node. Returns: - An iterator over the neighbours of this node. + An iterator over the neighbours of this node that point out of this node. """ @property - def in_neighbours(self): + def earliest_date_time(self): """ - Get the neighbours of this node that point into this node. + Returns the earliest datetime that the node exists. Returns: - - An iterator over the neighbours of this node that point into this node. + Datetime: The earliest datetime that the node exists as a Datetime. """ @property - def earliest_time(self): + def latest_time(self): """ - Returns the earliest time that the node exists. + Returns the latest time that the node exists. Returns: - int: The earliest time that the node exists as an integer. + int: The latest time that the node exists as an integer. """ @property @@ -2493,22 +2473,31 @@ class Node(object): """ @property - def out_neighbours(self): + def earliest_time(self): """ - Get the neighbours of this node that point out of this node. + Returns the earliest time that the node exists. Returns: + int: The earliest time that the node exists as an integer. + """ - An iterator over the neighbours of this node that point out of this node. + @property + def start_date_time(self): + """ + Gets the earliest datetime that this Node is valid + + Returns: + Optional[Datetime]: The earliest datetime that this Node is valid or None if the Node is valid for all times. """ @property - def latest_time(self): + def in_edges(self): """ - Returns the latest time that the node exists. + Get the edges that point into this node. Returns: - int: The latest time that the node exists as an integer. + + An iterator over the edges that point into this node. """ @property @@ -2521,40 +2510,51 @@ class Node(object): """ @property - def end(self): + def in_neighbours(self): """ - Gets the latest time that this Node is valid. + Get the neighbours of this node that point into this node. Returns: - Optional[int]: The latest time that this Node is valid or None if the Node is valid for all times. + + An iterator over the neighbours of this node that point into this node. """ @property - def window_size(self): + def id(self): """ - Get the window size (difference between start and end) for this Node + Returns the id of the node. + This is a unique identifier for the node. Returns: - Optional[int] + (str|int): The id of the node. """ @property - def in_edges(self): + def end(self): """ - Get the edges that point into this node. + Gets the latest time that this Node is valid. Returns: + Optional[int]: The latest time that this Node is valid or None if the Node is valid for all times. + """ - An iterator over the edges that point into this node. + @property + def end_date_time(self): + """ + Gets the latest datetime that this Node is valid + + Returns: + Optional[Datetime]: The latest datetime that this Node is valid or None if the Node is valid for all times. """ @property - def properties(self): + def neighbours(self): """ - The properties of the node + Get the neighbours of this node. Returns: - Properties: A list of properties. + + An iterator over the neighbours of this node. """ class Nodes(object): @@ -2933,39 +2933,51 @@ class Nodes(object): """ @property - def node_type(self): - """Returns the type of node""" + def edges(self): + """ + Get the edges that are incident to this node. - @property - def earliest_time(self): - """Returns an iterator over the nodes earliest time""" + Returns: + + An iterator over the edges that are incident to this node. + """ @property - def earliest_date_time(self): + def out_edges(self): """ - Returns the earliest time of the nodes. + Get the edges that point out of this node. Returns: - Earliest time of the nodes. + + An iterator over the edges that point out of this node. """ @property - def end(self): + def name(self): + """Returns an iterator over the nodes name""" + + @property + def out_neighbours(self): """ - Gets the latest time that this Nodes is valid. + Get the neighbours of this node that point out of this node. Returns: - Optional[int]: The latest time that this Nodes is valid or None if the Nodes is valid for all times. + + An iterator over the neighbours of this node that point out of this node. """ @property - def out_edges(self): + def id(self): + """Returns an iterator over the nodes ids""" + + @property + def in_edges(self): """ - Get the edges that point out of this node. + Get the edges that point into this node. Returns: - An iterator over the edges that point out of this node. + An iterator over the edges that point into this node. """ @property @@ -2978,49 +2990,48 @@ class Nodes(object): """ @property - def start(self): + def latest_date_time(self): """ - Gets the start time for rolling and expanding windows for this Nodes + Returns the latest date time of the nodes. Returns: - Optional[int]: The earliest time that this Nodes is valid or None if the Nodes is valid for all times. + Latest date time of the nodes. """ @property - def properties(self): + def earliest_date_time(self): """ - The properties of the node + Returns the earliest time of the nodes. Returns: - A List of properties + Earliest time of the nodes. """ @property - def in_neighbours(self): + def start(self): """ - Get the neighbours of this node that point into this node. + Gets the start time for rolling and expanding windows for this Nodes Returns: - - An iterator over the neighbours of this node that point into this node. + Optional[int]: The earliest time that this Nodes is valid or None if the Nodes is valid for all times. """ @property - def id(self): - """Returns an iterator over the nodes ids""" + def start_date_time(self): + """ + Gets the earliest datetime that this Nodes is valid - @property - def name(self): - """Returns an iterator over the nodes name""" + Returns: + Optional[Datetime]: The earliest datetime that this Nodes is valid or None if the Nodes is valid for all times. + """ @property - def edges(self): + def end(self): """ - Get the edges that are incident to this node. + Gets the latest time that this Nodes is valid. Returns: - - An iterator over the edges that are incident to this node. + Optional[int]: The latest time that this Nodes is valid or None if the Nodes is valid for all times. """ @property @@ -3033,23 +3044,23 @@ class Nodes(object): """ @property - def start_date_time(self): - """ - Gets the earliest datetime that this Nodes is valid - - Returns: - Optional[Datetime]: The earliest datetime that this Nodes is valid or None if the Nodes is valid for all times. - """ + def node_type(self): + """Returns the type of node""" @property - def latest_date_time(self): + def in_neighbours(self): """ - Returns the latest date time of the nodes. + Get the neighbours of this node that point into this node. Returns: - Latest date time of the nodes. + + An iterator over the neighbours of this node that point into this node. """ + @property + def latest_time(self): + """Returns an iterator over the nodes latest time""" + @property def neighbours(self): """ @@ -3061,28 +3072,17 @@ class Nodes(object): """ @property - def in_edges(self): - """ - Get the edges that point into this node. - - Returns: - - An iterator over the edges that point into this node. - """ - - @property - def out_neighbours(self): + def properties(self): """ - Get the neighbours of this node that point out of this node. + The properties of the node Returns: - - An iterator over the neighbours of this node that point out of this node. + A List of properties """ @property - def latest_time(self): - """Returns an iterator over the nodes latest time""" + def earliest_time(self): + """Returns an iterator over the nodes earliest time""" class MutableNode(Node): def __repr__(self): @@ -3486,34 +3486,43 @@ class Edge(object): """ @property - def nbr(self): - """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" + def latest_time(self): + """ + Gets the latest time of an edge. + + Returns: + int: The latest time of an edge + """ @property - def layer_name(self): + def end_date_time(self): """ - Gets the name of the layer this edge belongs to - assuming it only belongs to one layer + Gets the latest datetime that this Edge is valid Returns: - str: The name of the layer + Optional[Datetime]: The latest datetime that this Edge is valid or None if the Edge is valid for all times. """ @property - def start(self): + def nbr(self): + """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" + + @property + def time(self): """ - Gets the start time for rolling and expanding windows for this Edge + Gets the time of an exploded edge. Returns: - Optional[int]: The earliest time that this Edge is valid or None if the Edge is valid for all times. + int: The time of an exploded edge """ @property - def earliest_time(self): + def layer_name(self): """ - Gets the earliest time of an edge. + Gets the name of the layer this edge belongs to - assuming it only belongs to one layer Returns: - int: The earliest time of an edge + str: The name of the layer """ @property @@ -3526,12 +3535,13 @@ class Edge(object): """ @property - def dst(self): - """Returns the destination node of the edge.""" + def window_size(self): + """ + Get the window size (difference between start and end) for this Edge - @property - def id(self): - """The id of the edge.""" + Returns: + Optional[int] + """ @property def properties(self): @@ -3543,88 +3553,78 @@ class Edge(object): """ @property - def earliest_date_time(self): - """ - Gets of earliest datetime of an edge. - - Returns: - Datetime: the earliest datetime of an edge - """ + def id(self): + """The id of the edge.""" @property - def time(self): - """ - Gets the time of an exploded edge. - - Returns: - int: The time of an exploded edge - """ + def src(self): + """Returns the source node of the edge.""" @property - def latest_date_time(self): + def earliest_time(self): """ - Gets of latest datetime of an edge. + Gets the earliest time of an edge. Returns: - Datetime: the latest datetime of an edge + int: The earliest time of an edge """ @property - def date_time(self): + def earliest_date_time(self): """ - Gets the datetime of an exploded edge. + Gets of earliest datetime of an edge. Returns: - Datetime: the datetime of an exploded edge + Datetime: the earliest datetime of an edge """ @property - def src(self): - """Returns the source node of the edge.""" + def dst(self): + """Returns the destination node of the edge.""" @property - def latest_time(self): + def start_date_time(self): """ - Gets the latest time of an edge. + Gets the earliest datetime that this Edge is valid Returns: - int: The latest time of an edge + Optional[Datetime]: The earliest datetime that this Edge is valid or None if the Edge is valid for all times. """ @property - def start_date_time(self): + def date_time(self): """ - Gets the earliest datetime that this Edge is valid + Gets the datetime of an exploded edge. Returns: - Optional[Datetime]: The earliest datetime that this Edge is valid or None if the Edge is valid for all times. + Datetime: the datetime of an exploded edge """ @property - def end(self): + def latest_date_time(self): """ - Gets the latest time that this Edge is valid. + Gets of latest datetime of an edge. Returns: - Optional[int]: The latest time that this Edge is valid or None if the Edge is valid for all times. + Datetime: the latest datetime of an edge """ @property - def end_date_time(self): + def start(self): """ - Gets the latest datetime that this Edge is valid + Gets the start time for rolling and expanding windows for this Edge Returns: - Optional[Datetime]: The latest datetime that this Edge is valid or None if the Edge is valid for all times. + Optional[int]: The earliest time that this Edge is valid or None if the Edge is valid for all times. """ @property - def window_size(self): + def end(self): """ - Get the window size (difference between start and end) for this Edge + Gets the latest time that this Edge is valid. Returns: - Optional[int] + Optional[int]: The latest time that this Edge is valid or None if the Edge is valid for all times. """ class Edges(object): @@ -3963,25 +3963,35 @@ class Edges(object): """ @property - def layer_names(self): + def src(self): + """Returns the source node of the edge.""" + + @property + def window_size(self): """ - Get the layer names that all edges belong to - assuming they only belong to one layer + Get the window size (difference between start and end) for this Edges Returns: - A list of layer names + Optional[int] """ @property - def id(self): - """Returns all ids of the edges.""" + def time(self): + """ + Returns the times of exploded edges - @property - def src(self): - """Returns the source node of the edge.""" + Returns: + Time of edge + """ @property - def dst(self): - """Returns the destination node of the edge.""" + def layer_names(self): + """ + Get the layer names that all edges belong to - assuming they only belong to one layer + + Returns: + A list of layer names + """ @property def latest_time(self): @@ -4002,70 +4012,60 @@ class Edges(object): """ @property - def window_size(self): - """ - Get the window size (difference between start and end) for this Edges - - Returns: - Optional[int] - """ + def dst(self): + """Returns the destination node of the edge.""" @property def properties(self): """Returns all properties of the edges""" @property - def date_time(self): + def start(self): """ - Returns the date times of exploded edges + Gets the start time for rolling and expanding windows for this Edges Returns: - A list of date times. + Optional[int]: The earliest time that this Edges is valid or None if the Edges is valid for all times. """ @property - def end(self): + def date_time(self): """ - Gets the latest time that this Edges is valid. + Returns the date times of exploded edges Returns: - Optional[int]: The latest time that this Edges is valid or None if the Edges is valid for all times. + A list of date times. """ @property - def earliest_time(self): + def latest_date_time(self): """ - Returns the earliest time of the edges. + Returns the latest date time of the edges. Returns: - Earliest time of the edges. + Latest date time of the edges. """ @property - def time(self): - """ - Returns the times of exploded edges - - Returns: - Time of edge - """ + def id(self): + """Returns all ids of the edges.""" @property - def layer_name(self): + def end_date_time(self): """ - Get the layer name that all edges belong to - assuming they only belong to one layer + Gets the latest datetime that this Edges is valid Returns: - The name of the layer + Optional[Datetime]: The latest datetime that this Edges is valid or None if the Edges is valid for all times. """ @property - def end_date_time(self): + def earliest_time(self): """ - Gets the latest datetime that this Edges is valid + Returns the earliest time of the edges. Returns: - Optional[Datetime]: The latest datetime that this Edges is valid or None if the Edges is valid for all times. + Earliest time of the edges. """ @property @@ -4073,21 +4073,21 @@ class Edges(object): """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" @property - def start(self): + def end(self): """ - Gets the start time for rolling and expanding windows for this Edges + Gets the latest time that this Edges is valid. Returns: - Optional[int]: The earliest time that this Edges is valid or None if the Edges is valid for all times. + Optional[int]: The latest time that this Edges is valid or None if the Edges is valid for all times. """ @property - def latest_date_time(self): + def layer_name(self): """ - Returns the latest date time of the edges. + Get the layer name that all edges belong to - assuming they only belong to one layer Returns: - Latest date time of the edges. + The name of the layer """ @property diff --git a/python/python/raphtory/node_state/__init__.pyi b/python/python/raphtory/node_state/__init__.pyi index dbe347d4eb..5de6dcbc5c 100644 --- a/python/python/raphtory/node_state/__init__.pyi +++ b/python/python/raphtory/node_state/__init__.pyi @@ -50,6 +50,14 @@ class DegreeView(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def default_layer(self) -> DegreeView: """ Return a view of DegreeView containing only the default edge layer @@ -424,15 +432,6 @@ class DegreeView(object): list[int] """ - @property - def end_date_time(self): - """ - Gets the latest datetime that this DegreeView is valid - - Returns: - Optional[Datetime]: The latest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. - """ - @property def start_date_time(self): """ @@ -460,6 +459,15 @@ class DegreeView(object): Optional[int]: The latest time that this DegreeView is valid or None if the DegreeView is valid for all times. """ + @property + def end_date_time(self): + """ + Gets the latest datetime that this DegreeView is valid + + Returns: + Optional[Datetime]: The latest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. + """ + @property def window_size(self): """ @@ -500,6 +508,14 @@ class NodeStateUsize(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def sum(self): """ sum of values over all nodes @@ -1112,6 +1128,14 @@ class EarliestTimeView(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def default_layer(self) -> EarliestTimeView: """ Return a view of EarliestTimeView containing only the default edge layer @@ -1471,39 +1495,39 @@ class EarliestTimeView(object): """ @property - def start_date_time(self): + def start(self): """ - Gets the earliest datetime that this EarliestTimeView is valid + Gets the start time for rolling and expanding windows for this EarliestTimeView Returns: - Optional[Datetime]: The earliest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + Optional[int]: The earliest time that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ @property - def end_date_time(self): + def window_size(self): """ - Gets the latest datetime that this EarliestTimeView is valid + Get the window size (difference between start and end) for this EarliestTimeView Returns: - Optional[Datetime]: The latest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + Optional[int] """ @property - def window_size(self): + def end_date_time(self): """ - Get the window size (difference between start and end) for this EarliestTimeView + Gets the latest datetime that this EarliestTimeView is valid Returns: - Optional[int] + Optional[Datetime]: The latest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ @property - def start(self): + def start_date_time(self): """ - Gets the start time for rolling and expanding windows for this EarliestTimeView + Gets the earliest datetime that this EarliestTimeView is valid Returns: - Optional[int]: The earliest time that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + Optional[Datetime]: The earliest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ @property @@ -1548,6 +1572,14 @@ class LatestTimeView(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def default_layer(self) -> LatestTimeView: """ Return a view of LatestTimeView containing only the default edge layer @@ -1906,6 +1938,15 @@ class LatestTimeView(object): list[Optional[int]] """ + @property + def start(self): + """ + Gets the start time for rolling and expanding windows for this LatestTimeView + + Returns: + Optional[int]: The earliest time that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + """ + @property def end(self): """ @@ -1933,15 +1974,6 @@ class LatestTimeView(object): Optional[Datetime]: The latest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. """ - @property - def start(self): - """ - Gets the start time for rolling and expanding windows for this LatestTimeView - - Returns: - Optional[int]: The earliest time that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. - """ - @property def start_date_time(self): """ @@ -1984,6 +2016,14 @@ class NameView(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def sorted(self, reverse: bool = False): """ Sort by value @@ -2140,6 +2180,14 @@ class NodeStateString(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def sorted(self, reverse: bool = False): """ Sort by value @@ -2282,6 +2330,14 @@ class EarliestDateTimeView(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def default_layer(self) -> EarliestDateTimeView: """ Return a view of EarliestDateTimeView containing only the default edge layer @@ -2650,39 +2706,39 @@ class EarliestDateTimeView(object): """ @property - def start(self): + def start_date_time(self): """ - Gets the start time for rolling and expanding windows for this EarliestDateTimeView + Gets the earliest datetime that this EarliestDateTimeView is valid Returns: - Optional[int]: The earliest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[Datetime]: The earliest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ @property - def window_size(self): + def end(self): """ - Get the window size (difference between start and end) for this EarliestDateTimeView + Gets the latest time that this EarliestDateTimeView is valid. Returns: - Optional[int] + Optional[int]: The latest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ @property - def end(self): + def window_size(self): """ - Gets the latest time that this EarliestDateTimeView is valid. + Get the window size (difference between start and end) for this EarliestDateTimeView Returns: - Optional[int]: The latest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[int] """ @property - def start_date_time(self): + def start(self): """ - Gets the earliest datetime that this EarliestDateTimeView is valid + Gets the start time for rolling and expanding windows for this EarliestDateTimeView Returns: - Optional[Datetime]: The earliest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[int]: The earliest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ class LatestDateTimeView(object): @@ -2718,6 +2774,14 @@ class LatestDateTimeView(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def default_layer(self) -> LatestDateTimeView: """ Return a view of LatestDateTimeView containing only the default edge layer @@ -3076,15 +3140,6 @@ class LatestDateTimeView(object): list[Optional[Datetime]] """ - @property - def start_date_time(self): - """ - Gets the earliest datetime that this LatestDateTimeView is valid - - Returns: - Optional[Datetime]: The earliest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. - """ - @property def end_date_time(self): """ @@ -3095,12 +3150,12 @@ class LatestDateTimeView(object): """ @property - def window_size(self): + def start_date_time(self): """ - Get the window size (difference between start and end) for this LatestDateTimeView + Gets the earliest datetime that this LatestDateTimeView is valid Returns: - Optional[int] + Optional[Datetime]: The earliest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ @property @@ -3121,6 +3176,15 @@ class LatestDateTimeView(object): Optional[int]: The latest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ + @property + def window_size(self): + """ + Get the window size (difference between start and end) for this LatestDateTimeView + + Returns: + Optional[int] + """ + class NodeStateOptionDateTime(object): def __repr__(self): """Return repr(self).""" @@ -3152,6 +3216,14 @@ class NodeStateOptionDateTime(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def sorted(self, reverse: bool = False): """ Sort by value @@ -3652,15 +3724,6 @@ class HistoryView(object): list[list[int]] """ - @property - def end(self): - """ - Gets the latest time that this HistoryView is valid. - - Returns: - Optional[int]: The latest time that this HistoryView is valid or None if the HistoryView is valid for all times. - """ - @property def start(self): """ @@ -3679,6 +3742,15 @@ class HistoryView(object): Optional[int] """ + @property + def end(self): + """ + Gets the latest time that this HistoryView is valid. + + Returns: + Optional[int]: The latest time that this HistoryView is valid or None if the HistoryView is valid for all times. + """ + @property def start_date_time(self): """ @@ -4229,12 +4301,12 @@ class HistoryDateTimeView(object): """ @property - def start_date_time(self): + def window_size(self): """ - Gets the earliest datetime that this HistoryDateTimeView is valid + Get the window size (difference between start and end) for this HistoryDateTimeView Returns: - Optional[Datetime]: The earliest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + Optional[int] """ @property @@ -4247,21 +4319,21 @@ class HistoryDateTimeView(object): """ @property - def end(self): + def start_date_time(self): """ - Gets the latest time that this HistoryDateTimeView is valid. + Gets the earliest datetime that this HistoryDateTimeView is valid Returns: - Optional[int]: The latest time that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + Optional[Datetime]: The earliest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ @property - def window_size(self): + def end(self): """ - Get the window size (difference between start and end) for this HistoryDateTimeView + Gets the latest time that this HistoryDateTimeView is valid. Returns: - Optional[int] + Optional[int]: The latest time that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ @property @@ -4446,6 +4518,14 @@ class NodeTypeView(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def sorted(self, reverse: bool = False): """ Sort by value @@ -4602,6 +4682,14 @@ class NodeStateOptionStr(object): def __getitem__(self, key): """Return self[key].""" + def groups(self) -> NodeGroups: + """ + Group by value + + Returns: + NodeGroups: The grouped nodes + """ + def sorted(self, reverse: bool = False): """ Sort by value diff --git a/python/python/raphtory/vectors/__init__.pyi b/python/python/raphtory/vectors/__init__.pyi index dfcd3922e1..05916193ce 100644 --- a/python/python/raphtory/vectors/__init__.pyi +++ b/python/python/raphtory/vectors/__init__.pyi @@ -108,9 +108,9 @@ class Document(object): @property def entity(self): ... @property - def embedding(self): ... - @property def life(self): ... + @property + def embedding(self): ... class VectorSelection(object): def nodes(self): From 29810e2fd774a18ee6490fab5e3d3cd87e26a081 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 9 Jan 2025 13:34:04 +0100 Subject: [PATCH 13/29] tidy up warnings --- python/python/raphtory/__init__.pyi | 660 +++++------ .../python/raphtory/node_state/__init__.pyi | 1022 ++++++++--------- python/python/raphtory/vectors/__init__.pyi | 6 +- raphtory/src/algorithms/metrics/balance.rs | 24 +- raphtory/src/core/utils/errors.rs | 3 + raphtory/src/db/api/state/group_by.rs | 3 +- raphtory/src/db/api/state/lazy_node_state.rs | 5 +- raphtory/src/db/api/state/node_state_ops.rs | 5 +- raphtory/src/python/graph/node.rs | 5 +- .../src/python/graph/node_state/group_by.rs | 11 +- .../src/python/graph/node_state/node_state.rs | 40 +- raphtory/src/python/packages/algorithms.rs | 12 +- 12 files changed, 898 insertions(+), 898 deletions(-) diff --git a/python/python/raphtory/__init__.pyi b/python/python/raphtory/__init__.pyi index 11e92ae419..8ebdd89787 100644 --- a/python/python/raphtory/__init__.pyi +++ b/python/python/raphtory/__init__.pyi @@ -41,68 +41,6 @@ class GraphView(object): def __ge__(self, value): """Return self>=value.""" - def to_pyvis( - self, - explode_edges=False, - edge_color="#000000", - shape=None, - node_image=None, - edge_weight=None, - edge_label=None, - colour_nodes_by_type=False, - notebook=False, - **kwargs - ): - """ - Draw a graph with PyVis. - Pyvis is a required dependency. If you intend to use this function make sure that you install Pyvis - with ``pip install pyvis`` - - Args: - graph (graph): A Raphtory graph. - explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. Defaults to False. - edge_color (str): A string defining the colour of the edges in the graph. Defaults to "#000000". - shape (str): An optional string defining what the node looks like. Defaults to "dot". - There are two types of nodes. One type has the label inside of it and the other type has the label underneath it. - The types with the label inside of it are: ellipse, circle, database, box, text. - The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon. - node_image (str, optional): An optional string defining the url of a custom node image. - edge_weight (str, optional): An optional string defining the name of the property where edge weight is set on your Raphtory graph. - If not provided, the edge weight is set to `1.0` for all edges. - edge_label (str): An optional string defining the name of the property where edge label is set on your Raphtory graph. By default, an empty string as the label is set. - notebook (bool): A boolean that is set to True if using jupyter notebook. Defaults to False - kwargs: Additional keyword arguments that are passed to the pyvis Network class. - - Returns: - A pyvis network - """ - - def to_networkx( - self, - explode_edges: bool = False, - include_node_properties: bool = True, - include_edge_properties: bool = True, - include_update_history: bool = True, - include_property_history: bool = True, - ): - """ - Returns a graph with NetworkX. - - Network X is a required dependency. - If you intend to use this function make sure that - you install Network X with ``pip install networkx`` - - Args: - explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False. - include_node_properties (bool): A boolean that is set to True if you want to include the node properties in the graph. By default this is set to True. - include_edge_properties (bool): A boolean that is set to True if you want to include the edge properties in the graph. By default this is set to True. - include_update_history (bool): A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True. - include_property_history (bool): A boolean that is set to True if you want to include the histories in the graph. By default this is set to True. - - Returns: - A Networkx MultiDiGraph. - """ - def vectorise( self, embedding: Callable[[list], list], @@ -539,6 +477,68 @@ class GraphView(object): """ + def to_pyvis( + self, + explode_edges=False, + edge_color="#000000", + shape=None, + node_image=None, + edge_weight=None, + edge_label=None, + colour_nodes_by_type=False, + notebook=False, + **kwargs + ): + """ + Draw a graph with PyVis. + Pyvis is a required dependency. If you intend to use this function make sure that you install Pyvis + with ``pip install pyvis`` + + Args: + graph (graph): A Raphtory graph. + explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. Defaults to False. + edge_color (str): A string defining the colour of the edges in the graph. Defaults to "#000000". + shape (str): An optional string defining what the node looks like. Defaults to "dot". + There are two types of nodes. One type has the label inside of it and the other type has the label underneath it. + The types with the label inside of it are: ellipse, circle, database, box, text. + The ones with the label outside of it are: image, circularImage, diamond, dot, star, triangle, triangleDown, square and icon. + node_image (str, optional): An optional string defining the url of a custom node image. + edge_weight (str, optional): An optional string defining the name of the property where edge weight is set on your Raphtory graph. + If not provided, the edge weight is set to `1.0` for all edges. + edge_label (str): An optional string defining the name of the property where edge label is set on your Raphtory graph. By default, an empty string as the label is set. + notebook (bool): A boolean that is set to True if using jupyter notebook. Defaults to False + kwargs: Additional keyword arguments that are passed to the pyvis Network class. + + Returns: + A pyvis network + """ + + def to_networkx( + self, + explode_edges: bool = False, + include_node_properties: bool = True, + include_edge_properties: bool = True, + include_update_history: bool = True, + include_property_history: bool = True, + ): + """ + Returns a graph with NetworkX. + + Network X is a required dependency. + If you intend to use this function make sure that + you install Network X with ``pip install networkx`` + + Args: + explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False. + include_node_properties (bool): A boolean that is set to True if you want to include the node properties in the graph. By default this is set to True. + include_edge_properties (bool): A boolean that is set to True if you want to include the edge properties in the graph. By default this is set to True. + include_update_history (bool): A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True. + include_property_history (bool): A boolean that is set to True if you want to include the histories in the graph. By default this is set to True. + + Returns: + A Networkx MultiDiGraph. + """ + def index(self): """ Indexes all node and edge properties. @@ -550,30 +550,30 @@ class GraphView(object): """ @property - def end(self): + def latest_date_time(self): """ - Gets the latest time that this GraphView is valid. + DateTime of latest activity in the graph Returns: - Optional[int]: The latest time that this GraphView is valid or None if the GraphView is valid for all times. + Optional[Datetime]: the datetime of the latest activity in the graph """ @property - def start_date_time(self): + def earliest_time(self): """ - Gets the earliest datetime that this GraphView is valid + Timestamp of earliest activity in the graph Returns: - Optional[Datetime]: The earliest datetime that this GraphView is valid or None if the GraphView is valid for all times. + Optional[int]: the timestamp of the earliest activity in the graph """ @property - def nodes(self): + def end(self): """ - Gets the nodes in the graph + Gets the latest time that this GraphView is valid. Returns: - Nodes: the nodes in the graph + Optional[int]: The latest time that this GraphView is valid or None if the GraphView is valid for all times. """ @property @@ -586,85 +586,85 @@ class GraphView(object): """ @property - def unique_layers(self): + def nodes(self): """ - Return all the layer ids in the graph + Gets the nodes in the graph Returns: - list[str] + Nodes: the nodes in the graph """ @property - def earliest_date_time(self): + def unique_layers(self): """ - DateTime of earliest activity in the graph + Return all the layer ids in the graph Returns: - Optional[Datetime]: the datetime of the earliest activity in the graph + list[str] """ @property - def latest_time(self): + def properties(self): """ - Timestamp of latest activity in the graph + Get all graph properties + Returns: - Optional[int]: the timestamp of the latest activity in the graph + Properties: Properties paired with their names """ @property - def end_date_time(self): + def start(self): """ - Gets the latest datetime that this GraphView is valid + Gets the start time for rolling and expanding windows for this GraphView Returns: - Optional[Datetime]: The latest datetime that this GraphView is valid or None if the GraphView is valid for all times. + Optional[int]: The earliest time that this GraphView is valid or None if the GraphView is valid for all times. """ @property - def window_size(self): + def start_date_time(self): """ - Get the window size (difference between start and end) for this GraphView + Gets the earliest datetime that this GraphView is valid Returns: - Optional[int] + Optional[Datetime]: The earliest datetime that this GraphView is valid or None if the GraphView is valid for all times. """ @property - def properties(self): + def end_date_time(self): """ - Get all graph properties - + Gets the latest datetime that this GraphView is valid Returns: - Properties: Properties paired with their names + Optional[Datetime]: The latest datetime that this GraphView is valid or None if the GraphView is valid for all times. """ @property - def start(self): + def window_size(self): """ - Gets the start time for rolling and expanding windows for this GraphView + Get the window size (difference between start and end) for this GraphView Returns: - Optional[int]: The earliest time that this GraphView is valid or None if the GraphView is valid for all times. + Optional[int] """ @property - def latest_date_time(self): + def earliest_date_time(self): """ - DateTime of latest activity in the graph + DateTime of earliest activity in the graph Returns: - Optional[Datetime]: the datetime of the latest activity in the graph + Optional[Datetime]: the datetime of the earliest activity in the graph """ @property - def earliest_time(self): + def latest_time(self): """ - Timestamp of earliest activity in the graph + Timestamp of latest activity in the graph Returns: - Optional[int]: the timestamp of the earliest activity in the graph + Optional[int]: the timestamp of the latest activity in the graph """ class Graph(GraphView): @@ -2381,24 +2381,6 @@ class Node(object): """ - @property - def window_size(self): - """ - Get the window size (difference between start and end) for this Node - - Returns: - Optional[int] - """ - - @property - def properties(self): - """ - The properties of the node - - Returns: - Properties: A list of properties. - """ - @property def latest_date_time(self): """ @@ -2412,22 +2394,12 @@ class Node(object): """ @property - def out_edges(self): - """ - Get the edges that point out of this node. - - Returns: - - An iterator over the edges that point out of this node. - """ - - @property - def name(self): + def start(self): """ - Returns the name of the node. + Gets the start time for rolling and expanding windows for this Node Returns: - str: The id of the node as a string. + Optional[int]: The earliest time that this Node is valid or None if the Node is valid for all times. """ @property @@ -2435,88 +2407,107 @@ class Node(object): """Returns the type of node""" @property - def out_neighbours(self): + def start_date_time(self): """ - Get the neighbours of this node that point out of this node. + Gets the earliest datetime that this Node is valid Returns: - - An iterator over the neighbours of this node that point out of this node. + Optional[Datetime]: The earliest datetime that this Node is valid or None if the Node is valid for all times. """ @property - def earliest_date_time(self): + def window_size(self): """ - Returns the earliest datetime that the node exists. + Get the window size (difference between start and end) for this Node Returns: - Datetime: The earliest datetime that the node exists as a Datetime. + Optional[int] """ @property - def latest_time(self): + def end_date_time(self): """ - Returns the latest time that the node exists. + Gets the latest datetime that this Node is valid Returns: - int: The latest time that the node exists as an integer. + Optional[Datetime]: The latest datetime that this Node is valid or None if the Node is valid for all times. """ @property - def edges(self): + def end(self): """ - Get the edges that are incident to this node. + Gets the latest time that this Node is valid. Returns: - - An iterator over the edges that are incident to this node. + Optional[int]: The latest time that this Node is valid or None if the Node is valid for all times. """ @property - def earliest_time(self): + def in_edges(self): """ - Returns the earliest time that the node exists. + Get the edges that point into this node. Returns: - int: The earliest time that the node exists as an integer. + + An iterator over the edges that point into this node. """ @property - def start_date_time(self): + def neighbours(self): """ - Gets the earliest datetime that this Node is valid + Get the neighbours of this node. Returns: - Optional[Datetime]: The earliest datetime that this Node is valid or None if the Node is valid for all times. + + An iterator over the neighbours of this node. """ @property - def in_edges(self): + def in_neighbours(self): """ - Get the edges that point into this node. + Get the neighbours of this node that point into this node. Returns: - An iterator over the edges that point into this node. + An iterator over the neighbours of this node that point into this node. """ @property - def start(self): + def earliest_date_time(self): """ - Gets the start time for rolling and expanding windows for this Node + Returns the earliest datetime that the node exists. Returns: - Optional[int]: The earliest time that this Node is valid or None if the Node is valid for all times. + Datetime: The earliest datetime that the node exists as a Datetime. """ @property - def in_neighbours(self): + def edges(self): """ - Get the neighbours of this node that point into this node. + Get the edges that are incident to this node. Returns: - An iterator over the neighbours of this node that point into this node. + An iterator over the edges that are incident to this node. + """ + + @property + def latest_time(self): + """ + Returns the latest time that the node exists. + + Returns: + int: The latest time that the node exists as an integer. + """ + + @property + def out_edges(self): + """ + Get the edges that point out of this node. + + Returns: + + An iterator over the edges that point out of this node. """ @property @@ -2530,31 +2521,40 @@ class Node(object): """ @property - def end(self): + def properties(self): """ - Gets the latest time that this Node is valid. + The properties of the node Returns: - Optional[int]: The latest time that this Node is valid or None if the Node is valid for all times. + Properties: A list of properties. """ @property - def end_date_time(self): + def name(self): """ - Gets the latest datetime that this Node is valid + Returns the name of the node. Returns: - Optional[Datetime]: The latest datetime that this Node is valid or None if the Node is valid for all times. + str: The id of the node as a string. """ @property - def neighbours(self): + def out_neighbours(self): """ - Get the neighbours of this node. + Get the neighbours of this node that point out of this node. Returns: - An iterator over the neighbours of this node. + An iterator over the neighbours of this node that point out of this node. + """ + + @property + def earliest_time(self): + """ + Returns the earliest time that the node exists. + + Returns: + int: The earliest time that the node exists as an integer. """ class Nodes(object): @@ -2933,96 +2933,93 @@ class Nodes(object): """ @property - def edges(self): + def start(self): """ - Get the edges that are incident to this node. + Gets the start time for rolling and expanding windows for this Nodes Returns: - - An iterator over the edges that are incident to this node. + Optional[int]: The earliest time that this Nodes is valid or None if the Nodes is valid for all times. """ @property - def out_edges(self): + def start_date_time(self): """ - Get the edges that point out of this node. + Gets the earliest datetime that this Nodes is valid Returns: - - An iterator over the edges that point out of this node. + Optional[Datetime]: The earliest datetime that this Nodes is valid or None if the Nodes is valid for all times. """ @property - def name(self): - """Returns an iterator over the nodes name""" - - @property - def out_neighbours(self): + def window_size(self): """ - Get the neighbours of this node that point out of this node. + Get the window size (difference between start and end) for this Nodes Returns: - - An iterator over the neighbours of this node that point out of this node. + Optional[int] """ @property - def id(self): - """Returns an iterator over the nodes ids""" - - @property - def in_edges(self): + def in_neighbours(self): """ - Get the edges that point into this node. + Get the neighbours of this node that point into this node. Returns: - An iterator over the edges that point into this node. + An iterator over the neighbours of this node that point into this node. """ @property - def end_date_time(self): + def out_neighbours(self): """ - Gets the latest datetime that this Nodes is valid + Get the neighbours of this node that point out of this node. Returns: - Optional[Datetime]: The latest datetime that this Nodes is valid or None if the Nodes is valid for all times. + + An iterator over the neighbours of this node that point out of this node. """ @property - def latest_date_time(self): + def out_edges(self): """ - Returns the latest date time of the nodes. + Get the edges that point out of this node. Returns: - Latest date time of the nodes. + + An iterator over the edges that point out of this node. """ @property - def earliest_date_time(self): + def neighbours(self): """ - Returns the earliest time of the nodes. + Get the neighbours of this node. Returns: - Earliest time of the nodes. + + An iterator over the neighbours of this node. """ @property - def start(self): + def id(self): + """Returns an iterator over the nodes ids""" + + @property + def in_edges(self): """ - Gets the start time for rolling and expanding windows for this Nodes + Get the edges that point into this node. Returns: - Optional[int]: The earliest time that this Nodes is valid or None if the Nodes is valid for all times. + + An iterator over the edges that point into this node. """ @property - def start_date_time(self): + def latest_date_time(self): """ - Gets the earliest datetime that this Nodes is valid + Returns the latest date time of the nodes. Returns: - Optional[Datetime]: The earliest datetime that this Nodes is valid or None if the Nodes is valid for all times. + Latest date time of the nodes. """ @property @@ -3035,40 +3032,47 @@ class Nodes(object): """ @property - def window_size(self): + def end_date_time(self): """ - Get the window size (difference between start and end) for this Nodes + Gets the latest datetime that this Nodes is valid Returns: - Optional[int] + Optional[Datetime]: The latest datetime that this Nodes is valid or None if the Nodes is valid for all times. """ @property - def node_type(self): - """Returns the type of node""" + def latest_time(self): + """Returns an iterator over the nodes latest time""" @property - def in_neighbours(self): + def earliest_time(self): + """Returns an iterator over the nodes earliest time""" + + @property + def name(self): + """Returns an iterator over the nodes name""" + + @property + def earliest_date_time(self): """ - Get the neighbours of this node that point into this node. + Returns the earliest time of the nodes. Returns: - - An iterator over the neighbours of this node that point into this node. + Earliest time of the nodes. """ @property - def latest_time(self): - """Returns an iterator over the nodes latest time""" + def node_type(self): + """Returns the type of node""" @property - def neighbours(self): + def edges(self): """ - Get the neighbours of this node. + Get the edges that are incident to this node. Returns: - An iterator over the neighbours of this node. + An iterator over the edges that are incident to this node. """ @property @@ -3080,10 +3084,6 @@ class Nodes(object): A List of properties """ - @property - def earliest_time(self): - """Returns an iterator over the nodes earliest time""" - class MutableNode(Node): def __repr__(self): """Return repr(self).""" @@ -3486,70 +3486,57 @@ class Edge(object): """ @property - def latest_time(self): - """ - Gets the latest time of an edge. - - Returns: - int: The latest time of an edge - """ - - @property - def end_date_time(self): + def layer_names(self): """ - Gets the latest datetime that this Edge is valid + Gets the names of the layers this edge belongs to Returns: - Optional[Datetime]: The latest datetime that this Edge is valid or None if the Edge is valid for all times. + List[str]- The name of the layer """ @property - def nbr(self): - """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" - - @property - def time(self): + def earliest_date_time(self): """ - Gets the time of an exploded edge. + Gets of earliest datetime of an edge. Returns: - int: The time of an exploded edge + Datetime: the earliest datetime of an edge """ @property - def layer_name(self): + def start(self): """ - Gets the name of the layer this edge belongs to - assuming it only belongs to one layer + Gets the start time for rolling and expanding windows for this Edge Returns: - str: The name of the layer + Optional[int]: The earliest time that this Edge is valid or None if the Edge is valid for all times. """ @property - def layer_names(self): + def latest_date_time(self): """ - Gets the names of the layers this edge belongs to + Gets of latest datetime of an edge. Returns: - List[str]- The name of the layer + Datetime: the latest datetime of an edge """ @property - def window_size(self): + def properties(self): """ - Get the window size (difference between start and end) for this Edge + Returns a view of the properties of the edge. Returns: - Optional[int] + Properties on the Edge. """ @property - def properties(self): + def time(self): """ - Returns a view of the properties of the edge. + Gets the time of an exploded edge. Returns: - Properties on the Edge. + int: The time of an exploded edge """ @property @@ -3557,8 +3544,13 @@ class Edge(object): """The id of the edge.""" @property - def src(self): - """Returns the source node of the edge.""" + def latest_time(self): + """ + Gets the latest time of an edge. + + Returns: + int: The latest time of an edge + """ @property def earliest_time(self): @@ -3570,61 +3562,69 @@ class Edge(object): """ @property - def earliest_date_time(self): + def date_time(self): """ - Gets of earliest datetime of an edge. + Gets the datetime of an exploded edge. Returns: - Datetime: the earliest datetime of an edge + Datetime: the datetime of an exploded edge """ + @property + def src(self): + """Returns the source node of the edge.""" + @property def dst(self): """Returns the destination node of the edge.""" @property - def start_date_time(self): + def nbr(self): + """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" + + @property + def end_date_time(self): """ - Gets the earliest datetime that this Edge is valid + Gets the latest datetime that this Edge is valid Returns: - Optional[Datetime]: The earliest datetime that this Edge is valid or None if the Edge is valid for all times. + Optional[Datetime]: The latest datetime that this Edge is valid or None if the Edge is valid for all times. """ @property - def date_time(self): + def window_size(self): """ - Gets the datetime of an exploded edge. + Get the window size (difference between start and end) for this Edge Returns: - Datetime: the datetime of an exploded edge + Optional[int] """ @property - def latest_date_time(self): + def layer_name(self): """ - Gets of latest datetime of an edge. + Gets the name of the layer this edge belongs to - assuming it only belongs to one layer Returns: - Datetime: the latest datetime of an edge + str: The name of the layer """ @property - def start(self): + def end(self): """ - Gets the start time for rolling and expanding windows for this Edge + Gets the latest time that this Edge is valid. Returns: - Optional[int]: The earliest time that this Edge is valid or None if the Edge is valid for all times. + Optional[int]: The latest time that this Edge is valid or None if the Edge is valid for all times. """ @property - def end(self): + def start_date_time(self): """ - Gets the latest time that this Edge is valid. + Gets the earliest datetime that this Edge is valid Returns: - Optional[int]: The latest time that this Edge is valid or None if the Edge is valid for all times. + Optional[Datetime]: The earliest datetime that this Edge is valid or None if the Edge is valid for all times. """ class Edges(object): @@ -3963,34 +3963,52 @@ class Edges(object): """ @property - def src(self): - """Returns the source node of the edge.""" + def layer_name(self): + """ + Get the layer name that all edges belong to - assuming they only belong to one layer + + Returns: + The name of the layer + """ @property - def window_size(self): + def date_time(self): """ - Get the window size (difference between start and end) for this Edges + Returns the date times of exploded edges Returns: - Optional[int] + A list of date times. """ @property - def time(self): + def nbr(self): + """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" + + @property + def start(self): """ - Returns the times of exploded edges + Gets the start time for rolling and expanding windows for this Edges Returns: - Time of edge + Optional[int]: The earliest time that this Edges is valid or None if the Edges is valid for all times. """ @property - def layer_names(self): + def end_date_time(self): """ - Get the layer names that all edges belong to - assuming they only belong to one layer + Gets the latest datetime that this Edges is valid Returns: - A list of layer names + Optional[Datetime]: The latest datetime that this Edges is valid or None if the Edges is valid for all times. + """ + + @property + def window_size(self): + """ + Get the window size (difference between start and end) for this Edges + + Returns: + Optional[int] """ @property @@ -4016,25 +4034,30 @@ class Edges(object): """Returns the destination node of the edge.""" @property - def properties(self): - """Returns all properties of the edges""" + def time(self): + """ + Returns the times of exploded edges + + Returns: + Time of edge + """ @property - def start(self): + def earliest_time(self): """ - Gets the start time for rolling and expanding windows for this Edges + Returns the earliest time of the edges. Returns: - Optional[int]: The earliest time that this Edges is valid or None if the Edges is valid for all times. + Earliest time of the edges. """ @property - def date_time(self): + def earliest_date_time(self): """ - Returns the date times of exploded edges + Returns the earliest date time of the edges. Returns: - A list of date times. + Earliest date time of the edges. """ @property @@ -4047,31 +4070,18 @@ class Edges(object): """ @property - def id(self): - """Returns all ids of the edges.""" - - @property - def end_date_time(self): - """ - Gets the latest datetime that this Edges is valid - - Returns: - Optional[Datetime]: The latest datetime that this Edges is valid or None if the Edges is valid for all times. - """ + def properties(self): + """Returns all properties of the edges""" @property - def earliest_time(self): + def layer_names(self): """ - Returns the earliest time of the edges. + Get the layer names that all edges belong to - assuming they only belong to one layer Returns: - Earliest time of the edges. + A list of layer names """ - @property - def nbr(self): - """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" - @property def end(self): """ @@ -4082,22 +4092,12 @@ class Edges(object): """ @property - def layer_name(self): - """ - Get the layer name that all edges belong to - assuming they only belong to one layer - - Returns: - The name of the layer - """ + def id(self): + """Returns all ids of the edges.""" @property - def earliest_date_time(self): - """ - Returns the earliest date time of the edges. - - Returns: - Earliest date time of the edges. - """ + def src(self): + """Returns the source node of the edge.""" class MutableEdge(Edge): def __repr__(self): @@ -4223,14 +4223,14 @@ class Properties(object): def as_dict(self): """Convert properties view to a dict""" - @property - def constant(self): - """Get a view of the constant properties (meta-data) only.""" - @property def temporal(self): """Get a view of the temporal properties only.""" + @property + def constant(self): + """Get a view of the constant properties (meta-data) only.""" + class ConstantProperties(object): """A view of constant properties of an entity""" diff --git a/python/python/raphtory/node_state/__init__.pyi b/python/python/raphtory/node_state/__init__.pyi index 5de6dcbc5c..7cd55d8e13 100644 --- a/python/python/raphtory/node_state/__init__.pyi +++ b/python/python/raphtory/node_state/__init__.pyi @@ -291,23 +291,23 @@ class DegreeView(object): """ - def sum(self): + def sum(self) -> int: """ sum of values over all nodes Returns: - int + int: the sum """ - def mean(self): + def mean(self) -> float: """ mean of values over all nodes Returns: - float + float: mean value """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateUsize: """ Sort by value @@ -315,10 +315,10 @@ class DegreeView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateUsize + NodeStateUsize: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateUsize: """ Compute the k largest values @@ -326,10 +326,10 @@ class DegreeView(object): k (int): The number of values to return Returns: - NodeStateUsize + NodeStateUsize: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateUsize: """ Compute the k smallest values @@ -337,39 +337,39 @@ class DegreeView(object): k (int): The number of values to return Returns: - NodeStateUsize + NodeStateUsize: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, int]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[int]: """ Return the minimum value Returns: - Optional[int] + Optional[int]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, int]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[int]: """ Return the maximum value Returns: - Optional[int] + Optional[int]: The maximum value or `None` if empty """ def median(self): @@ -380,40 +380,40 @@ class DegreeView(object): Optional[int] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, int]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, int]] + Iterator[Tuple[Node, int]]: Iterator over items """ def values(self): """ Returns: - Iterator[int] + Iterator[int]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateUsize: """ Sort results by node id Returns: - NodeStateUsize + NodeStateUsize: The sorted node state """ def compute(self): @@ -429,43 +429,43 @@ class DegreeView(object): Compute all values and return the result as a list Returns - list[int] + list[int]: all values as a list """ @property - def start_date_time(self): + def end(self): """ - Gets the earliest datetime that this DegreeView is valid + Gets the latest time that this DegreeView is valid. Returns: - Optional[Datetime]: The earliest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. + Optional[int]: The latest time that this DegreeView is valid or None if the DegreeView is valid for all times. """ @property - def start(self): + def end_date_time(self): """ - Gets the start time for rolling and expanding windows for this DegreeView + Gets the latest datetime that this DegreeView is valid Returns: - Optional[int]: The earliest time that this DegreeView is valid or None if the DegreeView is valid for all times. + Optional[Datetime]: The latest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. """ @property - def end(self): + def start(self): """ - Gets the latest time that this DegreeView is valid. + Gets the start time for rolling and expanding windows for this DegreeView Returns: - Optional[int]: The latest time that this DegreeView is valid or None if the DegreeView is valid for all times. + Optional[int]: The earliest time that this DegreeView is valid or None if the DegreeView is valid for all times. """ @property - def end_date_time(self): + def start_date_time(self): """ - Gets the latest datetime that this DegreeView is valid + Gets the earliest datetime that this DegreeView is valid Returns: - Optional[Datetime]: The latest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. + Optional[Datetime]: The earliest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. """ @property @@ -516,23 +516,23 @@ class NodeStateUsize(object): NodeGroups: The grouped nodes """ - def sum(self): + def sum(self) -> int: """ sum of values over all nodes Returns: - int + int: the sum """ - def mean(self): + def mean(self) -> float: """ mean of values over all nodes Returns: - float + float: mean value """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateUsize: """ Sort by value @@ -540,10 +540,10 @@ class NodeStateUsize(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateUsize + NodeStateUsize: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateUsize: """ Compute the k largest values @@ -551,10 +551,10 @@ class NodeStateUsize(object): k (int): The number of values to return Returns: - NodeStateUsize + NodeStateUsize: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateUsize: """ Compute the k smallest values @@ -562,39 +562,39 @@ class NodeStateUsize(object): k (int): The number of values to return Returns: - NodeStateUsize + NodeStateUsize: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, int]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[int]: """ Return the minimum value Returns: - Optional[int] + Optional[int]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, int]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[int]: """ Return the maximum value Returns: - Optional[int] + Optional[int]: The maximum value or `None` if empty """ def median(self): @@ -605,40 +605,40 @@ class NodeStateUsize(object): Optional[int] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, int]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, int]] + Iterator[Tuple[Node, int]]: Iterator over items """ def values(self): """ Returns: - Iterator[int] + Iterator[int]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateUsize: """ Sort results by node id Returns: - NodeStateUsize + NodeStateUsize: The sorted node state """ class NodeStateU64(object): @@ -672,23 +672,23 @@ class NodeStateU64(object): def __getitem__(self, key): """Return self[key].""" - def sum(self): + def sum(self) -> int: """ sum of values over all nodes Returns: - int + int: the sum """ - def mean(self): + def mean(self) -> float: """ mean of values over all nodes Returns: - float + float: mean value """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateU64: """ Sort by value @@ -696,10 +696,10 @@ class NodeStateU64(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateU64 + NodeStateU64: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateU64: """ Compute the k largest values @@ -707,10 +707,10 @@ class NodeStateU64(object): k (int): The number of values to return Returns: - NodeStateU64 + NodeStateU64: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateU64: """ Compute the k smallest values @@ -718,39 +718,39 @@ class NodeStateU64(object): k (int): The number of values to return Returns: - NodeStateU64 + NodeStateU64: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, int]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[int]: """ Return the minimum value Returns: - Optional[int] + Optional[int]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, int]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[int]: """ Return the maximum value Returns: - Optional[int] + Optional[int]: The maximum value or `None` if empty """ def median(self): @@ -761,40 +761,40 @@ class NodeStateU64(object): Optional[int] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, int]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, int]] + Optional[Tuple[Node, int]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, int]] + Iterator[Tuple[Node, int]]: Iterator over items """ def values(self): """ Returns: - Iterator[int] + Iterator[int]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateU64: """ Sort results by node id Returns: - NodeStateU64 + NodeStateU64: The sorted node state """ class IdView(object): @@ -830,7 +830,7 @@ class IdView(object): def __getitem__(self, key): """Return self[key].""" - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateGID: """ Sort by value @@ -838,10 +838,10 @@ class IdView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateGID + NodeStateGID: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateGID: """ Compute the k largest values @@ -849,10 +849,10 @@ class IdView(object): k (int): The number of values to return Returns: - NodeStateGID + NodeStateGID: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateGID: """ Compute the k smallest values @@ -860,39 +860,39 @@ class IdView(object): k (int): The number of values to return Returns: - NodeStateGID + NodeStateGID: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, GID]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, GID]] + Optional[Tuple[Node, GID]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[GID]: """ Return the minimum value Returns: - Optional[GID] + Optional[GID]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, GID]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, GID]] + Optional[Tuple[Node, GID]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[GID]: """ Return the maximum value Returns: - Optional[GID] + Optional[GID]: The maximum value or `None` if empty """ def median(self): @@ -903,40 +903,40 @@ class IdView(object): Optional[GID] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, GID]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, GID]] + Optional[Tuple[Node, GID]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, GID]] + Iterator[Tuple[Node, GID]]: Iterator over items """ def values(self): """ Returns: - Iterator[GID] + Iterator[GID]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateGID: """ Sort results by node id Returns: - NodeStateGID + NodeStateGID: The sorted node state """ def compute(self): @@ -952,7 +952,7 @@ class IdView(object): Compute all values and return the result as a list Returns - list[GID] + list[GID]: all values as a list """ class NodeStateGID(object): @@ -986,7 +986,7 @@ class NodeStateGID(object): def __getitem__(self, key): """Return self[key].""" - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateGID: """ Sort by value @@ -994,10 +994,10 @@ class NodeStateGID(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateGID + NodeStateGID: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateGID: """ Compute the k largest values @@ -1005,10 +1005,10 @@ class NodeStateGID(object): k (int): The number of values to return Returns: - NodeStateGID + NodeStateGID: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateGID: """ Compute the k smallest values @@ -1016,39 +1016,39 @@ class NodeStateGID(object): k (int): The number of values to return Returns: - NodeStateGID + NodeStateGID: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, GID]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, GID]] + Optional[Tuple[Node, GID]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[GID]: """ Return the minimum value Returns: - Optional[GID] + Optional[GID]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, GID]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, GID]] + Optional[Tuple[Node, GID]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[GID]: """ Return the maximum value Returns: - Optional[GID] + Optional[GID]: The maximum value or `None` if empty """ def median(self): @@ -1059,40 +1059,40 @@ class NodeStateGID(object): Optional[GID] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, GID]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, GID]] + Optional[Tuple[Node, GID]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, GID]] + Iterator[Tuple[Node, GID]]: Iterator over items """ def values(self): """ Returns: - Iterator[GID] + Iterator[GID]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateGID: """ Sort results by node id Returns: - NodeStateGID + NodeStateGID: The sorted node state """ class EarliestTimeView(object): @@ -1377,7 +1377,7 @@ class EarliestTimeView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionI64 + NodeStateOptionI64: Sorted node state """ def top_k(self, k: int): @@ -1388,7 +1388,7 @@ class EarliestTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionI64 + NodeStateOptionI64: The k largest values as a node state """ def bottom_k(self, k: int): @@ -1399,39 +1399,39 @@ class EarliestTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionI64 + NodeStateOptionI64: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[int]]] + Optional[Tuple[Node, Optional[int]]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[Optional[int]]: """ Return the minimum value Returns: - Optional[Optional[int]] + Optional[Optional[int]]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[int]]] + Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[Optional[int]]: """ Return the maximum value Returns: - Optional[Optional[int]] + Optional[Optional[int]]: The maximum value or `None` if empty """ def median(self): @@ -1442,32 +1442,32 @@ class EarliestTimeView(object): Optional[Optional[int]] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[int]]] + Optional[Tuple[Node, Optional[int]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[int]]] + Iterator[Tuple[Node, Optional[int]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[int]] + Iterator[Optional[int]]: Iterator over values """ def sorted_by_id(self): @@ -1475,7 +1475,7 @@ class EarliestTimeView(object): Sort results by node id Returns: - NodeStateOptionI64 + NodeStateOptionI64: The sorted node state """ def compute(self): @@ -1491,25 +1491,25 @@ class EarliestTimeView(object): Compute all values and return the result as a list Returns - list[Optional[int]] + list[Optional[int]]: all values as a list """ @property - def start(self): + def start_date_time(self): """ - Gets the start time for rolling and expanding windows for this EarliestTimeView + Gets the earliest datetime that this EarliestTimeView is valid Returns: - Optional[int]: The earliest time that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + Optional[Datetime]: The earliest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ @property - def window_size(self): + def start(self): """ - Get the window size (difference between start and end) for this EarliestTimeView + Gets the start time for rolling and expanding windows for this EarliestTimeView Returns: - Optional[int] + Optional[int]: The earliest time that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ @property @@ -1522,12 +1522,12 @@ class EarliestTimeView(object): """ @property - def start_date_time(self): + def window_size(self): """ - Gets the earliest datetime that this EarliestTimeView is valid + Get the window size (difference between start and end) for this EarliestTimeView Returns: - Optional[Datetime]: The earliest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + Optional[int] """ @property @@ -1821,7 +1821,7 @@ class LatestTimeView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionI64 + NodeStateOptionI64: Sorted node state """ def top_k(self, k: int): @@ -1832,7 +1832,7 @@ class LatestTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionI64 + NodeStateOptionI64: The k largest values as a node state """ def bottom_k(self, k: int): @@ -1843,39 +1843,39 @@ class LatestTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionI64 + NodeStateOptionI64: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[int]]] + Optional[Tuple[Node, Optional[int]]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[Optional[int]]: """ Return the minimum value Returns: - Optional[Optional[int]] + Optional[Optional[int]]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[int]]] + Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[Optional[int]]: """ Return the maximum value Returns: - Optional[Optional[int]] + Optional[Optional[int]]: The maximum value or `None` if empty """ def median(self): @@ -1886,32 +1886,32 @@ class LatestTimeView(object): Optional[Optional[int]] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[int]]] + Optional[Tuple[Node, Optional[int]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[int]]] + Iterator[Tuple[Node, Optional[int]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[int]] + Iterator[Optional[int]]: Iterator over values """ def sorted_by_id(self): @@ -1919,7 +1919,7 @@ class LatestTimeView(object): Sort results by node id Returns: - NodeStateOptionI64 + NodeStateOptionI64: The sorted node state """ def compute(self): @@ -1935,16 +1935,7 @@ class LatestTimeView(object): Compute all values and return the result as a list Returns - list[Optional[int]] - """ - - @property - def start(self): - """ - Gets the start time for rolling and expanding windows for this LatestTimeView - - Returns: - Optional[int]: The earliest time that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + list[Optional[int]]: all values as a list """ @property @@ -1957,12 +1948,12 @@ class LatestTimeView(object): """ @property - def window_size(self): + def start_date_time(self): """ - Get the window size (difference between start and end) for this LatestTimeView + Gets the earliest datetime that this LatestTimeView is valid Returns: - Optional[int] + Optional[Datetime]: The earliest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. """ @property @@ -1975,12 +1966,21 @@ class LatestTimeView(object): """ @property - def start_date_time(self): + def start(self): """ - Gets the earliest datetime that this LatestTimeView is valid + Gets the start time for rolling and expanding windows for this LatestTimeView Returns: - Optional[Datetime]: The earliest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + Optional[int]: The earliest time that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + """ + + @property + def window_size(self): + """ + Get the window size (difference between start and end) for this LatestTimeView + + Returns: + Optional[int] """ class NameView(object): @@ -2024,7 +2024,7 @@ class NameView(object): NodeGroups: The grouped nodes """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateString: """ Sort by value @@ -2032,10 +2032,10 @@ class NameView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateString + NodeStateString: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateString: """ Compute the k largest values @@ -2043,10 +2043,10 @@ class NameView(object): k (int): The number of values to return Returns: - NodeStateString + NodeStateString: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateString: """ Compute the k smallest values @@ -2054,39 +2054,39 @@ class NameView(object): k (int): The number of values to return Returns: - NodeStateString + NodeStateString: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, str]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, str]] + Optional[Tuple[Node, str]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[str]: """ Return the minimum value Returns: - Optional[str] + Optional[str]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, str]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, str]] + Optional[Tuple[Node, str]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[str]: """ Return the maximum value Returns: - Optional[str] + Optional[str]: The maximum value or `None` if empty """ def median(self): @@ -2097,40 +2097,40 @@ class NameView(object): Optional[str] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, str]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, str]] + Optional[Tuple[Node, str]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, str]] + Iterator[Tuple[Node, str]]: Iterator over items """ def values(self): """ Returns: - Iterator[str] + Iterator[str]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateString: """ Sort results by node id Returns: - NodeStateString + NodeStateString: The sorted node state """ def compute(self): @@ -2146,7 +2146,7 @@ class NameView(object): Compute all values and return the result as a list Returns - list[str] + list[str]: all values as a list """ class NodeStateString(object): @@ -2188,7 +2188,7 @@ class NodeStateString(object): NodeGroups: The grouped nodes """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateString: """ Sort by value @@ -2196,10 +2196,10 @@ class NodeStateString(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateString + NodeStateString: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateString: """ Compute the k largest values @@ -2207,10 +2207,10 @@ class NodeStateString(object): k (int): The number of values to return Returns: - NodeStateString + NodeStateString: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateString: """ Compute the k smallest values @@ -2218,39 +2218,39 @@ class NodeStateString(object): k (int): The number of values to return Returns: - NodeStateString + NodeStateString: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, str]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, str]] + Optional[Tuple[Node, str]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[str]: """ Return the minimum value Returns: - Optional[str] + Optional[str]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, str]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, str]] + Optional[Tuple[Node, str]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[str]: """ Return the maximum value Returns: - Optional[str] + Optional[str]: The maximum value or `None` if empty """ def median(self): @@ -2261,40 +2261,40 @@ class NodeStateString(object): Optional[str] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, str]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, str]] + Optional[Tuple[Node, str]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, str]] + Iterator[Tuple[Node, str]]: Iterator over items """ def values(self): """ Returns: - Iterator[str] + Iterator[str]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateString: """ Sort results by node id Returns: - NodeStateString + NodeStateString: The sorted node state """ class EarliestDateTimeView(object): @@ -2571,7 +2571,7 @@ class EarliestDateTimeView(object): """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: """ Sort by value @@ -2579,10 +2579,10 @@ class EarliestDateTimeView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateOptionDateTime: """ Compute the k largest values @@ -2590,10 +2590,10 @@ class EarliestDateTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateOptionDateTime: """ Compute the k smallest values @@ -2601,7 +2601,7 @@ class EarliestDateTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The k smallest values as a node state """ def min_item(self): @@ -2609,7 +2609,7 @@ class EarliestDateTimeView(object): Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The Node and minimum value or `None` if empty """ def min(self): @@ -2617,7 +2617,7 @@ class EarliestDateTimeView(object): Return the minimum value Returns: - Optional[Optional[Datetime]] + Optional[Optional[Datetime]]: The minimum value or `None` if empty """ def max_item(self): @@ -2625,7 +2625,7 @@ class EarliestDateTimeView(object): Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The Node and maximum value or `None` if empty """ def max(self): @@ -2633,7 +2633,7 @@ class EarliestDateTimeView(object): Return the maximum value Returns: - Optional[Optional[Datetime]] + Optional[Optional[Datetime]]: The maximum value or `None` if empty """ def median(self): @@ -2646,38 +2646,38 @@ class EarliestDateTimeView(object): def median_item(self): """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[Datetime]]] + Iterator[Tuple[Node, Optional[Datetime]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[Datetime]] + Iterator[Optional[Datetime]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateOptionDateTime: """ Sort results by node id Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The sorted node state """ def compute(self): @@ -2693,52 +2693,52 @@ class EarliestDateTimeView(object): Compute all values and return the result as a list Returns - list[Optional[Datetime]] + list[Optional[Datetime]]: all values as a list """ @property - def end_date_time(self): + def window_size(self): """ - Gets the latest datetime that this EarliestDateTimeView is valid + Get the window size (difference between start and end) for this EarliestDateTimeView Returns: - Optional[Datetime]: The latest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[int] """ @property - def start_date_time(self): + def start(self): """ - Gets the earliest datetime that this EarliestDateTimeView is valid + Gets the start time for rolling and expanding windows for this EarliestDateTimeView Returns: - Optional[Datetime]: The earliest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[int]: The earliest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ @property - def end(self): + def start_date_time(self): """ - Gets the latest time that this EarliestDateTimeView is valid. + Gets the earliest datetime that this EarliestDateTimeView is valid Returns: - Optional[int]: The latest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[Datetime]: The earliest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ @property - def window_size(self): + def end_date_time(self): """ - Get the window size (difference between start and end) for this EarliestDateTimeView + Gets the latest datetime that this EarliestDateTimeView is valid Returns: - Optional[int] + Optional[Datetime]: The latest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ @property - def start(self): + def end(self): """ - Gets the start time for rolling and expanding windows for this EarliestDateTimeView + Gets the latest time that this EarliestDateTimeView is valid. Returns: - Optional[int]: The earliest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[int]: The latest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ class LatestDateTimeView(object): @@ -3015,7 +3015,7 @@ class LatestDateTimeView(object): """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: """ Sort by value @@ -3023,10 +3023,10 @@ class LatestDateTimeView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateOptionDateTime: """ Compute the k largest values @@ -3034,10 +3034,10 @@ class LatestDateTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateOptionDateTime: """ Compute the k smallest values @@ -3045,7 +3045,7 @@ class LatestDateTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The k smallest values as a node state """ def min_item(self): @@ -3053,7 +3053,7 @@ class LatestDateTimeView(object): Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The Node and minimum value or `None` if empty """ def min(self): @@ -3061,7 +3061,7 @@ class LatestDateTimeView(object): Return the minimum value Returns: - Optional[Optional[Datetime]] + Optional[Optional[Datetime]]: The minimum value or `None` if empty """ def max_item(self): @@ -3069,7 +3069,7 @@ class LatestDateTimeView(object): Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The Node and maximum value or `None` if empty """ def max(self): @@ -3077,7 +3077,7 @@ class LatestDateTimeView(object): Return the maximum value Returns: - Optional[Optional[Datetime]] + Optional[Optional[Datetime]]: The maximum value or `None` if empty """ def median(self): @@ -3090,38 +3090,38 @@ class LatestDateTimeView(object): def median_item(self): """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[Datetime]]] + Iterator[Tuple[Node, Optional[Datetime]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[Datetime]] + Iterator[Optional[Datetime]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateOptionDateTime: """ Sort results by node id Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The sorted node state """ def compute(self): @@ -3137,52 +3137,52 @@ class LatestDateTimeView(object): Compute all values and return the result as a list Returns - list[Optional[Datetime]] + list[Optional[Datetime]]: all values as a list """ @property - def end_date_time(self): + def window_size(self): """ - Gets the latest datetime that this LatestDateTimeView is valid + Get the window size (difference between start and end) for this LatestDateTimeView Returns: - Optional[Datetime]: The latest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + Optional[int] """ @property - def start_date_time(self): + def end(self): """ - Gets the earliest datetime that this LatestDateTimeView is valid + Gets the latest time that this LatestDateTimeView is valid. Returns: - Optional[Datetime]: The earliest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + Optional[int]: The latest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ @property - def start(self): + def start_date_time(self): """ - Gets the start time for rolling and expanding windows for this LatestDateTimeView + Gets the earliest datetime that this LatestDateTimeView is valid Returns: - Optional[int]: The earliest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + Optional[Datetime]: The earliest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ @property - def end(self): + def end_date_time(self): """ - Gets the latest time that this LatestDateTimeView is valid. + Gets the latest datetime that this LatestDateTimeView is valid Returns: - Optional[int]: The latest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + Optional[Datetime]: The latest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ @property - def window_size(self): + def start(self): """ - Get the window size (difference between start and end) for this LatestDateTimeView + Gets the start time for rolling and expanding windows for this LatestDateTimeView Returns: - Optional[int] + Optional[int]: The earliest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ class NodeStateOptionDateTime(object): @@ -3224,7 +3224,7 @@ class NodeStateOptionDateTime(object): NodeGroups: The grouped nodes """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: """ Sort by value @@ -3232,10 +3232,10 @@ class NodeStateOptionDateTime(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateOptionDateTime: """ Compute the k largest values @@ -3243,10 +3243,10 @@ class NodeStateOptionDateTime(object): k (int): The number of values to return Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateOptionDateTime: """ Compute the k smallest values @@ -3254,7 +3254,7 @@ class NodeStateOptionDateTime(object): k (int): The number of values to return Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The k smallest values as a node state """ def min_item(self): @@ -3262,7 +3262,7 @@ class NodeStateOptionDateTime(object): Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The Node and minimum value or `None` if empty """ def min(self): @@ -3270,7 +3270,7 @@ class NodeStateOptionDateTime(object): Return the minimum value Returns: - Optional[Optional[Datetime]] + Optional[Optional[Datetime]]: The minimum value or `None` if empty """ def max_item(self): @@ -3278,7 +3278,7 @@ class NodeStateOptionDateTime(object): Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The Node and maximum value or `None` if empty """ def max(self): @@ -3286,7 +3286,7 @@ class NodeStateOptionDateTime(object): Return the maximum value Returns: - Optional[Optional[Datetime]] + Optional[Optional[Datetime]]: The maximum value or `None` if empty """ def median(self): @@ -3299,38 +3299,38 @@ class NodeStateOptionDateTime(object): def median_item(self): """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]] + Optional[Tuple[Node, Optional[Datetime]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[Datetime]]] + Iterator[Tuple[Node, Optional[Datetime]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[Datetime]] + Iterator[Optional[Datetime]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateOptionDateTime: """ Sort results by node id Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: The sorted node state """ class HistoryView(object): @@ -3599,7 +3599,7 @@ class HistoryView(object): """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateListI64: """ Sort by value @@ -3607,10 +3607,10 @@ class HistoryView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateListI64 + NodeStateListI64: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateListI64: """ Compute the k largest values @@ -3618,10 +3618,10 @@ class HistoryView(object): k (int): The number of values to return Returns: - NodeStateListI64 + NodeStateListI64: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateListI64: """ Compute the k smallest values @@ -3629,39 +3629,39 @@ class HistoryView(object): k (int): The number of values to return Returns: - NodeStateListI64 + NodeStateListI64: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, list[int]]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, list[int]]] + Optional[Tuple[Node, list[int]]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[list[int]]: """ Return the minimum value Returns: - Optional[list[int]] + Optional[list[int]]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, list[int]]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, list[int]]] + Optional[Tuple[Node, list[int]]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[list[int]]: """ Return the maximum value Returns: - Optional[list[int]] + Optional[list[int]]: The maximum value or `None` if empty """ def median(self): @@ -3672,40 +3672,40 @@ class HistoryView(object): Optional[list[int]] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, list[int]]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, list[int]]] + Optional[Tuple[Node, list[int]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, list[int]]] + Iterator[Tuple[Node, list[int]]]: Iterator over items """ def values(self): """ Returns: - Iterator[list[int]] + Iterator[list[int]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateListI64: """ Sort results by node id Returns: - NodeStateListI64 + NodeStateListI64: The sorted node state """ def compute(self): @@ -3721,25 +3721,25 @@ class HistoryView(object): Compute all values and return the result as a list Returns - list[list[int]] + list[list[int]]: all values as a list """ @property - def start(self): + def end_date_time(self): """ - Gets the start time for rolling and expanding windows for this HistoryView + Gets the latest datetime that this HistoryView is valid Returns: - Optional[int]: The earliest time that this HistoryView is valid or None if the HistoryView is valid for all times. + Optional[Datetime]: The latest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. """ @property - def window_size(self): + def start_date_time(self): """ - Get the window size (difference between start and end) for this HistoryView + Gets the earliest datetime that this HistoryView is valid Returns: - Optional[int] + Optional[Datetime]: The earliest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. """ @property @@ -3752,21 +3752,21 @@ class HistoryView(object): """ @property - def start_date_time(self): + def start(self): """ - Gets the earliest datetime that this HistoryView is valid + Gets the start time for rolling and expanding windows for this HistoryView Returns: - Optional[Datetime]: The earliest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. + Optional[int]: The earliest time that this HistoryView is valid or None if the HistoryView is valid for all times. """ @property - def end_date_time(self): + def window_size(self): """ - Gets the latest datetime that this HistoryView is valid + Get the window size (difference between start and end) for this HistoryView Returns: - Optional[Datetime]: The latest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. + Optional[int] """ class NodeStateListI64(object): @@ -3800,7 +3800,7 @@ class NodeStateListI64(object): def __getitem__(self, key): """Return self[key].""" - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateListI64: """ Sort by value @@ -3808,10 +3808,10 @@ class NodeStateListI64(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateListI64 + NodeStateListI64: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateListI64: """ Compute the k largest values @@ -3819,10 +3819,10 @@ class NodeStateListI64(object): k (int): The number of values to return Returns: - NodeStateListI64 + NodeStateListI64: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateListI64: """ Compute the k smallest values @@ -3830,39 +3830,39 @@ class NodeStateListI64(object): k (int): The number of values to return Returns: - NodeStateListI64 + NodeStateListI64: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, list[int]]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, list[int]]] + Optional[Tuple[Node, list[int]]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[list[int]]: """ Return the minimum value Returns: - Optional[list[int]] + Optional[list[int]]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, list[int]]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, list[int]]] + Optional[Tuple[Node, list[int]]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[list[int]]: """ Return the maximum value Returns: - Optional[list[int]] + Optional[list[int]]: The maximum value or `None` if empty """ def median(self): @@ -3873,40 +3873,40 @@ class NodeStateListI64(object): Optional[list[int]] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, list[int]]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, list[int]]] + Optional[Tuple[Node, list[int]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, list[int]]] + Iterator[Tuple[Node, list[int]]]: Iterator over items """ def values(self): """ Returns: - Iterator[list[int]] + Iterator[list[int]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateListI64: """ Sort results by node id Returns: - NodeStateListI64 + NodeStateListI64: The sorted node state """ class HistoryDateTimeView(object): @@ -4175,7 +4175,7 @@ class HistoryDateTimeView(object): """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateOptionListDateTime: """ Sort by value @@ -4183,10 +4183,10 @@ class HistoryDateTimeView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateOptionListDateTime: """ Compute the k largest values @@ -4194,10 +4194,10 @@ class HistoryDateTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateOptionListDateTime: """ Compute the k smallest values @@ -4205,7 +4205,7 @@ class HistoryDateTimeView(object): k (int): The number of values to return Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: The k smallest values as a node state """ def min_item(self): @@ -4213,7 +4213,7 @@ class HistoryDateTimeView(object): Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]] + Optional[Tuple[Node, Optional[list[Datetime]]]]: The Node and minimum value or `None` if empty """ def min(self): @@ -4221,7 +4221,7 @@ class HistoryDateTimeView(object): Return the minimum value Returns: - Optional[Optional[list[Datetime]]] + Optional[Optional[list[Datetime]]]: The minimum value or `None` if empty """ def max_item(self): @@ -4229,7 +4229,7 @@ class HistoryDateTimeView(object): Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]] + Optional[Tuple[Node, Optional[list[Datetime]]]]: The Node and maximum value or `None` if empty """ def max(self): @@ -4237,7 +4237,7 @@ class HistoryDateTimeView(object): Return the maximum value Returns: - Optional[Optional[list[Datetime]]] + Optional[Optional[list[Datetime]]]: The maximum value or `None` if empty """ def median(self): @@ -4250,38 +4250,38 @@ class HistoryDateTimeView(object): def median_item(self): """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]] + Optional[Tuple[Node, Optional[list[Datetime]]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[list[Datetime]]]] + Iterator[Tuple[Node, Optional[list[Datetime]]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[list[Datetime]]] + Iterator[Optional[list[Datetime]]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateOptionListDateTime: """ Sort results by node id Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: The sorted node state """ def compute(self): @@ -4297,16 +4297,16 @@ class HistoryDateTimeView(object): Compute all values and return the result as a list Returns - list[Optional[list[Datetime]]] + list[Optional[list[Datetime]]]: all values as a list """ @property - def window_size(self): + def end(self): """ - Get the window size (difference between start and end) for this HistoryDateTimeView + Gets the latest time that this HistoryDateTimeView is valid. Returns: - Optional[int] + Optional[int]: The latest time that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ @property @@ -4319,30 +4319,30 @@ class HistoryDateTimeView(object): """ @property - def start_date_time(self): + def end_date_time(self): """ - Gets the earliest datetime that this HistoryDateTimeView is valid + Gets the latest datetime that this HistoryDateTimeView is valid Returns: - Optional[Datetime]: The earliest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + Optional[Datetime]: The latest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ @property - def end(self): + def start_date_time(self): """ - Gets the latest time that this HistoryDateTimeView is valid. + Gets the earliest datetime that this HistoryDateTimeView is valid Returns: - Optional[int]: The latest time that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + Optional[Datetime]: The earliest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ @property - def end_date_time(self): + def window_size(self): """ - Gets the latest datetime that this HistoryDateTimeView is valid + Get the window size (difference between start and end) for this HistoryDateTimeView Returns: - Optional[Datetime]: The latest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + Optional[int] """ class NodeStateOptionListDateTime(object): @@ -4376,7 +4376,7 @@ class NodeStateOptionListDateTime(object): def __getitem__(self, key): """Return self[key].""" - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateOptionListDateTime: """ Sort by value @@ -4384,10 +4384,10 @@ class NodeStateOptionListDateTime(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateOptionListDateTime: """ Compute the k largest values @@ -4395,10 +4395,10 @@ class NodeStateOptionListDateTime(object): k (int): The number of values to return Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateOptionListDateTime: """ Compute the k smallest values @@ -4406,7 +4406,7 @@ class NodeStateOptionListDateTime(object): k (int): The number of values to return Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: The k smallest values as a node state """ def min_item(self): @@ -4414,7 +4414,7 @@ class NodeStateOptionListDateTime(object): Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]] + Optional[Tuple[Node, Optional[list[Datetime]]]]: The Node and minimum value or `None` if empty """ def min(self): @@ -4422,7 +4422,7 @@ class NodeStateOptionListDateTime(object): Return the minimum value Returns: - Optional[Optional[list[Datetime]]] + Optional[Optional[list[Datetime]]]: The minimum value or `None` if empty """ def max_item(self): @@ -4430,7 +4430,7 @@ class NodeStateOptionListDateTime(object): Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]] + Optional[Tuple[Node, Optional[list[Datetime]]]]: The Node and maximum value or `None` if empty """ def max(self): @@ -4438,7 +4438,7 @@ class NodeStateOptionListDateTime(object): Return the maximum value Returns: - Optional[Optional[list[Datetime]]] + Optional[Optional[list[Datetime]]]: The maximum value or `None` if empty """ def median(self): @@ -4451,38 +4451,38 @@ class NodeStateOptionListDateTime(object): def median_item(self): """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]] + Optional[Tuple[Node, Optional[list[Datetime]]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[list[Datetime]]]] + Iterator[Tuple[Node, Optional[list[Datetime]]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[list[Datetime]]] + Iterator[Optional[list[Datetime]]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateOptionListDateTime: """ Sort results by node id Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: The sorted node state """ class NodeTypeView(object): @@ -4526,7 +4526,7 @@ class NodeTypeView(object): NodeGroups: The grouped nodes """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateOptionStr: """ Sort by value @@ -4534,10 +4534,10 @@ class NodeTypeView(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionStr + NodeStateOptionStr: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateOptionStr: """ Compute the k largest values @@ -4545,10 +4545,10 @@ class NodeTypeView(object): k (int): The number of values to return Returns: - NodeStateOptionStr + NodeStateOptionStr: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateOptionStr: """ Compute the k smallest values @@ -4556,39 +4556,39 @@ class NodeTypeView(object): k (int): The number of values to return Returns: - NodeStateOptionStr + NodeStateOptionStr: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[str]]] + Optional[Tuple[Node, Optional[str]]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[Optional[str]]: """ Return the minimum value Returns: - Optional[Optional[str]] + Optional[Optional[str]]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[str]]] + Optional[Tuple[Node, Optional[str]]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[Optional[str]]: """ Return the maximum value Returns: - Optional[Optional[str]] + Optional[Optional[str]]: The maximum value or `None` if empty """ def median(self): @@ -4599,40 +4599,40 @@ class NodeTypeView(object): Optional[Optional[str]] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[str]]] + Optional[Tuple[Node, Optional[str]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[str]]] + Iterator[Tuple[Node, Optional[str]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[str]] + Iterator[Optional[str]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateOptionStr: """ Sort results by node id Returns: - NodeStateOptionStr + NodeStateOptionStr: The sorted node state """ def compute(self): @@ -4648,7 +4648,7 @@ class NodeTypeView(object): Compute all values and return the result as a list Returns - list[Optional[str]] + list[Optional[str]]: all values as a list """ class NodeStateOptionStr(object): @@ -4690,7 +4690,7 @@ class NodeStateOptionStr(object): NodeGroups: The grouped nodes """ - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateOptionStr: """ Sort by value @@ -4698,10 +4698,10 @@ class NodeStateOptionStr(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionStr + NodeStateOptionStr: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateOptionStr: """ Compute the k largest values @@ -4709,10 +4709,10 @@ class NodeStateOptionStr(object): k (int): The number of values to return Returns: - NodeStateOptionStr + NodeStateOptionStr: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateOptionStr: """ Compute the k smallest values @@ -4720,39 +4720,39 @@ class NodeStateOptionStr(object): k (int): The number of values to return Returns: - NodeStateOptionStr + NodeStateOptionStr: The k smallest values as a node state """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[str]]] + Optional[Tuple[Node, Optional[str]]]: The Node and minimum value or `None` if empty """ - def min(self): + def min(self) -> Optional[Optional[str]]: """ Return the minimum value Returns: - Optional[Optional[str]] + Optional[Optional[str]]: The minimum value or `None` if empty """ - def max_item(self): + def max_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ Return largest value and corresponding node Returns: - Optional[Tuple[Node, Optional[str]]] + Optional[Tuple[Node, Optional[str]]]: The Node and maximum value or `None` if empty """ - def max(self): + def max(self) -> Optional[Optional[str]]: """ Return the maximum value Returns: - Optional[Optional[str]] + Optional[Optional[str]]: The maximum value or `None` if empty """ def median(self): @@ -4763,40 +4763,40 @@ class NodeStateOptionStr(object): Optional[Optional[str]] """ - def median_item(self): + def median_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[str]]] + Optional[Tuple[Node, Optional[str]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, Optional[str]]] + Iterator[Tuple[Node, Optional[str]]]: Iterator over items """ def values(self): """ Returns: - Iterator[Optional[str]] + Iterator[Optional[str]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateOptionStr: """ Sort results by node id Returns: - NodeStateOptionStr + NodeStateOptionStr: The sorted node state """ class NodeStateListDateTime(object): @@ -4830,7 +4830,7 @@ class NodeStateListDateTime(object): def __getitem__(self, key): """Return self[key].""" - def sorted(self, reverse: bool = False): + def sorted(self, reverse: bool = False) -> NodeStateListDateTime: """ Sort by value @@ -4838,10 +4838,10 @@ class NodeStateListDateTime(object): reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateListDateTime + NodeStateListDateTime: Sorted node state """ - def top_k(self, k: int): + def top_k(self, k: int) -> NodeStateListDateTime: """ Compute the k largest values @@ -4849,10 +4849,10 @@ class NodeStateListDateTime(object): k (int): The number of values to return Returns: - NodeStateListDateTime + NodeStateListDateTime: The k largest values as a node state """ - def bottom_k(self, k: int): + def bottom_k(self, k: int) -> NodeStateListDateTime: """ Compute the k smallest values @@ -4860,7 +4860,7 @@ class NodeStateListDateTime(object): k (int): The number of values to return Returns: - NodeStateListDateTime + NodeStateListDateTime: The k smallest values as a node state """ def min_item(self): @@ -4868,7 +4868,7 @@ class NodeStateListDateTime(object): Return smallest value and corresponding node Returns: - Optional[Tuple[Node, list[Datetime]]] + Optional[Tuple[Node, list[Datetime]]]: The Node and minimum value or `None` if empty """ def min(self): @@ -4876,7 +4876,7 @@ class NodeStateListDateTime(object): Return the minimum value Returns: - Optional[list[Datetime]] + Optional[list[Datetime]]: The minimum value or `None` if empty """ def max_item(self): @@ -4884,7 +4884,7 @@ class NodeStateListDateTime(object): Return largest value and corresponding node Returns: - Optional[Tuple[Node, list[Datetime]]] + Optional[Tuple[Node, list[Datetime]]]: The Node and maximum value or `None` if empty """ def max(self): @@ -4892,7 +4892,7 @@ class NodeStateListDateTime(object): Return the maximum value Returns: - Optional[list[Datetime]] + Optional[list[Datetime]]: The maximum value or `None` if empty """ def median(self): @@ -4905,36 +4905,36 @@ class NodeStateListDateTime(object): def median_item(self): """ - Return medain value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, list[Datetime]]] + Optional[Tuple[Node, list[Datetime]]]: The median value or `None` if empty """ - def nodes(self): + def nodes(self) -> Nodes: """ Iterate over nodes Returns: - Iterator[Node] + Nodes: The nodes """ def items(self): """ Returns: - Iterator[Tuple[Node, list[Datetime]]] + Iterator[Tuple[Node, list[Datetime]]]: Iterator over items """ def values(self): """ Returns: - Iterator[list[Datetime]] + Iterator[list[Datetime]]: Iterator over values """ - def sorted_by_id(self): + def sorted_by_id(self) -> NodeStateListDateTime: """ Sort results by node id Returns: - NodeStateListDateTime + NodeStateListDateTime: The sorted node state """ diff --git a/python/python/raphtory/vectors/__init__.pyi b/python/python/raphtory/vectors/__init__.pyi index 05916193ce..bd0b523fa5 100644 --- a/python/python/raphtory/vectors/__init__.pyi +++ b/python/python/raphtory/vectors/__init__.pyi @@ -104,13 +104,13 @@ class Document(object): """Return repr(self).""" @property - def content(self): ... + def life(self): ... @property def entity(self): ... @property - def life(self): ... - @property def embedding(self): ... + @property + def content(self): ... class VectorSelection(object): def nodes(self): diff --git a/raphtory/src/algorithms/metrics/balance.rs b/raphtory/src/algorithms/metrics/balance.rs index 7eec5ca211..b5d98e0105 100644 --- a/raphtory/src/algorithms/metrics/balance.rs +++ b/raphtory/src/algorithms/metrics/balance.rs @@ -9,6 +9,7 @@ use crate::{ accumulator_id::accumulators::sum, compute_state::{ComputeState, ComputeStateVec}, }, + utils::errors::GraphError, Direction, }, db::{ @@ -23,7 +24,6 @@ use crate::{ prelude::{EdgeViewOps, GraphViewOps, NodeViewOps}, }; use ordered_float::OrderedFloat; -use raphtory_api::core::PropType; /// Computes the net sum of weights for a given node based on edge direction. /// @@ -103,13 +103,12 @@ pub fn balance( name: String, direction: Direction, threads: Option, -) -> Result>, &'static str> { +) -> Result>, GraphError> { let mut ctx: Context = graph.into(); let min = sum(0); ctx.agg(min); - let mut weight_type = Some(PropType::U8); - weight_type = match graph.edge_meta().temporal_prop_meta().get_id(&name) { + let weight_type = match graph.edge_meta().temporal_prop_meta().get_id(&name) { Some(weight_id) => graph.edge_meta().temporal_prop_meta().get_dtype(weight_id), None => graph .edge_meta() @@ -123,10 +122,19 @@ pub fn balance( .unwrap() }), }; - if weight_type.is_none() { - return Err("Weight property not found on edges"); - } else if weight_type.unwrap().is_numeric() == false { - return Err("Weight property is not numeric"); + match weight_type { + None => { + return Err(GraphError::InvalidProperty { + reason: "Edge property {name} does not exist".to_string(), + }) + } + Some(weight_type) => { + if !weight_type.is_numeric() { + return Err(GraphError::InvalidProperty { + reason: "Edge property {name} is not numeric".to_string(), + }); + } + } } let step1 = ATask::new(move |evv| { diff --git a/raphtory/src/core/utils/errors.rs b/raphtory/src/core/utils/errors.rs index dd3dd3238b..e87c7538d4 100644 --- a/raphtory/src/core/utils/errors.rs +++ b/raphtory/src/core/utils/errors.rs @@ -125,6 +125,9 @@ pub enum GraphError { #[error("PropertyType Error: {0}")] PropertyTypeError(#[from] PropError), + #[error("{reason}")] + InvalidProperty { reason: String }, + #[error("Tried to mutate constant property {name}: old value {old:?}, new value {new:?}")] ConstantPropertyMutationError { name: ArcStr, old: Prop, new: Prop }, diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index 693abaddb6..3ace5fa51f 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -5,8 +5,7 @@ use crate::{ }, prelude::{GraphViewOps, NodeStateOps}, }; -use raphtory_api::{core::entities::VID, iter::BoxedLIter}; -use rayon::prelude::*; +use raphtory_api::core::entities::VID; use std::{collections::HashMap, hash::Hash, sync::Arc}; #[derive(Clone, Debug)] diff --git a/raphtory/src/db/api/state/lazy_node_state.rs b/raphtory/src/db/api/state/lazy_node_state.rs index 71d5b57416..90af73a3b3 100644 --- a/raphtory/src/db/api/state/lazy_node_state.rs +++ b/raphtory/src/db/api/state/lazy_node_state.rs @@ -16,10 +16,7 @@ use crate::{ prelude::*, }; use rayon::prelude::*; -use std::{ - fmt::{Debug, Formatter}, - sync::Arc, -}; +use std::fmt::{Debug, Formatter}; #[derive(Clone)] pub struct LazyNodeState<'graph, Op, G, GH = G> { diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index f84e5972cf..7ba019671a 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -1,10 +1,7 @@ use crate::{ core::entities::nodes::node_ref::AsNodeRef, db::{ - api::{ - state::{group_by::NodeGroups, node_state::NodeState, node_state_ord_ops, Index}, - view::internal::CoreGraphOps, - }, + api::state::{group_by::NodeGroups, node_state::NodeState, node_state_ord_ops, Index}, graph::{node::NodeView, nodes::Nodes}, }, prelude::{GraphViewOps, NodeViewOps}, diff --git a/raphtory/src/python/graph/node.rs b/raphtory/src/python/graph/node.rs index 37b1147a4e..f1c2932fa4 100644 --- a/raphtory/src/python/graph/node.rs +++ b/raphtory/src/python/graph/node.rs @@ -13,7 +13,7 @@ use crate::{ state::{ops, LazyNodeState, NodeStateOps}, view::{ internal::{ - CoreGraphOps, DynOrMutableGraph, DynamicGraph, Immutable, IntoDynamic, + CoreGraphOps, DynOrMutableGraph, DynamicGraph, IntoDynamic, IntoDynamicOrMutable, MaterializedGraph, }, *, @@ -23,10 +23,9 @@ use crate::{ node::NodeView, nodes::Nodes, path::{PathFromGraph, PathFromNode}, - views::{deletion_graph::PersistentGraph, property_filter::internal::*}, + views::property_filter::internal::*, }, }, - prelude::Graph, python::{ graph::{ node::internal::OneHopFilter, diff --git a/raphtory/src/python/graph/node_state/group_by.rs b/raphtory/src/python/graph/node_state/group_by.rs index b667ab335e..f4f100e6df 100644 --- a/raphtory/src/python/graph/node_state/group_by.rs +++ b/raphtory/src/python/graph/node_state/group_by.rs @@ -1,15 +1,12 @@ use crate::{ - db::{ - api::{ - state::NodeGroups, - view::{internal::IntoDynamicOrMutable, DynamicGraph, IntoDynamic, StaticGraphViewOps}, - }, - graph::{nodes::Nodes, views::node_subgraph::NodeSubgraph}, + db::api::{ + state::NodeGroups, + view::{internal::IntoDynamicOrMutable, DynamicGraph, IntoDynamic, StaticGraphViewOps}, }, python::utils::PyGenericIterator, }; use pyo3::{exceptions::PyIndexError, prelude::*, IntoPyObjectExt}; -use std::{hash::Hash, sync::Arc}; +use std::hash::Hash; trait PyNodeGroupOps: Send + Sync + 'static { fn iter(&self) -> PyGenericIterator; diff --git a/raphtory/src/python/graph/node_state/node_state.rs b/raphtory/src/python/graph/node_state/node_state.rs index bf1cc1438c..9cce6a9a66 100644 --- a/raphtory/src/python/graph/node_state/node_state.rs +++ b/raphtory/src/python/graph/node_state/node_state.rs @@ -12,14 +12,14 @@ use crate::{ StaticGraphViewOps, }, }, - graph::node::NodeView, + graph::{node::NodeView, nodes::Nodes}, }, prelude::*, py_borrowing_iter, python::{ graph::node_state::group_by::PyNodeGroups, types::{repr::Repr, wrappers::iterators::PyBorrowingIterator}, - utils::{PyGenericIterator, PyNodeRef}, + utils::PyNodeRef, }, }; use chrono::{DateTime, Utc}; @@ -48,9 +48,9 @@ macro_rules! impl_node_state_ops { /// Iterate over nodes /// /// Returns: - /// Iterator[Node] - fn nodes(&self) -> PyGenericIterator { - self.inner.nodes().into_iter().into() + /// Nodes: The nodes + fn nodes(&self) -> Nodes<'static, DynamicGraph> { + self.inner.nodes() } fn __iter__(&self) -> PyBorrowingIterator { @@ -81,7 +81,7 @@ macro_rules! impl_node_state_ops { } /// Returns: - #[doc = concat!(" Iterator[Tuple[Node, ", $py_value, "]]")] + #[doc = concat!(" Iterator[Tuple[Node, ", $py_value, "]]: Iterator over items")] fn items(&self) -> PyBorrowingIterator { py_borrowing_iter!(self.inner.clone(), $inner_t, |inner| inner .iter() @@ -89,7 +89,7 @@ macro_rules! impl_node_state_ops { } /// Returns: - #[doc = concat!(" Iterator[",$py_value, "]")] + #[doc = concat!(" Iterator[",$py_value, "]: Iterator over values")] fn values(&self) -> PyBorrowingIterator { self.__iter__() } @@ -97,7 +97,7 @@ macro_rules! impl_node_state_ops { /// Sort results by node id /// /// Returns: - #[doc = concat!(" ", $computed)] + #[doc = concat!(" ", $computed, ": The sorted node state")] fn sorted_by_id(&self) -> NodeState<'static, $value, DynamicGraph> { self.inner.sort_by_id() } @@ -134,7 +134,7 @@ macro_rules! impl_node_state_ord_ops { /// reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. /// /// Returns: - #[doc = concat!(" ", $computed)] + #[doc = concat!(" ", $computed, ": Sorted node state")] #[pyo3(signature = (reverse = false))] fn sorted(&self, reverse: bool) -> NodeState<'static, $value, DynamicGraph> { self.inner.sort_by_values(reverse) @@ -146,7 +146,7 @@ macro_rules! impl_node_state_ord_ops { /// k (int): The number of values to return /// /// Returns: - #[doc = concat!(" ", $computed)] + #[doc = concat!(" ", $computed, ": The k largest values as a node state")] fn top_k(&self, k: usize) -> NodeState<'static, $value, DynamicGraph> { self.inner.top_k(k) } @@ -157,7 +157,7 @@ macro_rules! impl_node_state_ord_ops { /// k (int): The number of values to return /// /// Returns: - #[doc = concat!(" ", $computed)] + #[doc = concat!(" ", $computed, ": The k smallest values as a node state")] fn bottom_k(&self, k: usize) -> NodeState<'static, $value, DynamicGraph> { self.inner.bottom_k(k) } @@ -165,7 +165,7 @@ macro_rules! impl_node_state_ord_ops { /// Return smallest value and corresponding node /// /// Returns: - #[doc = concat!(" Optional[Tuple[Node, ", $py_value,"]]")] + #[doc = concat!(" Optional[Tuple[Node, ", $py_value,"]]: The Node and minimum value or `None` if empty")] fn min_item(&self) -> Option<(NodeView, $value)> { self.inner .min_item() @@ -175,7 +175,7 @@ macro_rules! impl_node_state_ord_ops { /// Return the minimum value /// /// Returns: - #[doc = concat!(" Optional[", $py_value, "]")] + #[doc = concat!(" Optional[", $py_value, "]: The minimum value or `None` if empty")] fn min(&self) -> Option<$value> { self.inner.min().map($to_owned) } @@ -183,7 +183,7 @@ macro_rules! impl_node_state_ord_ops { /// Return largest value and corresponding node /// /// Returns: - #[doc = concat!(" Optional[Tuple[Node, ", $py_value,"]]")] + #[doc = concat!(" Optional[Tuple[Node, ", $py_value,"]]: The Node and maximum value or `None` if empty")] fn max_item(&self) -> Option<(NodeView, $value)> { self.inner .max_item() @@ -193,7 +193,7 @@ macro_rules! impl_node_state_ord_ops { /// Return the maximum value /// /// Returns: - #[doc = concat!(" Optional[", $py_value, "]")] + #[doc = concat!(" Optional[", $py_value, "]: The maximum value or `None` if empty")] fn max(&self) -> Option<$value> { self.inner.max().map($to_owned) } @@ -206,10 +206,10 @@ macro_rules! impl_node_state_ord_ops { self.inner.median().map($to_owned) } - /// Return medain value and corresponding node + /// Return median value and corresponding node /// /// Returns: - #[doc = concat!(" Optional[Tuple[Node, ", $py_value,"]]")] + #[doc = concat!(" Optional[Tuple[Node, ", $py_value,"]]: The median value or `None` if empty")] fn median_item(&self) -> Option<(NodeView, $value)> { self.inner .median_item() @@ -247,7 +247,7 @@ macro_rules! impl_node_state_num_ops { /// sum of values over all nodes /// /// Returns: - #[doc= concat!(" ", $py_value)] + #[doc= concat!(" ", $py_value, ": the sum")] fn sum(&self) -> $value { self.inner.sum() } @@ -255,7 +255,7 @@ macro_rules! impl_node_state_num_ops { /// mean of values over all nodes /// /// Returns: - /// float + /// float: mean value fn mean(&self) -> f64 { self.inner.mean() } @@ -292,7 +292,7 @@ macro_rules! impl_lazy_node_state { /// Compute all values and return the result as a list /// /// Returns - #[doc = concat!(" list[", $py_value, "]")] + #[doc = concat!(" list[", $py_value, "]", ": all values as a list")] fn collect(&self) -> Vec<<$op as NodeOp>::Output> { self.inner.collect() } diff --git a/raphtory/src/python/packages/algorithms.rs b/raphtory/src/python/packages/algorithms.rs index c50bc9a933..07ce2c7c2b 100644 --- a/raphtory/src/python/packages/algorithms.rs +++ b/raphtory/src/python/packages/algorithms.rs @@ -66,7 +66,10 @@ use std::collections::{HashMap, HashSet}; #[cfg(feature = "storage")] use crate::python::graph::disk_graph::PyDiskGraph; -use crate::{algorithms::bipartite::max_weight_matching::Matching, db::api::state::NodeState}; +use crate::{ + algorithms::bipartite::max_weight_matching::Matching, core::utils::errors::GraphError, + db::api::state::NodeState, +}; #[cfg(feature = "storage")] use pometry_storage::algorithms::connected_components::connected_components as connected_components_rs; @@ -562,11 +565,8 @@ pub fn balance( name: String, direction: Direction, threads: Option, -) -> PyResult>> { - match balance_rs(&g.graph, name.clone(), direction, threads) { - Ok(result) => Ok(result), - Err(err_msg) => Err(PyErr::new::(err_msg)), - } +) -> Result>, GraphError> { + balance_rs(&g.graph, name.clone(), direction, threads) } /// Computes the degree centrality of all nodes in the graph. The values are normalized From 31cfaed98a717c8f908fed444b634005cac0409c Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 9 Jan 2025 17:34:06 +0100 Subject: [PATCH 14/29] update the in- and out-component test for updated GQL apis --- python/tests/graphql/misc/test_components.py | 40 +++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/python/tests/graphql/misc/test_components.py b/python/tests/graphql/misc/test_components.py index 17d1a049d4..77cdadbb95 100644 --- a/python/tests/graphql/misc/test_components.py +++ b/python/tests/graphql/misc/test_components.py @@ -8,9 +8,13 @@ def test_in_out_components(): def sort_components(data): if "inComponent" in data: - data["inComponent"] = sorted(data["inComponent"], key=lambda x: x["name"]) + data["inComponent"]["list"] = sorted( + data["inComponent"]["list"], key=lambda x: x["name"] + ) if "outComponent" in data: - data["outComponent"] = sorted(data["outComponent"], key=lambda x: x["name"]) + data["outComponent"]["list"] = sorted( + data["outComponent"]["list"], key=lambda x: x["name"] + ) def prepare_for_comparison(structure): if "node" in structure: @@ -25,23 +29,31 @@ def prepare_for_comparison(structure): graph(path: "graph") { node(name: "3") { inComponent { - name + list { + name + } } outComponent { - name + list { + name + } } } window(start:1,end:6){ node(name:"3"){ inComponent{ - name + list { + name + } } } } at(time:4){ node(name:"4"){ outComponent{ - name + list { + name + } } } } @@ -51,11 +63,19 @@ def prepare_for_comparison(structure): result = { "graph": { "node": { - "inComponent": [{"name": "7"}, {"name": "1"}], - "outComponent": [{"name": "6"}, {"name": "4"}, {"name": "5"}], + "inComponent": { + "list": [{"name": "7"}, {"name": "1"}], + }, + "outComponent": { + "list": [{"name": "6"}, {"name": "4"}, {"name": "5"}], + }, + }, + "window": { + "node": {"inComponent": {"list": [{"name": "1"}]}}, + }, + "at": { + "node": {"outComponent": {"list": [{"name": "5"}]}}, }, - "window": {"node": {"inComponent": [{"name": "1"}]}}, - "at": {"node": {"outComponent": [{"name": "5"}]}}, } } work_dir = tempfile.mkdtemp() From be82ce6bbb4c42c4b34f270050ad69a42468432f Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 9 Jan 2025 17:49:04 +0100 Subject: [PATCH 15/29] fix some docstring error --- python/tests/graphql/edit_graph/test_graphql.py | 8 +++++++- python/tests/test_graphdb/test_graphdb.py | 11 ++++++++--- raphtory/src/python/graph/graph.rs | 8 ++++---- raphtory/src/python/graph/graph_with_deletions.rs | 4 ++-- raphtory/src/python/graph/node_state/node_state.rs | 13 +++++++------ raphtory/src/python/graph/views/graph_view.rs | 2 +- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/python/tests/graphql/edit_graph/test_graphql.py b/python/tests/graphql/edit_graph/test_graphql.py index 6c5a2382ab..16109164df 100644 --- a/python/tests/graphql/edit_graph/test_graphql.py +++ b/python/tests/graphql/edit_graph/test_graphql.py @@ -3,7 +3,13 @@ import pytest -from raphtory.graphql import GraphServer, RaphtoryClient, encode_graph, decode_graph, RemoteGraph +from raphtory.graphql import ( + GraphServer, + RaphtoryClient, + encode_graph, + decode_graph, + RemoteGraph, +) from raphtory import graph_loader from raphtory import Graph import json diff --git a/python/tests/test_graphdb/test_graphdb.py b/python/tests/test_graphdb/test_graphdb.py index 14ae889fb8..205cc84c5b 100644 --- a/python/tests/test_graphdb/test_graphdb.py +++ b/python/tests/test_graphdb/test_graphdb.py @@ -949,8 +949,13 @@ def check_temporal_properties(g): ["prop 4", "prop 1", "prop 2", "prop 3"] ) - assert sorted(g.at(1).edge(1, 2).properties.temporal.keys()) == ["prop 1", "prop 2", "prop 3", "prop 4"] - + assert sorted(g.at(1).edge(1, 2).properties.temporal.keys()) == [ + "prop 1", + "prop 2", + "prop 3", + "prop 4", + ] + # find all edges that match properties [e] = g.at(1).find_edges({"prop 1": 1, "prop 3": "hi"}) assert e == g.edge(1, 2) @@ -2144,7 +2149,7 @@ def check_g_inner(mg): assert g.has_edge(1, 2) assert mg.has_edge(2, 1) assert g.has_edge(2, 1) - + check_g_inner(g) mg = g.materialize() diff --git a/raphtory/src/python/graph/graph.rs b/raphtory/src/python/graph/graph.rs index 79e31f4c26..f841a31e57 100644 --- a/raphtory/src/python/graph/graph.rs +++ b/raphtory/src/python/graph/graph.rs @@ -451,7 +451,7 @@ impl PyGraph { /// If merge is true, the function merges the histories of the imported edge and the existing edge (in the graph). /// /// Returns: - /// EdgeView: An EdgeView object if the edge was successfully imported. + /// Edge: An Edge object if the edge was successfully imported. /// /// Raises: /// GraphError: If the operation fails. @@ -474,7 +474,7 @@ impl PyGraph { /// If merge is true, the function merges the histories of the imported edge and the existing edge (in the graph). /// /// Returns: - /// EdgeView: An EdgeView object if the edge was successfully imported. + /// Edge: An Edge object if the edge was successfully imported. /// /// Raises: /// GraphError: If the operation fails. @@ -511,13 +511,13 @@ impl PyGraph { /// /// Arguments: /// edges (List[Edge]): A list of Edge objects representing the edges to be imported. - /// new_ids (List[tuple]) - The IDs of the new edges. It's a vector of tuples of the source and destination node ids. + /// new_ids (List[Tuple[int, int]]): The IDs of the new edges. It's a vector of tuples of the source and destination node ids. /// merge (bool): An optional boolean flag. /// If merge is false, the function will return an error if any of the imported edges already exists in the graph. /// If merge is true, the function merges the histories of the imported edges and the existing edges (in the graph). /// /// Returns: - /// None: This function does not return a value, if the operation is successful. + /// None: This function does not return a value if the operation is successful. /// /// Raises: /// GraphError: If the operation fails. diff --git a/raphtory/src/python/graph/graph_with_deletions.rs b/raphtory/src/python/graph/graph_with_deletions.rs index cfc4ab5486..4248e48606 100644 --- a/raphtory/src/python/graph/graph_with_deletions.rs +++ b/raphtory/src/python/graph/graph_with_deletions.rs @@ -356,7 +356,7 @@ impl PyPersistentGraph { /// merge (bool): An optional boolean flag indicating whether to merge the import of the node. Defaults to False. /// /// Returns: - /// NodeView: A nodeview object if the node was successfully imported, and an error otherwise. + /// Node: A Node object if the node was successfully imported, and an error otherwise. /// /// Raises: /// GraphError: If the operation fails. @@ -380,7 +380,7 @@ impl PyPersistentGraph { /// merge (bool): An optional boolean flag indicating whether to merge the import of the node. Defaults to False. /// /// Returns: - /// NodeView: A nodeview object if the node was successfully imported, and an error otherwise. + /// Node: A Node object if the node was successfully imported, and an error otherwise. /// /// Raises: /// GraphError: If the operation fails. diff --git a/raphtory/src/python/graph/node_state/node_state.rs b/raphtory/src/python/graph/node_state/node_state.rs index 9cce6a9a66..f812e08a5a 100644 --- a/raphtory/src/python/graph/node_state/node_state.rs +++ b/raphtory/src/python/graph/node_state/node_state.rs @@ -476,7 +476,7 @@ type EarliestDateTime = ops::Map, Option>> impl_lazy_node_state_ord!( EarliestDateTimeView>, "NodeStateOptionDateTime", - "Optional[Datetime]" + "Optional[datetime]" ); impl_one_hop!( EarliestDateTimeView, @@ -488,14 +488,14 @@ type LatestDateTime = ops::Map, Option>>; impl_lazy_node_state_ord!( LatestDateTimeView, Option>>>, "NodeStateOptionDateTime", - "Optional[Datetime]" + "Optional[datetime]" ); impl_one_hop!(LatestDateTimeView, "LatestDateTimeView"); impl_node_state_group_by_ops!(LatestDateTimeView, Option>); impl_node_state_ord!( NodeStateOptionDateTime>>, "NodeStateOptionDateTime", - "Optional[Datetime]" + "Optional[datetime]" ); impl_node_state_group_by_ops!(NodeStateOptionDateTime, Option>); @@ -511,13 +511,13 @@ type HistoryDateTime = ops::Map, Option>>>; impl_lazy_node_state_ord!( HistoryDateTimeView>, "NodeStateOptionListDateTime", - "Optional[list[Datetime]]" + "Optional[list[datetime]]" ); impl_one_hop!(HistoryDateTimeView, "HistoryDateTimeView"); impl_node_state_ord!( NodeStateOptionListDateTime>>>, "NodeStateOptionListDateTime", - "Optional[list[Datetime]]" + "Optional[list[datetime]]" ); impl_lazy_node_state_ord!( @@ -536,7 +536,7 @@ impl_node_state_group_by_ops!(NodeStateOptionStr, Option); impl_node_state_ord!( NodeStateListDateTime>>, "NodeStateListDateTime", - "list[Datetime]" + "list[datetime]" ); pub fn base_node_state_module(py: Python<'_>) -> PyResult> { @@ -546,6 +546,7 @@ pub fn base_node_state_module(py: Python<'_>) -> PyResult> { DegreeView, NodeStateUsize, NodeStateU64, + NodeStateOptionI64, IdView, NodeStateGID, EarliestTimeView, diff --git a/raphtory/src/python/graph/views/graph_view.rs b/raphtory/src/python/graph/views/graph_view.rs index 71f6f36b77..b0bb964fea 100644 --- a/raphtory/src/python/graph/views/graph_view.rs +++ b/raphtory/src/python/graph/views/graph_view.rs @@ -401,7 +401,7 @@ impl PyGraphView { /// creates bitsets per layer for nodes and edges /// /// Returns: - /// MaskedGraph: Returns the masked graph + /// GraphView: Returns the masked graph fn cache_view(&self) -> CachedView { self.graph.cache_view() } From 67a11813d1bf627248ac253c16189017ab82ea9e Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Thu, 9 Jan 2025 17:49:31 +0100 Subject: [PATCH 16/29] bring back sorting for methods as they otherwise change order randomly --- python/python/raphtory/__init__.pyi | 4003 +++++++-------- .../python/raphtory/algorithms/__init__.pyi | 50 +- python/python/raphtory/graphql/__init__.pyi | 330 +- .../python/raphtory/node_state/__init__.pyi | 4382 +++++++++-------- python/python/raphtory/vectors/__init__.pyi | 102 +- python/scripts/stub_gen/stub_gen.py | 2 +- 6 files changed, 4511 insertions(+), 4358 deletions(-) diff --git a/python/python/raphtory/__init__.pyi b/python/python/raphtory/__init__.pyi index 8ebdd89787..03fab964ec 100644 --- a/python/python/raphtory/__init__.pyi +++ b/python/python/raphtory/__init__.pyi @@ -20,69 +20,76 @@ from pandas import DataFrame class GraphView(object): """Graph view is a read-only version of a graph at a certain point in time.""" - def __repr__(self): - """Return repr(self).""" + def __eq__(self, value): + """Return self==value.""" - def __lt__(self, value): - """Return self=value.""" + + def __gt__(self, value): + """Return self>value.""" def __le__(self, value): """Return self<=value.""" - def __eq__(self, value): - """Return self==value.""" + def __lt__(self, value): + """Return selfvalue.""" + def __repr__(self): + """Return repr(self).""" - def __ge__(self, value): - """Return self>=value.""" + def after(self, start: TimeInput): + """ + Create a view of the GraphView including all events after `start` (exclusive). - def vectorise( - self, - embedding: Callable[[list], list], - cache: Optional[str] = None, - overwrite_cache: bool = False, - graph: bool | str = True, - nodes: bool | str = True, - edges: bool | str = True, - graph_name: Optional[str] = None, - verbose: bool = False, - ) -> VectorisedGraph: + Arguments: + start (TimeInput): The start time of the window. + + Returns: + GraphView """ - Create a VectorisedGraph from the current graph - Args: - embedding (Callable[[list], list]): the embedding function to translate documents to embeddings - cache (str, optional): the file to be used as a cache to avoid calling the embedding function - overwrite_cache (bool): whether or not to overwrite the cache if there are new embeddings. Defaults to False. - graph (bool | str): if the graph has to be embedded or not or the custom template to use if a str is provided. Defaults to True. - nodes (bool | str): if nodes have to be embedded or not or the custom template to use if a str is provided. Defaults to True. - edges (bool | str): if edges have to be embedded or not or the custom template to use if a str is provided. Defaults to True. - graph_name (str, optional): the name of the graph - verbose (bool): whether or not to print logs reporting the progress. Defaults to False. + def at(self, time: TimeInput): + """ + Create a view of the GraphView including all events at `time`. + + Arguments: + time (TimeInput): The time of the window. Returns: - VectorisedGraph: A VectorisedGraph with all the documents/embeddings computed and with an initial empty selection + GraphView """ - def count_edges(self) -> int: + def before(self, end: TimeInput): """ - Number of edges in the graph + Create a view of the GraphView including all events before `end` (exclusive). + + Arguments: + end (TimeInput): The end time of the window. Returns: - int: the number of edges in the graph + GraphView """ - def count_temporal_edges(self) -> int: + def cache_view(self) -> GraphView: + """ + Applies the filters to the graph and retains the node ids and the edge ids + in the graph that satisfy the filters + creates bitsets per layer for nodes and edges + + Returns: + GraphView: Returns the masked graph + """ + + def count_edges(self) -> int: """ Number of edges in the graph Returns: - int: the number of temporal edges in the graph + int: the number of edges in the graph """ def count_nodes(self) -> int: @@ -93,47 +100,37 @@ class GraphView(object): int: the number of nodes in the graph """ - def has_node(self, id: InputNode) -> bool: + def count_temporal_edges(self) -> int: """ - Returns true if the graph contains the specified node - - Arguments: - id (InputNode): the node id + Number of edges in the graph Returns: - bool: true if the graph contains the specified node, false otherwise + int: the number of temporal edges in the graph """ - def has_edge(self, src: InputNode, dst: InputNode) -> bool: + def default_layer(self) -> GraphView: """ - Returns true if the graph contains the specified edge - - Arguments: - src (InputNode): the source node id - dst (InputNode): the destination node id - + Return a view of GraphView containing only the default edge layer Returns: - bool: true if the graph contains the specified edge, false otherwise + GraphView: The layered view """ - def node(self, id: InputNode) -> Optional[Node]: + @property + def earliest_date_time(self): """ - Gets the node with the specified id - - Arguments: - id (InputNode): the node id + DateTime of earliest activity in the graph Returns: - Optional[Node]: the node with the specified id, or None if the node does not exist + Optional[Datetime]: the datetime of the earliest activity in the graph """ - def find_nodes(self, properties_dict) -> list[Node]: + @property + def earliest_time(self): """ - Get the nodes that match the properties name and value - Arguments: - property_dict (dict[str, Prop]): the properties name and value + Timestamp of earliest activity in the graph + Returns: - list[Node]: the nodes that match the properties name and value + Optional[int]: the timestamp of the earliest activity in the graph """ def edge(self, src: InputNode, dst: InputNode) -> Optional[Edge]: @@ -148,45 +145,55 @@ class GraphView(object): Optional[Edge]: the edge with the specified source and destination nodes, or None if the edge does not exist """ - def find_edges(self, properties_dict) -> list[Edge]: + @property + def edges(self): """ - Get the edges that match the properties name and value - Arguments: - property_dict (dict[str, Prop]): the properties name and value + Gets all edges in the graph + Returns: - list[Edge]: the edges that match the properties name and value + Edges: the edges in the graph """ - def subgraph(self, nodes: list[InputNode]) -> GraphView: + @property + def end(self): """ - Returns a subgraph given a set of nodes + Gets the latest time that this GraphView is valid. - Arguments: - nodes (list[InputNode]): set of nodes + Returns: + Optional[int]: The latest time that this GraphView is valid or None if the GraphView is valid for all times. + """ + + @property + def end_date_time(self): + """ + Gets the latest datetime that this GraphView is valid Returns: - GraphView: Returns the subgraph + Optional[Datetime]: The latest datetime that this GraphView is valid or None if the GraphView is valid for all times. """ - def cache_view(self): + def exclude_layer(self, name: str) -> GraphView: """ - Applies the filters to the graph and retains the node ids and the edge ids - in the graph that satisfy the filters - creates bitsets per layer for nodes and edges + Return a view of GraphView containing all layers except the excluded `name` + Errors if any of the layers do not exist. + + Arguments: + name (str): layer name that is excluded for the new view Returns: - MaskedGraph: Returns the masked graph + GraphView: The layered view """ - def subgraph_node_types(self, node_types: list[str]) -> GraphView: + def exclude_layers(self, names: list[str]) -> GraphView: """ - Returns a subgraph filtered by node types given a set of node types + Return a view of GraphView containing all layers except the excluded `names` + Errors if any of the layers do not exist. Arguments: - node_types (list[str]): set of node types + names (list[str]): list of layer names that are excluded for the new view Returns: - GraphView: Returns the subgraph + GraphView: The layered view """ def exclude_nodes(self, nodes: list[InputNode]) -> GraphView: @@ -200,12 +207,37 @@ class GraphView(object): GraphView: Returns the subgraph """ - def materialize(self) -> GraphView: + def exclude_valid_layer(self, name: str) -> GraphView: """ - Returns a 'materialized' clone of the graph view - i.e. a new graph with a copy of the data seen within the view instead of just a mask over the original graph + Return a view of GraphView containing all layers except the excluded `name` + Arguments: + name (str): layer name that is excluded for the new view Returns: - GraphView: Returns a graph clone + GraphView: The layered view + """ + + def exclude_valid_layers(self, names: list[str]) -> GraphView: + """ + Return a view of GraphView containing all layers except the excluded `names` + Arguments: + names (list[str]): list of layer names that are excluded for the new view + + Returns: + GraphView: The layered view + """ + + def expanding(self, step: int | str) -> WindowSet: + """ + Creates a `WindowSet` with the given `step` size using an expanding window. + + An expanding window is a window that grows by `step` size at each iteration. + + Arguments: + step (int | str): The step size of the window. + + Returns: + WindowSet: A `WindowSet` object. """ def filter_edges(self, filter) -> GraphView: @@ -232,45 +264,46 @@ class GraphView(object): GraphView: The filtered view """ - def default_layer(self) -> GraphView: + def filter_nodes(self, filter) -> GraphView: """ - Return a view of GraphView containing only the default edge layer + Return a filtered view that only includes nodes that satisfy the filter + + Arguments + filter (PropertyFilter): The filter to apply to the node properties. Construct a + filter using `Prop`. + Returns: - GraphView: The layered view + GraphView: The filtered view """ - def layer(self, name: str) -> GraphView: + def find_edges(self, properties_dict) -> list[Edge]: """ - Return a view of GraphView containing the layer `"name"` - Errors if the layer does not exist - + Get the edges that match the properties name and value Arguments: - name (str): then name of the layer. - + property_dict (dict[str, Prop]): the properties name and value Returns: - GraphView: The layered view + list[Edge]: the edges that match the properties name and value """ - def exclude_layer(self, name: str) -> GraphView: + def find_nodes(self, properties_dict) -> list[Node]: """ - Return a view of GraphView containing all layers except the excluded `name` - Errors if any of the layers do not exist. - + Get the nodes that match the properties name and value Arguments: - name (str): layer name that is excluded for the new view - + property_dict (dict[str, Prop]): the properties name and value Returns: - GraphView: The layered view + list[Node]: the nodes that match the properties name and value """ - def exclude_valid_layer(self, name: str) -> GraphView: + def has_edge(self, src: InputNode, dst: InputNode) -> bool: """ - Return a view of GraphView containing all layers except the excluded `name` + Returns true if the graph contains the specified edge + Arguments: - name (str): layer name that is excluded for the new view + src (InputNode): the source node id + dst (InputNode): the destination node id Returns: - GraphView: The layered view + bool: true if the graph contains the specified edge, false otherwise """ def has_layer(self, name: str): @@ -284,44 +317,69 @@ class GraphView(object): bool """ - def layers(self, names: list[str]) -> GraphView: + def has_node(self, id: InputNode) -> bool: """ - Return a view of GraphView containing all layers `names` - Errors if any of the layers do not exist. + Returns true if the graph contains the specified node Arguments: - names (list[str]): list of layer names for the new view + id (InputNode): the node id Returns: - GraphView: The layered view + bool: true if the graph contains the specified node, false otherwise """ - def exclude_layers(self, names: list[str]) -> GraphView: + def index(self): """ - Return a view of GraphView containing all layers except the excluded `names` - Errors if any of the layers do not exist. + Indexes all node and edge properties. + Returns a GraphIndex which allows the user to search the edges and nodes of the graph via tantivity fuzzy matching queries. + Note this is currently immutable and will not update if the graph changes. This is to be improved in a future release. - Arguments: - names (list[str]): list of layer names that are excluded for the new view + Returns: + GraphIndex - Returns a GraphIndex + """ + + def latest(self): + """ + Create a view of the GraphView including all events at the latest time. Returns: - GraphView: The layered view + GraphView """ - def exclude_valid_layers(self, names: list[str]) -> GraphView: + @property + def latest_date_time(self): """ - Return a view of GraphView containing all layers except the excluded `names` + DateTime of latest activity in the graph + + Returns: + Optional[Datetime]: the datetime of the latest activity in the graph + """ + + @property + def latest_time(self): + """ + Timestamp of latest activity in the graph + + Returns: + Optional[int]: the timestamp of the latest activity in the graph + """ + + def layer(self, name: str) -> GraphView: + """ + Return a view of GraphView containing the layer `"name"` + Errors if the layer does not exist + Arguments: - names (list[str]): list of layer names that are excluded for the new view + name (str): then name of the layer. Returns: GraphView: The layered view """ - def valid_layers(self, names: list[str]) -> GraphView: + def layers(self, names: list[str]) -> GraphView: """ Return a view of GraphView containing all layers `names` - Any layers that do not exist are ignored + Errors if any of the layers do not exist. Arguments: names (list[str]): list of layer names for the new view @@ -330,29 +388,42 @@ class GraphView(object): GraphView: The layered view """ - def filter_nodes(self, filter) -> GraphView: + def materialize(self) -> GraphView: """ - Return a filtered view that only includes nodes that satisfy the filter + Returns a 'materialized' clone of the graph view - i.e. a new graph with a copy of the data seen within the view instead of just a mask over the original graph - Arguments - filter (PropertyFilter): The filter to apply to the node properties. Construct a - filter using `Prop`. + Returns: + GraphView: Returns a graph clone + """ + + def node(self, id: InputNode) -> Optional[Node]: + """ + Gets the node with the specified id + + Arguments: + id (InputNode): the node id Returns: - GraphView: The filtered view + Optional[Node]: the node with the specified id, or None if the node does not exist """ - def expanding(self, step: int | str) -> WindowSet: + @property + def nodes(self): """ - Creates a `WindowSet` with the given `step` size using an expanding window. + Gets the nodes in the graph - An expanding window is a window that grows by `step` size at each iteration. + Returns: + Nodes: the nodes in the graph + """ + + @property + def properties(self): + """ + Get all graph properties - Arguments: - step (int | str): The step size of the window. Returns: - WindowSet: A `WindowSet` object. + Properties: Properties paired with their names """ def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: @@ -370,35 +441,35 @@ class GraphView(object): WindowSet: A `WindowSet` object. """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def shrink_end(self, end: TimeInput): """ - Create a view of the GraphView including all events between `start` (inclusive) and `end` (exclusive) + Set the end of the window to the smaller of `end` and `self.end()` Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). - + end (TimeInput): the new end time of the window Returns: - r GraphView + GraphView """ - def at(self, time: TimeInput): + def shrink_start(self, start: TimeInput): """ - Create a view of the GraphView including all events at `time`. + Set the start of the window to the larger of `start` and `self.start()` Arguments: - time (TimeInput): The time of the window. + start (TimeInput): the new start time of the window Returns: GraphView """ - def latest(self): + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Create a view of the GraphView including all events at the latest time. + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - Returns: - GraphView """ def snapshot_at(self, time: TimeInput): @@ -424,57 +495,70 @@ class GraphView(object): GraphView """ - def before(self, end: TimeInput): + @property + def start(self): """ - Create a view of the GraphView including all events before `end` (exclusive). - - Arguments: - end (TimeInput): The end time of the window. + Gets the start time for rolling and expanding windows for this GraphView Returns: - GraphView + Optional[int]: The earliest time that this GraphView is valid or None if the GraphView is valid for all times. """ - def after(self, start: TimeInput): + @property + def start_date_time(self): """ - Create a view of the GraphView including all events after `start` (exclusive). - - Arguments: - start (TimeInput): The start time of the window. + Gets the earliest datetime that this GraphView is valid Returns: - GraphView + Optional[Datetime]: The earliest datetime that this GraphView is valid or None if the GraphView is valid for all times. """ - def shrink_start(self, start: TimeInput): + def subgraph(self, nodes: list[InputNode]) -> GraphView: """ - Set the start of the window to the larger of `start` and `self.start()` + Returns a subgraph given a set of nodes Arguments: - start (TimeInput): the new start time of the window + nodes (list[InputNode]): set of nodes Returns: - GraphView + GraphView: Returns the subgraph """ - def shrink_end(self, end: TimeInput): + def subgraph_node_types(self, node_types: list[str]) -> GraphView: """ - Set the end of the window to the smaller of `end` and `self.end()` + Returns a subgraph filtered by node types given a set of node types Arguments: - end (TimeInput): the new end time of the window + node_types (list[str]): set of node types + Returns: - GraphView + GraphView: Returns the subgraph """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def to_networkx( + self, + explode_edges: bool = False, + include_node_properties: bool = True, + include_edge_properties: bool = True, + include_update_history: bool = True, + include_property_history: bool = True, + ): """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + Returns a graph with NetworkX. - Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + Network X is a required dependency. + If you intend to use this function make sure that + you install Network X with ``pip install networkx`` + + Args: + explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False. + include_node_properties (bool): A boolean that is set to True if you want to include the node properties in the graph. By default this is set to True. + include_edge_properties (bool): A boolean that is set to True if you want to include the edge properties in the graph. By default this is set to True. + include_update_history (bool): A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True. + include_property_history (bool): A boolean that is set to True if you want to include the histories in the graph. By default this is set to True. + Returns: + A Networkx MultiDiGraph. """ def to_pyvis( @@ -513,176 +597,129 @@ class GraphView(object): A pyvis network """ - def to_networkx( - self, - explode_edges: bool = False, - include_node_properties: bool = True, - include_edge_properties: bool = True, - include_update_history: bool = True, - include_property_history: bool = True, - ): - """ - Returns a graph with NetworkX. - - Network X is a required dependency. - If you intend to use this function make sure that - you install Network X with ``pip install networkx`` - - Args: - explode_edges (bool): A boolean that is set to True if you want to explode the edges in the graph. By default this is set to False. - include_node_properties (bool): A boolean that is set to True if you want to include the node properties in the graph. By default this is set to True. - include_edge_properties (bool): A boolean that is set to True if you want to include the edge properties in the graph. By default this is set to True. - include_update_history (bool): A boolean that is set to True if you want to include the update histories in the graph. By default this is set to True. - include_property_history (bool): A boolean that is set to True if you want to include the histories in the graph. By default this is set to True. - - Returns: - A Networkx MultiDiGraph. - """ - - def index(self): + @property + def unique_layers(self): """ - Indexes all node and edge properties. - Returns a GraphIndex which allows the user to search the edges and nodes of the graph via tantivity fuzzy matching queries. - Note this is currently immutable and will not update if the graph changes. This is to be improved in a future release. + Return all the layer ids in the graph Returns: - GraphIndex - Returns a GraphIndex + list[str] """ - @property - def latest_date_time(self): + def valid_layers(self, names: list[str]) -> GraphView: """ - DateTime of latest activity in the graph + Return a view of GraphView containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[Datetime]: the datetime of the latest activity in the graph + GraphView: The layered view """ - @property - def earliest_time(self): + def vectorise( + self, + embedding: Callable[[list], list], + cache: Optional[str] = None, + overwrite_cache: bool = False, + graph: bool | str = True, + nodes: bool | str = True, + edges: bool | str = True, + graph_name: Optional[str] = None, + verbose: bool = False, + ) -> VectorisedGraph: """ - Timestamp of earliest activity in the graph + Create a VectorisedGraph from the current graph + + Args: + embedding (Callable[[list], list]): the embedding function to translate documents to embeddings + cache (str, optional): the file to be used as a cache to avoid calling the embedding function + overwrite_cache (bool): whether or not to overwrite the cache if there are new embeddings. Defaults to False. + graph (bool | str): if the graph has to be embedded or not or the custom template to use if a str is provided. Defaults to True. + nodes (bool | str): if nodes have to be embedded or not or the custom template to use if a str is provided. Defaults to True. + edges (bool | str): if edges have to be embedded or not or the custom template to use if a str is provided. Defaults to True. + graph_name (str, optional): the name of the graph + verbose (bool): whether or not to print logs reporting the progress. Defaults to False. Returns: - Optional[int]: the timestamp of the earliest activity in the graph + VectorisedGraph: A VectorisedGraph with all the documents/embeddings computed and with an initial empty selection """ - @property - def end(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Gets the latest time that this GraphView is valid. + Create a view of the GraphView including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - Optional[int]: The latest time that this GraphView is valid or None if the GraphView is valid for all times. + r GraphView """ @property - def edges(self): + def window_size(self): """ - Gets all edges in the graph + Get the window size (difference between start and end) for this GraphView Returns: - Edges: the edges in the graph + Optional[int] """ - @property - def nodes(self): - """ - Gets the nodes in the graph - - Returns: - Nodes: the nodes in the graph - """ - - @property - def unique_layers(self): - """ - Return all the layer ids in the graph - - Returns: - list[str] - """ - - @property - def properties(self): - """ - Get all graph properties - - - Returns: - Properties: Properties paired with their names - """ - - @property - def start(self): - """ - Gets the start time for rolling and expanding windows for this GraphView +class Graph(GraphView): + """ + A temporal graph with event semantics. - Returns: - Optional[int]: The earliest time that this GraphView is valid or None if the GraphView is valid for all times. - """ + Arguments: + num_shards (int, optional): The number of locks to use in the storage to allow for multithreaded updates. + """ - @property - def start_date_time(self): - """ - Gets the earliest datetime that this GraphView is valid + def __new__(cls, num_shards: Optional[int] = None) -> Graph: + """Create and return a new object. See help(type) for accurate signature.""" - Returns: - Optional[Datetime]: The earliest datetime that this GraphView is valid or None if the GraphView is valid for all times. + def __reduce__(self): ... + def add_constant_properties(self, properties: PropInput) -> None: """ + Adds static properties to the graph. - @property - def end_date_time(self): - """ - Gets the latest datetime that this GraphView is valid + Arguments: + properties (PropInput): The static properties of the graph. Returns: - Optional[Datetime]: The latest datetime that this GraphView is valid or None if the GraphView is valid for all times. - """ + None: This function does not return a value, if the operation is successful. - @property - def window_size(self): + Raises: + GraphError: If the operation fails. """ - Get the window size (difference between start and end) for this GraphView - Returns: - Optional[int] + def add_edge( + self, + timestamp: TimeInput, + src: str | int, + dst: str | int, + properties: Optional[PropInput] = None, + layer: Optional[str] = None, + secondary_index=None, + ) -> MutableEdge: """ + Adds a new edge with the given source and destination nodes and properties to the graph. - @property - def earliest_date_time(self): - """ - DateTime of earliest activity in the graph + Arguments: + timestamp (TimeInput): The timestamp of the edge. + src (str|int): The id of the source node. + dst (str|int): The id of the destination node. + properties (PropInput, optional): The properties of the edge, as a dict of string and properties. + layer (str, optional): The layer of the edge. + secondary_index (int, optional): The optional integer which will be used as a secondary index Returns: - Optional[Datetime]: the datetime of the earliest activity in the graph - """ - - @property - def latest_time(self): - """ - Timestamp of latest activity in the graph + MutableEdge: The added edge. - Returns: - Optional[int]: the timestamp of the latest activity in the graph + Raises: + GraphError: If the operation fails. """ -class Graph(GraphView): - """ - A temporal graph with event semantics. - - Arguments: - num_shards (int, optional): The number of locks to use in the storage to allow for multithreaded updates. - """ - - def __new__(cls, num_shards: Optional[int] = None) -> Graph: - """Create and return a new object. See help(type) for accurate signature.""" - - def persist_as_disk_graph(self, graph_dir): - """save graph in disk_graph format and memory map the result""" - - def __reduce__(self): ... - def to_disk_graph(self, graph_dir): ... def add_node( self, timestamp: TimeInput, @@ -708,6 +745,38 @@ class Graph(GraphView): GraphError: If the operation fails. """ + def add_properties( + self, + timestamp: TimeInput, + properties: PropInput, + secondary_index: Optional[int] = None, + ) -> None: + """ + Adds properties to the graph. + + Arguments: + timestamp (TimeInput): The timestamp of the temporal property. + properties (PropInput): The temporal properties of the graph. + secondary_index (int, optional): The optional integer which will be used as a secondary index + + Returns: + None: This function does not return a value, if the operation is successful. + + Raises: + GraphError: If the operation fails. + """ + + def cache(self, path: str): + """ + Write Graph to cache file and initialise the cache. + + Future updates are tracked. Use `write_updates` to persist them to the + cache file. If the file already exists its contents are overwritten. + + Arguments: + path (str): The path to the cache file + """ + def create_node( self, timestamp: TimeInput, @@ -733,47 +802,83 @@ class Graph(GraphView): GraphError: If the operation fails. """ - def add_properties( - self, - timestamp: TimeInput, - properties: PropInput, - secondary_index: Optional[int] = None, - ) -> None: + @staticmethod + def deserialise(bytes: bytes): """ - Adds properties to the graph. + Load Graph from serialised bytes. Arguments: - timestamp (TimeInput): The timestamp of the temporal property. - properties (PropInput): The temporal properties of the graph. - secondary_index (int, optional): The optional integer which will be used as a secondary index + bytes (bytes): The serialised bytes to decode Returns: - None: This function does not return a value, if the operation is successful. + Graph + """ + + def edge(self, src: str | int, dst: str | int) -> Edge: + """ + Gets the edge with the specified source and destination nodes + + Arguments: + src (str|int): the source node id + dst (str|int): the destination node id + + Returns: + Edge: the edge with the specified source and destination nodes, or None if the edge does not exist + """ + + def event_graph(self): ... + def get_all_node_types(self): + """ + Returns all the node types in the graph. + + Returns: + List[str] + """ + + def import_edge(self, edge: Edge, merge: bool = False) -> Edge: + """ + Import a single edge into the graph. + + Arguments: + edge (Edge): A Edge object representing the edge to be imported. + merge (bool): An optional boolean flag. + If merge is false, the function will return an error if the imported edge already exists in the graph. + If merge is true, the function merges the histories of the imported edge and the existing edge (in the graph). + + Returns: + Edge: An Edge object if the edge was successfully imported. Raises: GraphError: If the operation fails. """ - def add_constant_properties(self, properties: PropInput) -> None: + def import_edge_as(self, edge: Edge, new_id: tuple, merge: bool = False) -> Edge: """ - Adds static properties to the graph. + Import a single edge into the graph with new id. Arguments: - properties (PropInput): The static properties of the graph. + edge (Edge): A Edge object representing the edge to be imported. + new_id (tuple) : The ID of the new edge. It's a tuple of the source and destination node ids. + merge (bool): An optional boolean flag. + If merge is false, the function will return an error if the imported edge already exists in the graph. + If merge is true, the function merges the histories of the imported edge and the existing edge (in the graph). Returns: - None: This function does not return a value, if the operation is successful. + Edge: An Edge object if the edge was successfully imported. Raises: GraphError: If the operation fails. """ - def update_constant_properties(self, properties: PropInput) -> None: + def import_edges(self, edges: List[Edge], merge: bool = False) -> None: """ - Updates static properties to the graph. + Import multiple edges into the graph. Arguments: - properties (PropInput): The static properties of the graph. + edges (List[Edge]): A list of Edge objects representing the edges to be imported. + merge (bool): An optional boolean flag. + If merge is false, the function will return an error if any of the imported edges already exists in the graph. + If merge is true, the function merges the histories of the imported edges and the existing edges (in the graph). Returns: None: This function does not return a value, if the operation is successful. @@ -782,28 +887,21 @@ class Graph(GraphView): GraphError: If the operation fails. """ - def add_edge( - self, - timestamp: TimeInput, - src: str | int, - dst: str | int, - properties: Optional[PropInput] = None, - layer: Optional[str] = None, - secondary_index=None, - ) -> MutableEdge: + def import_edges_as( + self, edges: List[Edge], new_ids: List[Tuple[int, int]], merge: bool = False + ) -> None: """ - Adds a new edge with the given source and destination nodes and properties to the graph. + Import multiple edges into the graph with new ids. Arguments: - timestamp (TimeInput): The timestamp of the edge. - src (str|int): The id of the source node. - dst (str|int): The id of the destination node. - properties (PropInput, optional): The properties of the edge, as a dict of string and properties. - layer (str, optional): The layer of the edge. - secondary_index (int, optional): The optional integer which will be used as a secondary index + edges (List[Edge]): A list of Edge objects representing the edges to be imported. + new_ids (List[Tuple[int, int]]): The IDs of the new edges. It's a vector of tuples of the source and destination node ids. + merge (bool): An optional boolean flag. + If merge is false, the function will return an error if any of the imported edges already exists in the graph. + If merge is true, the function merges the histories of the imported edges and the existing edges (in the graph). Returns: - MutableEdge: The added edge. + None: This function does not return a value if the operation is successful. Raises: GraphError: If the operation fails. @@ -883,146 +981,54 @@ class Graph(GraphView): GraphError: If the operation fails. """ - def import_edge(self, edge: Edge, merge: bool = False): + def largest_connected_component(self): """ - Import a single edge into the graph. + Gives the large connected component of a graph. - Arguments: - edge (Edge): A Edge object representing the edge to be imported. - merge (bool): An optional boolean flag. - If merge is false, the function will return an error if the imported edge already exists in the graph. - If merge is true, the function merges the histories of the imported edge and the existing edge (in the graph). + # Example Usage: + g.largest_connected_component() - Returns: - EdgeView: An EdgeView object if the edge was successfully imported. + # Returns: + Graph: sub-graph of the graph `g` containing the largest connected component - Raises: - GraphError: If the operation fails. - """ - - def import_edge_as(self, edge: Edge, new_id: tuple, merge: bool = False): - """ - Import a single edge into the graph with new id. - - Arguments: - edge (Edge): A Edge object representing the edge to be imported. - new_id (tuple) : The ID of the new edge. It's a tuple of the source and destination node ids. - merge (bool): An optional boolean flag. - If merge is false, the function will return an error if the imported edge already exists in the graph. - If merge is true, the function merges the histories of the imported edge and the existing edge (in the graph). - - Returns: - EdgeView: An EdgeView object if the edge was successfully imported. - - Raises: - GraphError: If the operation fails. - """ - - def import_edges(self, edges: List[Edge], merge: bool = False) -> None: - """ - Import multiple edges into the graph. - - Arguments: - edges (List[Edge]): A list of Edge objects representing the edges to be imported. - merge (bool): An optional boolean flag. - If merge is false, the function will return an error if any of the imported edges already exists in the graph. - If merge is true, the function merges the histories of the imported edges and the existing edges (in the graph). - - Returns: - None: This function does not return a value, if the operation is successful. - - Raises: - GraphError: If the operation fails. - """ - - def import_edges_as(self, edges, new_ids, merge=False): - """ - Import multiple edges into the graph with new ids. - - Arguments: - edges (List[Edge]): A list of Edge objects representing the edges to be imported. - new_ids (List[tuple]) - The IDs of the new edges. It's a vector of tuples of the source and destination node ids. - merge (bool): An optional boolean flag. - If merge is false, the function will return an error if any of the imported edges already exists in the graph. - If merge is true, the function merges the histories of the imported edges and the existing edges (in the graph). - - Returns: - None: This function does not return a value, if the operation is successful. - - Raises: - GraphError: If the operation fails. - """ - - def node(self, id: str | int) -> Node: """ - Gets the node with the specified id - - Arguments: - id (str|int): the node id - Returns: - Node: The node object with the specified id, or None if the node does not exist + @staticmethod + def load_cached(path: str): """ + Load Graph from a file and initialise it as a cache file. - def edge(self, src: str | int, dst: str | int) -> Edge: - """ - Gets the edge with the specified source and destination nodes + Future updates are tracked. Use `write_updates` to persist them to the + cache file. Arguments: - src (str|int): the source node id - dst (str|int): the destination node id - - Returns: - Edge: the edge with the specified source and destination nodes, or None if the edge does not exist - """ - - def get_all_node_types(self): - """ - Returns all the node types in the graph. + path (str): The path to the cache file Returns: - List[str] - """ - - def largest_connected_component(self): - """ - Gives the large connected component of a graph. - - # Example Usage: - g.largest_connected_component() - - # Returns: - Graph: sub-graph of the graph `g` containing the largest connected component - + Graph """ - def persistent_graph(self): - """Get persistent graph""" - - def event_graph(self): ... - def load_nodes_from_pandas( + def load_edge_props_from_pandas( self, df: DataFrame, - time: str, - id: str, - node_type: Optional[str] = None, - node_type_col: Optional[str] = None, - properties: Optional[List[str]] = None, + src: str, + dst: str, constant_properties: Optional[List[str]] = None, shared_constant_properties: Optional[PropInput] = None, + layer: Optional[str] = None, + layer_col: Optional[str] = None, ) -> None: """ - Load nodes from a Pandas DataFrame into the graph. + Load edge properties from a Pandas DataFrame. Arguments: - df (DataFrame): The Pandas DataFrame containing the nodes. - time (str): The column name for the timestamps. - id (str): The column name for the node IDs. - node_type (str, optional): A constant value to use as the node type for all nodes. Defaults to None. (cannot be used in combination with node_type_col) - node_type_col (str, optional): The node type col name in dataframe. Defaults to None. (cannot be used in combination with node_type) - properties (List[str], optional): List of node property column names. Defaults to None. - constant_properties (List[str], optional): List of constant node property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every node. Defaults to None. + df (DataFrame): The Pandas DataFrame containing edge information. + src (str): The column name for the source node. + dst (str): The column name for the destination node. + constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. + layer (str, optional): The edge layer name. Defaults to None. + layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. Returns: None: This function does not return a value, if the operation is successful. @@ -1031,29 +1037,27 @@ class Graph(GraphView): GraphError: If the operation fails. """ - def load_nodes_from_parquet( + def load_edge_props_from_parquet( self, parquet_path: str, - time: str, - id: str, - node_type: Optional[str] = None, - node_type_col: Optional[str] = None, - properties: Optional[List[str]] = None, + src: str, + dst: str, constant_properties: Optional[List[str]] = None, shared_constant_properties: Optional[PropInput] = None, + layer: Optional[str] = None, + layer_col: Optional[str] = None, ) -> None: """ - Load nodes from a Parquet file into the graph. + Load edge properties from parquet file Arguments: - parquet_path (str): Parquet file or directory of Parquet files containing the nodes - time (str): The column name for the timestamps. - id (str): The column name for the node IDs. - node_type (str, optional): A constant value to use as the node type for all nodes. Defaults to None. (cannot be used in combination with node_type_col) - node_type_col (str, optional): The node type col name in dataframe. Defaults to None. (cannot be used in combination with node_type) - properties (List[str], optional): List of node property column names. Defaults to None. - constant_properties (List[str], optional): List of constant node property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every node. Defaults to None. + parquet_path (str): Parquet file or directory of Parquet files path containing edge information. + src (str): The column name for the source node. + dst (str): The column name for the destination node. + constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. + layer (str, optional): The edge layer name. Defaults to None. + layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. Returns: None: This function does not return a value, if the operation is successful. @@ -1128,6 +1132,18 @@ class Graph(GraphView): GraphError: If the operation fails. """ + @staticmethod + def load_from_file(path: str): + """ + Load Graph from a file. + + Arguments: + path (str): The path to the file. + + Returns: + Graph + """ + def load_node_props_from_pandas( self, df: DataFrame, @@ -1182,27 +1198,29 @@ class Graph(GraphView): GraphError: If the operation fails. """ - def load_edge_props_from_pandas( + def load_nodes_from_pandas( self, df: DataFrame, - src: str, - dst: str, + time: str, + id: str, + node_type: Optional[str] = None, + node_type_col: Optional[str] = None, + properties: Optional[List[str]] = None, constant_properties: Optional[List[str]] = None, shared_constant_properties: Optional[PropInput] = None, - layer: Optional[str] = None, - layer_col: Optional[str] = None, ) -> None: """ - Load edge properties from a Pandas DataFrame. + Load nodes from a Pandas DataFrame into the graph. Arguments: - df (DataFrame): The Pandas DataFrame containing edge information. - src (str): The column name for the source node. - dst (str): The column name for the destination node. - constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. - layer (str, optional): The edge layer name. Defaults to None. - layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. + df (DataFrame): The Pandas DataFrame containing the nodes. + time (str): The column name for the timestamps. + id (str): The column name for the node IDs. + node_type (str, optional): A constant value to use as the node type for all nodes. Defaults to None. (cannot be used in combination with node_type_col) + node_type_col (str, optional): The node type col name in dataframe. Defaults to None. (cannot be used in combination with node_type) + properties (List[str], optional): List of node property column names. Defaults to None. + constant_properties (List[str], optional): List of constant node property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every node. Defaults to None. Returns: None: This function does not return a value, if the operation is successful. @@ -1211,27 +1229,29 @@ class Graph(GraphView): GraphError: If the operation fails. """ - def load_edge_props_from_parquet( + def load_nodes_from_parquet( self, parquet_path: str, - src: str, - dst: str, + time: str, + id: str, + node_type: Optional[str] = None, + node_type_col: Optional[str] = None, + properties: Optional[List[str]] = None, constant_properties: Optional[List[str]] = None, shared_constant_properties: Optional[PropInput] = None, - layer: Optional[str] = None, - layer_col: Optional[str] = None, ) -> None: """ - Load edge properties from parquet file + Load nodes from a Parquet file into the graph. Arguments: - parquet_path (str): Parquet file or directory of Parquet files path containing edge information. - src (str): The column name for the source node. - dst (str): The column name for the destination node. - constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. - layer (str, optional): The edge layer name. Defaults to None. - layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. + parquet_path (str): Parquet file or directory of Parquet files containing the nodes + time (str): The column name for the timestamps. + id (str): The column name for the node IDs. + node_type (str, optional): A constant value to use as the node type for all nodes. Defaults to None. (cannot be used in combination with node_type_col) + node_type_col (str, optional): The node type col name in dataframe. Defaults to None. (cannot be used in combination with node_type) + properties (List[str], optional): List of node property column names. Defaults to None. + constant_properties (List[str], optional): List of constant node property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every node. Defaults to None. Returns: None: This function does not return a value, if the operation is successful. @@ -1240,48 +1260,32 @@ class Graph(GraphView): GraphError: If the operation fails. """ - def cache(self, path: str): + def node(self, id: str | int) -> Node: """ - Write Graph to cache file and initialise the cache. - - Future updates are tracked. Use `write_updates` to persist them to the - cache file. If the file already exists its contents are overwritten. + Gets the node with the specified id Arguments: - path (str): The path to the cache file - """ - - def write_updates(self): - """Persist the new updates by appending them to the cache file.""" + id (str|int): the node id - @staticmethod - def load_cached(path: str): + Returns: + Node: The node object with the specified id, or None if the node does not exist """ - Load Graph from a file and initialise it as a cache file. - Future updates are tracked. Use `write_updates` to persist them to the - cache file. + def persist_as_disk_graph(self, graph_dir): + """save graph in disk_graph format and memory map the result""" - Arguments: - path (str): The path to the cache file + def persistent_graph(self): + """Get persistent graph""" - Returns: - Graph + def save_to_file(self, path: str): """ + Saves the Graph to the given path. - @staticmethod - def load_from_file(path: str): + Arguments: + path (str): The path to the file. """ - Load Graph from a file. - Arguments: - path (str): The path to the file. - - Returns: - Graph - """ - - def save_to_file(self, path: str): + def save_to_zip(self, path: str): """ Saves the Graph to the given path. @@ -1289,33 +1293,31 @@ class Graph(GraphView): path (str): The path to the file. """ - def save_to_zip(self, path: str): + def serialise(self): """ - Saves the Graph to the given path. + Serialise Graph to bytes. - Arguments: - path (str): The path to the file. + Returns: + bytes """ - @staticmethod - def deserialise(bytes: bytes): + def to_disk_graph(self, graph_dir): ... + def update_constant_properties(self, properties: PropInput) -> None: """ - Load Graph from serialised bytes. + Updates static properties to the graph. Arguments: - bytes (bytes): The serialised bytes to decode + properties (PropInput): The static properties of the graph. Returns: - Graph - """ + None: This function does not return a value, if the operation is successful. - def serialise(self): + Raises: + GraphError: If the operation fails. """ - Serialise Graph to bytes. - Returns: - bytes - """ + def write_updates(self): + """Persist the new updates by appending them to the cache file.""" class PersistentGraph(GraphView): """A temporal graph that allows edges and nodes to be deleted.""" @@ -1324,22 +1326,38 @@ class PersistentGraph(GraphView): """Create and return a new object. See help(type) for accurate signature.""" def __reduce__(self): ... - def add_node( + def add_constant_properties(self, properties: dict) -> None: + """ + Adds static properties to the graph. + + Arguments: + properties (dict): The static properties of the graph. + + Returns: + None: This function does not return a value, if the operation is successful. + + Raises: + GraphError: If the operation fails. + """ + + def add_edge( self, - timestamp: TimeInput, - id: str | int, + timestamp: int, + src: str | int, + dst: str | int, properties: Optional[PropInput] = None, - node_type: Optional[str] = None, + layer: Optional[str] = None, secondary_index: Optional[int] = None, ) -> None: """ - Adds a new node with the given id and properties to the graph. + Adds a new edge with the given source and destination nodes and properties to the graph. Arguments: - timestamp (TimeInput): The timestamp of the node. - id (str | int): The id of the node. - properties (PropInput, optional): The properties of the node. - node_type (str, optional) : The optional string which will be used as a node type + timestamp (int): The timestamp of the edge. + src (str | int): The id of the source node. + dst (str | int): The id of the destination node. + properties (PropInput, optional): The properties of the edge, as a dict of string and properties + layer (str, optional): The layer of the edge. secondary_index (int, optional): The optional integer which will be used as a secondary index Returns: @@ -1349,16 +1367,16 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def create_node( + def add_node( self, timestamp: TimeInput, id: str | int, properties: Optional[PropInput] = None, node_type: Optional[str] = None, secondary_index: Optional[int] = None, - ) -> MutableNode: + ) -> None: """ - Creates a new node with the given id and properties to the graph. It fails if the node already exists. + Adds a new node with the given id and properties to the graph. Arguments: timestamp (TimeInput): The timestamp of the node. @@ -1368,7 +1386,7 @@ class PersistentGraph(GraphView): secondary_index (int, optional): The optional integer which will be used as a secondary index Returns: - MutableNode: the newly created node. + None: This function does not return a value, if the operation is successful. Raises: GraphError: If the operation fails. @@ -1395,56 +1413,37 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def add_constant_properties(self, properties: dict) -> None: - """ - Adds static properties to the graph. - - Arguments: - properties (dict): The static properties of the graph. - - Returns: - None: This function does not return a value, if the operation is successful. - - Raises: - GraphError: If the operation fails. + def cache(self, path: str): """ + Write PersistentGraph to cache file and initialise the cache. - def update_constant_properties(self, properties: dict) -> None: - """ - Updates static properties to the graph. + Future updates are tracked. Use `write_updates` to persist them to the + cache file. If the file already exists its contents are overwritten. Arguments: - properties (dict): The static properties of the graph. - - Returns: - None: This function does not return a value, if the operation is successful. - - Raises: - GraphError: If the operation fails. + path (str): The path to the cache file """ - def add_edge( + def create_node( self, - timestamp: int, - src: str | int, - dst: str | int, + timestamp: TimeInput, + id: str | int, properties: Optional[PropInput] = None, - layer: Optional[str] = None, + node_type: Optional[str] = None, secondary_index: Optional[int] = None, - ) -> None: + ) -> MutableNode: """ - Adds a new edge with the given source and destination nodes and properties to the graph. + Creates a new node with the given id and properties to the graph. It fails if the node already exists. Arguments: - timestamp (int): The timestamp of the edge. - src (str | int): The id of the source node. - dst (str | int): The id of the destination node. - properties (PropInput, optional): The properties of the edge, as a dict of string and properties - layer (str, optional): The layer of the edge. + timestamp (TimeInput): The timestamp of the node. + id (str | int): The id of the node. + properties (PropInput, optional): The properties of the node. + node_type (str, optional) : The optional string which will be used as a node type secondary_index (int, optional): The optional integer which will be used as a secondary index Returns: - None: This function does not return a value, if the operation is successful. + MutableNode: the newly created node. Raises: GraphError: If the operation fails. @@ -1475,15 +1474,16 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def node(self, id: str | int): + @staticmethod + def deserialise(bytes: bytes): """ - Gets the node with the specified id + Load PersistentGraph from serialised bytes. Arguments: - id (str | int): the node id + bytes (bytes): The serialised bytes to decode Returns: - The node with the specified id, or None if the node does not exist + PersistentGraph """ def edge(self, src: str | int, dst: str | int): @@ -1498,80 +1498,15 @@ class PersistentGraph(GraphView): The edge with the specified source and destination nodes, or None if the edge does not exist """ - def import_node(self, node: Node, merge: bool = False): - """ - Import a single node into the graph. - - This function takes a node object and an optional boolean flag. If the flag is set to true, - the function will merge the import of the node even if it already exists in the graph. - - Arguments: - node (Node): A node object representing the node to be imported. - merge (bool): An optional boolean flag indicating whether to merge the import of the node. Defaults to False. - - Returns: - NodeView: A nodeview object if the node was successfully imported, and an error otherwise. - - Raises: - GraphError: If the operation fails. - """ - - def import_node_as(self, node: Node, new_id: str | int, merge: bool = False): - """ - Import a single node into the graph with new id. - - This function takes a node object, a new node id and an optional boolean flag. If the flag is set to true, - the function will merge the import of the node even if it already exists in the graph. - - Arguments: - node (Node): A node object representing the node to be imported. - new_id (str|int): The new node id. - merge (bool): An optional boolean flag indicating whether to merge the import of the node. Defaults to False. - - Returns: - NodeView: A nodeview object if the node was successfully imported, and an error otherwise. - - Raises: - GraphError: If the operation fails. - """ - - def import_nodes(self, nodes: List[Node], merge: bool = False) -> None: - """ - Import multiple nodes into the graph. - - This function takes a vector of node objects and an optional boolean flag. If the flag is set to true, - the function will merge the import of the nodes even if they already exist in the graph. - - Arguments: - nodes (List[Node]): A vector of node objects representing the nodes to be imported. - merge (bool): An optional boolean flag indicating whether to merge the import of the nodes. Defaults to False. - - Returns: - None: This function does not return a value, if the operation is successful. - - Raises: - GraphError: If the operation fails. - """ + def event_graph(self): + """Get event graph""" - def import_nodes_as( - self, nodes: List[Node], new_ids: List[str | int], merge: bool = False - ) -> None: + def get_all_node_types(self): """ - Import multiple nodes into the graph with new ids. - - This function takes a vector of node objects, a list of new node ids and an optional boolean flag. If the flag is set to true, - the function will merge the import of the nodes even if they already exist in the graph. - - Arguments: - nodes (List[Node]): A vector of node objects representing the nodes to be imported. - new_ids (List[str|int]): A list of node IDs to use for the imported nodes. - merge (bool): An optional boolean flag indicating whether to merge the import of the nodes. Defaults to False. + Returns all the node types in the graph. Returns: - None: This function does not return a value, if the operation is successful. - - Raises: - GraphError: If the operation fails. + A list of node types """ def import_edge(self, edge: Edge, merge: bool = False) -> Edge: @@ -1647,72 +1582,76 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def get_all_node_types(self): - """ - Returns all the node types in the graph. - - Returns: - A list of node types + def import_node(self, node: Node, merge: bool = False) -> Node: """ + Import a single node into the graph. - def event_graph(self): - """Get event graph""" - - def persistent_graph(self): ... - def load_nodes_from_pandas( - self, - df: DataFrame, - time: str, - id: str, - node_type: Optional[str] = None, - node_type_col: Optional[str] = None, - properties: Optional[List[str]] = None, - constant_properties: Optional[List[str]] = None, - shared_constant_properties: Optional[PropInput] = None, - ) -> None: - """ - Load nodes from a Pandas DataFrame into the graph. + This function takes a node object and an optional boolean flag. If the flag is set to true, + the function will merge the import of the node even if it already exists in the graph. Arguments: - df (DataFrame): The Pandas DataFrame containing the nodes. - time (str): The column name for the timestamps. - id (str): The column name for the node IDs. - node_type (str, optional): A constant value to use as the node type for all nodes. Defaults to None. (cannot be used in combination with node_type_col) - node_type_col (str, optional): The node type col name in dataframe. Defaults to None. (cannot be used in combination with node_type) - properties (List[str], optional): List of node property column names. Defaults to None. - constant_properties (List[str], optional): List of constant node property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every node. Defaults to None. + node (Node): A node object representing the node to be imported. + merge (bool): An optional boolean flag indicating whether to merge the import of the node. Defaults to False. Returns: - None: This function does not return a value, if the operation is successful. + Node: A Node object if the node was successfully imported, and an error otherwise. Raises: GraphError: If the operation fails. """ - def load_nodes_from_parquet( - self, - parquet_path: str, - time: str, - id: str, - node_type: Optional[str] = None, - node_type_col: Optional[str] = None, - properties: Optional[List[str]] = None, - constant_properties: Optional[List[str]] = None, - shared_constant_properties: Optional[PropInput] = None, + def import_node_as( + self, node: Node, new_id: str | int, merge: bool = False + ) -> Node: + """ + Import a single node into the graph with new id. + + This function takes a node object, a new node id and an optional boolean flag. If the flag is set to true, + the function will merge the import of the node even if it already exists in the graph. + + Arguments: + node (Node): A node object representing the node to be imported. + new_id (str|int): The new node id. + merge (bool): An optional boolean flag indicating whether to merge the import of the node. Defaults to False. + + Returns: + Node: A Node object if the node was successfully imported, and an error otherwise. + + Raises: + GraphError: If the operation fails. + """ + + def import_nodes(self, nodes: List[Node], merge: bool = False) -> None: + """ + Import multiple nodes into the graph. + + This function takes a vector of node objects and an optional boolean flag. If the flag is set to true, + the function will merge the import of the nodes even if they already exist in the graph. + + Arguments: + nodes (List[Node]): A vector of node objects representing the nodes to be imported. + merge (bool): An optional boolean flag indicating whether to merge the import of the nodes. Defaults to False. + + Returns: + None: This function does not return a value, if the operation is successful. + + Raises: + GraphError: If the operation fails. + """ + + def import_nodes_as( + self, nodes: List[Node], new_ids: List[str | int], merge: bool = False ) -> None: """ - Load nodes from a Parquet file into the graph. + Import multiple nodes into the graph with new ids. + + This function takes a vector of node objects, a list of new node ids and an optional boolean flag. If the flag is set to true, + the function will merge the import of the nodes even if they already exist in the graph. Arguments: - parquet_path (str): Parquet file or directory of Parquet files containing the nodes - time (str): The column name for the timestamps. - id (str): The column name for the node IDs. - node_type (str, optional): A constant value to use as the node type for all nodes. Defaults to None. (cannot be used in combination with node_type_col) - node_type_col (str, optional): The node type col name in dataframe. Defaults to None. (cannot be used in combination with node_type) - properties (List[str], optional): List of node property column names. Defaults to None. - constant_properties (List[str], optional): List of constant node property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every node. Defaults to None. + nodes (List[Node]): A vector of node objects representing the nodes to be imported. + new_ids (List[str|int]): A list of node IDs to use for the imported nodes. + merge (bool): An optional boolean flag indicating whether to merge the import of the nodes. Defaults to False. Returns: None: This function does not return a value, if the operation is successful. @@ -1721,29 +1660,38 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def load_edges_from_pandas( + @staticmethod + def load_cached(path: str): + """ + Load PersistentGraph from a file and initialise it as a cache file. + + Future updates are tracked. Use `write_updates` to persist them to the + cache file. + + Arguments: + path (str): The path to the cache file + + Returns: + PersistentGraph + """ + + def load_edge_deletions_from_pandas( self, df: DataFrame, time: str, src: str, dst: str, - properties: Optional[List[str]] = None, - constant_properties: Optional[List[str]] = None, - shared_constant_properties: Optional[PropInput] = None, layer: Optional[str] = None, layer_col: Optional[str] = None, ) -> None: """ - Load edges from a Pandas DataFrame into the graph. + Load edges deletions from a Pandas DataFrame into the graph. Arguments: df (DataFrame): The Pandas DataFrame containing the edges. time (str): The column name for the update timestamps. src (str): The column name for the source node ids. dst (str): The column name for the destination node ids. - properties (List[str], optional): List of edge property column names. Defaults to None. - constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. layer (str, optional): A constant value to use as the layer for all edges. Defaults to None. (cannot be used in combination with layer_col) layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. (cannot be used in combination with layer) @@ -1754,29 +1702,23 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def load_edges_from_parquet( + def load_edge_deletions_from_parquet( self, parquet_path: str, time: str, src: str, dst: str, - properties: Optional[List[str]] = None, - constant_properties: Optional[List[str]] = None, - shared_constant_properties: Optional[PropInput] = None, layer: Optional[str] = None, layer_col: Optional[str] = None, ) -> None: """ - Load edges from a Parquet file into the graph. + Load edges deletions from a Parquet file into the graph. Arguments: - parquet_path (str): Parquet file or directory of Parquet files path containing edges - time (str): The column name for the update timestamps. + parquet_path (str): Parquet file or directory of Parquet files path containing node information. src (str): The column name for the source node ids. dst (str): The column name for the destination node ids. - properties (List[str], optional): List of edge property column names. Defaults to None. - constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. + time (str): The column name for the update timestamps. layer (str, optional): A constant value to use as the layer for all edges. Defaults to None. (cannot be used in combination with layer_col) layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. (cannot be used in combination with layer) @@ -1787,23 +1729,87 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def load_edge_deletions_from_pandas( + def load_edge_props_from_pandas( + self, + df: DataFrame, + src: str, + dst: str, + constant_properties: Optional[List[str]] = None, + shared_constant_properties: Optional[PropInput] = None, + layer: Optional[str] = None, + layer_col: Optional[str] = None, + ) -> None: + """ + Load edge properties from a Pandas DataFrame. + + Arguments: + df (DataFrame): The Pandas DataFrame containing edge information. + src (str): The column name for the source node. + dst (str): The column name for the destination node. + constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. + layer (str, optional): The edge layer name. Defaults to None. + layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. + + Returns: + None: This function does not return a value, if the operation is successful. + + Raises: + GraphError: If the operation fails. + """ + + def load_edge_props_from_parquet( + self, + parquet_path: str, + src: str, + dst: str, + constant_properties: Optional[List[str]] = None, + shared_constant_properties: Optional[PropInput] = None, + layer: Optional[str] = None, + layer_col: Optional[str] = None, + ) -> None: + """ + Load edge properties from parquet file + + Arguments: + parquet_path (str): Parquet file or directory of Parquet files path containing edge information. + src (str): The column name for the source node. + dst (str): The column name for the destination node. + constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. + layer (str, optional): The edge layer name. Defaults to None. + layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. + + Returns: + None: This function does not return a value, if the operation is successful. + + Raises: + GraphError: If the operation fails. + """ + + def load_edges_from_pandas( self, df: DataFrame, time: str, src: str, dst: str, + properties: Optional[List[str]] = None, + constant_properties: Optional[List[str]] = None, + shared_constant_properties: Optional[PropInput] = None, layer: Optional[str] = None, layer_col: Optional[str] = None, ) -> None: """ - Load edges deletions from a Pandas DataFrame into the graph. + Load edges from a Pandas DataFrame into the graph. Arguments: df (DataFrame): The Pandas DataFrame containing the edges. time (str): The column name for the update timestamps. src (str): The column name for the source node ids. dst (str): The column name for the destination node ids. + properties (List[str], optional): List of edge property column names. Defaults to None. + constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. layer (str, optional): A constant value to use as the layer for all edges. Defaults to None. (cannot be used in combination with layer_col) layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. (cannot be used in combination with layer) @@ -1814,23 +1820,29 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def load_edge_deletions_from_parquet( + def load_edges_from_parquet( self, parquet_path: str, time: str, src: str, dst: str, + properties: Optional[List[str]] = None, + constant_properties: Optional[List[str]] = None, + shared_constant_properties: Optional[PropInput] = None, layer: Optional[str] = None, layer_col: Optional[str] = None, ) -> None: """ - Load edges deletions from a Parquet file into the graph. + Load edges from a Parquet file into the graph. Arguments: - parquet_path (str): Parquet file or directory of Parquet files path containing node information. + parquet_path (str): Parquet file or directory of Parquet files path containing edges + time (str): The column name for the update timestamps. src (str): The column name for the source node ids. dst (str): The column name for the destination node ids. - time (str): The column name for the update timestamps. + properties (List[str], optional): List of edge property column names. Defaults to None. + constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. layer (str, optional): A constant value to use as the layer for all edges. Defaults to None. (cannot be used in combination with layer_col) layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. (cannot be used in combination with layer) @@ -1841,6 +1853,18 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ + @staticmethod + def load_from_file(path: str): + """ + Load PersistentGraph from a file. + + Arguments: + path (str): The path to the file. + + Returns: + PersistentGraph + """ + def load_node_props_from_pandas( self, df: DataFrame, @@ -1895,27 +1919,29 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def load_edge_props_from_pandas( + def load_nodes_from_pandas( self, df: DataFrame, - src: str, - dst: str, + time: str, + id: str, + node_type: Optional[str] = None, + node_type_col: Optional[str] = None, + properties: Optional[List[str]] = None, constant_properties: Optional[List[str]] = None, shared_constant_properties: Optional[PropInput] = None, - layer: Optional[str] = None, - layer_col: Optional[str] = None, ) -> None: """ - Load edge properties from a Pandas DataFrame. + Load nodes from a Pandas DataFrame into the graph. Arguments: - df (DataFrame): The Pandas DataFrame containing edge information. - src (str): The column name for the source node. - dst (str): The column name for the destination node. - constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. - layer (str, optional): The edge layer name. Defaults to None. - layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. + df (DataFrame): The Pandas DataFrame containing the nodes. + time (str): The column name for the timestamps. + id (str): The column name for the node IDs. + node_type (str, optional): A constant value to use as the node type for all nodes. Defaults to None. (cannot be used in combination with node_type_col) + node_type_col (str, optional): The node type col name in dataframe. Defaults to None. (cannot be used in combination with node_type) + properties (List[str], optional): List of node property column names. Defaults to None. + constant_properties (List[str], optional): List of constant node property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every node. Defaults to None. Returns: None: This function does not return a value, if the operation is successful. @@ -1924,27 +1950,29 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def load_edge_props_from_parquet( + def load_nodes_from_parquet( self, parquet_path: str, - src: str, - dst: str, + time: str, + id: str, + node_type: Optional[str] = None, + node_type_col: Optional[str] = None, + properties: Optional[List[str]] = None, constant_properties: Optional[List[str]] = None, shared_constant_properties: Optional[PropInput] = None, - layer: Optional[str] = None, - layer_col: Optional[str] = None, ) -> None: """ - Load edge properties from parquet file + Load nodes from a Parquet file into the graph. Arguments: - parquet_path (str): Parquet file or directory of Parquet files path containing edge information. - src (str): The column name for the source node. - dst (str): The column name for the destination node. - constant_properties (List[str], optional): List of constant edge property column names. Defaults to None. - shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every edge. Defaults to None. - layer (str, optional): The edge layer name. Defaults to None. - layer_col (str, optional): The edge layer col name in dataframe. Defaults to None. + parquet_path (str): Parquet file or directory of Parquet files containing the nodes + time (str): The column name for the timestamps. + id (str): The column name for the node IDs. + node_type (str, optional): A constant value to use as the node type for all nodes. Defaults to None. (cannot be used in combination with node_type_col) + node_type_col (str, optional): The node type col name in dataframe. Defaults to None. (cannot be used in combination with node_type) + properties (List[str], optional): List of node property column names. Defaults to None. + constant_properties (List[str], optional): List of constant node property column names. Defaults to None. + shared_constant_properties (PropInput, optional): A dictionary of constant properties that will be added to every node. Defaults to None. Returns: None: This function does not return a value, if the operation is successful. @@ -1953,47 +1981,18 @@ class PersistentGraph(GraphView): GraphError: If the operation fails. """ - def cache(self, path: str): + def node(self, id: str | int): """ - Write PersistentGraph to cache file and initialise the cache. - - Future updates are tracked. Use `write_updates` to persist them to the - cache file. If the file already exists its contents are overwritten. + Gets the node with the specified id Arguments: - path (str): The path to the cache file - """ - - def write_updates(self): - """Persist the new updates by appending them to the cache file.""" - - @staticmethod - def load_cached(path: str): - """ - Load PersistentGraph from a file and initialise it as a cache file. - - Future updates are tracked. Use `write_updates` to persist them to the - cache file. - - Arguments: - path (str): The path to the cache file - - Returns: - PersistentGraph - """ - - @staticmethod - def load_from_file(path: str): - """ - Load PersistentGraph from a file. - - Arguments: - path (str): The path to the file. + id (str | int): the node id Returns: - PersistentGraph + The node with the specified id, or None if the node does not exist """ + def persistent_graph(self): ... def save_to_file(self, path: str): """ Saves the PersistentGraph to the given path. @@ -2010,149 +2009,163 @@ class PersistentGraph(GraphView): path (str): The path to the file. """ - @staticmethod - def deserialise(bytes: bytes): + def serialise(self): """ - Load PersistentGraph from serialised bytes. - - Arguments: - bytes (bytes): The serialised bytes to decode + Serialise PersistentGraph to bytes. Returns: - PersistentGraph + bytes """ - def serialise(self): + def update_constant_properties(self, properties: dict) -> None: """ - Serialise PersistentGraph to bytes. + Updates static properties to the graph. + + Arguments: + properties (dict): The static properties of the graph. Returns: - bytes + None: This function does not return a value, if the operation is successful. + + Raises: + GraphError: If the operation fails. """ -class PyGraphEncoder(object): - def __new__(cls) -> PyGraphEncoder: - """Create and return a new object. See help(type) for accurate signature.""" + def write_updates(self): + """Persist the new updates by appending them to the cache file.""" +class PyGraphEncoder(object): def __call__(self, *args, **kwargs): """Call self as a function.""" - def __setstate__(self): ... def __getstate__(self): ... + def __new__(cls) -> PyGraphEncoder: + """Create and return a new object. See help(type) for accurate signature.""" + + def __setstate__(self): ... class Node(object): """A node (or node) in the graph.""" - def __repr__(self): - """Return repr(self).""" + def __eq__(self, value): + """Return self==value.""" + + def __ge__(self, value): + """Return self>=value.""" + + def __getitem__(self, key): + """Return self[key].""" + + def __gt__(self, value): + """Return self>value.""" def __hash__(self): """Return hash(self).""" - def __lt__(self, value): - """Return selfvalue.""" + def __repr__(self): + """Return repr(self).""" - def __ge__(self, value): - """Return self>=value.""" + def after(self, start: TimeInput): + """ + Create a view of the Node including all events after `start` (exclusive). - def __getitem__(self, key): - """Return self[key].""" + Arguments: + start (TimeInput): The start time of the window. - def degree(self): + Returns: + Node """ - Get the degree of this node (i.e., the number of edges that are incident to it). - Returns - int: The degree of this node. + def at(self, time: TimeInput): """ + Create a view of the Node including all events at `time`. - def in_degree(self) -> int: - """ - Get the in-degree of this node (i.e., the number of edges that are incident to it from other nodes). + Arguments: + time (TimeInput): The time of the window. Returns: - int: The in-degree of this node. + Node """ - def out_degree(self) -> int: + def before(self, end: TimeInput): """ - Get the out-degree of this node (i.e., the number of edges that are incident to it from this node). + Create a view of the Node including all events before `end` (exclusive). + + Arguments: + end (TimeInput): The end time of the window. Returns: - int: The out-degree of this node. + Node """ - def history(self) -> List[int]: + def default_layer(self) -> Node: """ - Returns the history of a node, including node additions and changes made to node. - + Return a view of Node containing only the default edge layer Returns: - List[int]: A list of unix timestamps of the event history of node. + Node: The layered view """ - def history_date_time(self) -> List[datetime]: + def degree(self): """ - Returns the history of a node, including node additions and changes made to node. + Get the degree of this node (i.e., the number of edges that are incident to it). - Returns: - List[datetime]: A list of timestamps of the event history of node. + Returns + int: The degree of this node. + """ + @property + def earliest_date_time(self): """ + Returns the earliest datetime that the node exists. - def is_active(self): ... - def filter_edges(self, filter) -> Node: + Returns: + Datetime: The earliest datetime that the node exists as a Datetime. """ - Return a filtered view that only includes edges that satisfy the filter - Arguments - filter (PropertyFilter): The filter to apply to the edge properties. Construct a - filter using `Prop`. + @property + def earliest_time(self): + """ + Returns the earliest time that the node exists. Returns: - Node: The filtered view + int: The earliest time that the node exists as an integer. """ - def filter_exploded_edges(self, filter: PropertyFilter) -> Node: + @property + def edges(self): """ - Return a filtered view that only includes exploded edges that satisfy the filter - - Arguments: - filter (PropertyFilter): The filter to apply to the exploded edge properties. Construct a - filter using `Prop`. + Get the edges that are incident to this node. Returns: - Node: The filtered view + + An iterator over the edges that are incident to this node. """ - def default_layer(self) -> Node: + @property + def end(self): """ - Return a view of Node containing only the default edge layer + Gets the latest time that this Node is valid. + Returns: - Node: The layered view + Optional[int]: The latest time that this Node is valid or None if the Node is valid for all times. """ - def layer(self, name: str) -> Node: + @property + def end_date_time(self): """ - Return a view of Node containing the layer `"name"` - Errors if the layer does not exist - - Arguments: - name (str): then name of the layer. + Gets the latest datetime that this Node is valid Returns: - Node: The layered view + Optional[Datetime]: The latest datetime that this Node is valid or None if the Node is valid for all times. """ def exclude_layer(self, name: str) -> Node: @@ -2167,71 +2180,73 @@ class Node(object): Node: The layered view """ - def exclude_valid_layer(self, name: str) -> Node: + def exclude_layers(self, names: list[str]) -> Node: """ - Return a view of Node containing all layers except the excluded `name` + Return a view of Node containing all layers except the excluded `names` + Errors if any of the layers do not exist. + Arguments: - name (str): layer name that is excluded for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: Node: The layered view """ - def has_layer(self, name: str): + def exclude_valid_layer(self, name: str) -> Node: """ - Check if Node has the layer `"name"` - + Return a view of Node containing all layers except the excluded `name` Arguments: - name (str): the name of the layer to check + name (str): layer name that is excluded for the new view Returns: - bool + Node: The layered view """ - def layers(self, names: list[str]) -> Node: + def exclude_valid_layers(self, names: list[str]) -> Node: """ - Return a view of Node containing all layers `names` - Errors if any of the layers do not exist. - + Return a view of Node containing all layers except the excluded `names` Arguments: - names (list[str]): list of layer names for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: Node: The layered view """ - def exclude_layers(self, names: list[str]) -> Node: + def expanding(self, step: int | str) -> WindowSet: """ - Return a view of Node containing all layers except the excluded `names` - Errors if any of the layers do not exist. + Creates a `WindowSet` with the given `step` size using an expanding window. + + An expanding window is a window that grows by `step` size at each iteration. Arguments: - names (list[str]): list of layer names that are excluded for the new view + step (int | str): The step size of the window. Returns: - Node: The layered view + WindowSet: A `WindowSet` object. """ - def exclude_valid_layers(self, names: list[str]) -> Node: + def filter_edges(self, filter) -> Node: """ - Return a view of Node containing all layers except the excluded `names` - Arguments: - names (list[str]): list of layer names that are excluded for the new view + Return a filtered view that only includes edges that satisfy the filter + + Arguments + filter (PropertyFilter): The filter to apply to the edge properties. Construct a + filter using `Prop`. Returns: - Node: The layered view + Node: The filtered view """ - def valid_layers(self, names: list[str]) -> Node: + def filter_exploded_edges(self, filter: PropertyFilter) -> Node: """ - Return a view of Node containing all layers `names` - Any layers that do not exist are ignored + Return a filtered view that only includes exploded edges that satisfy the filter Arguments: - names (list[str]): list of layer names for the new view + filter (PropertyFilter): The filter to apply to the exploded edge properties. Construct a + filter using `Prop`. Returns: - Node: The layered view + Node: The filtered view """ def filter_nodes(self, filter) -> Node: @@ -2246,464 +2261,437 @@ class Node(object): Node: The filtered view """ - def expanding(self, step: int | str) -> WindowSet: + def has_layer(self, name: str): """ - Creates a `WindowSet` with the given `step` size using an expanding window. - - An expanding window is a window that grows by `step` size at each iteration. + Check if Node has the layer `"name"` Arguments: - step (int | str): The step size of the window. + name (str): the name of the layer to check Returns: - WindowSet: A `WindowSet` object. + bool """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: + def history(self) -> List[int]: """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - - A rolling window is a window that moves forward by `step` size at each iteration. - - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + Returns the history of a node, including node additions and changes made to node. Returns: - WindowSet: A `WindowSet` object. + List[int]: A list of unix timestamps of the event history of node. """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def history_date_time(self) -> List[datetime]: """ - Create a view of the Node including all events between `start` (inclusive) and `end` (exclusive) - - Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + Returns the history of a node, including node additions and changes made to node. Returns: - r Node - """ + List[datetime]: A list of timestamps of the event history of node. - def at(self, time: TimeInput): """ - Create a view of the Node including all events at `time`. - Arguments: - time (TimeInput): The time of the window. + @property + def id(self): + """ + Returns the id of the node. + This is a unique identifier for the node. Returns: - Node + (str|int): The id of the node. """ - def latest(self): + def in_degree(self) -> int: """ - Create a view of the Node including all events at the latest time. + Get the in-degree of this node (i.e., the number of edges that are incident to it from other nodes). Returns: - Node + int: The in-degree of this node. """ - def snapshot_at(self, time: TimeInput): + @property + def in_edges(self): """ - Create a view of the Node including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s - - Arguments: - time (TimeInput): The time of the window. + Get the edges that point into this node. Returns: - Node - """ - def snapshot_latest(self): + An iterator over the edges that point into this node. """ - Create a view of the Node including all events that have not been explicitly deleted at the latest time. - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + @property + def in_neighbours(self): + """ + Get the neighbours of this node that point into this node. Returns: - Node - """ - def before(self, end: TimeInput): + An iterator over the neighbours of this node that point into this node. """ - Create a view of the Node including all events before `end` (exclusive). - Arguments: - end (TimeInput): The end time of the window. + def is_active(self): ... + def latest(self): + """ + Create a view of the Node including all events at the latest time. Returns: Node """ - def after(self, start: TimeInput): + @property + def latest_date_time(self): """ - Create a view of the Node including all events after `start` (exclusive). + Returns the latest datetime that the node exists. Arguments: - start (TimeInput): The start time of the window. + None Returns: - Node + Datetime: The latest datetime that the node exists as a Datetime. """ - def shrink_start(self, start: TimeInput): + @property + def latest_time(self): """ - Set the start of the window to the larger of `start` and `self.start()` - - Arguments: - start (TimeInput): the new start time of the window + Returns the latest time that the node exists. Returns: - Node + int: The latest time that the node exists as an integer. """ - def shrink_end(self, end: TimeInput): + def layer(self, name: str) -> Node: """ - Set the end of the window to the smaller of `end` and `self.end()` + Return a view of Node containing the layer `"name"` + Errors if the layer does not exist Arguments: - end (TimeInput): the new end time of the window + name (str): then name of the layer. + Returns: - Node + Node: The layered view """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def layers(self, names: list[str]) -> Node: """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + Return a view of Node containing all layers `names` + Errors if any of the layers do not exist. Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + names (list[str]): list of layer names for the new view + Returns: + Node: The layered view """ @property - def latest_date_time(self): + def name(self): """ - Returns the latest datetime that the node exists. - - Arguments: - None + Returns the name of the node. Returns: - Datetime: The latest datetime that the node exists as a Datetime. + str: The id of the node as a string. """ @property - def start(self): + def neighbours(self): """ - Gets the start time for rolling and expanding windows for this Node + Get the neighbours of this node. Returns: - Optional[int]: The earliest time that this Node is valid or None if the Node is valid for all times. + + An iterator over the neighbours of this node. """ @property def node_type(self): """Returns the type of node""" - @property - def start_date_time(self): + def out_degree(self) -> int: """ - Gets the earliest datetime that this Node is valid + Get the out-degree of this node (i.e., the number of edges that are incident to it from this node). Returns: - Optional[Datetime]: The earliest datetime that this Node is valid or None if the Node is valid for all times. + int: The out-degree of this node. """ @property - def window_size(self): + def out_edges(self): """ - Get the window size (difference between start and end) for this Node + Get the edges that point out of this node. Returns: - Optional[int] + + An iterator over the edges that point out of this node. """ @property - def end_date_time(self): + def out_neighbours(self): """ - Gets the latest datetime that this Node is valid + Get the neighbours of this node that point out of this node. Returns: - Optional[Datetime]: The latest datetime that this Node is valid or None if the Node is valid for all times. + + An iterator over the neighbours of this node that point out of this node. """ @property - def end(self): + def properties(self): """ - Gets the latest time that this Node is valid. + The properties of the node Returns: - Optional[int]: The latest time that this Node is valid or None if the Node is valid for all times. + Properties: A list of properties. """ - @property - def in_edges(self): + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Get the edges that point into this node. + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - Returns: + A rolling window is a window that moves forward by `step` size at each iteration. - An iterator over the edges that point into this node. + Arguments: + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. + + Returns: + WindowSet: A `WindowSet` object. """ - @property - def neighbours(self): + def shrink_end(self, end: TimeInput): """ - Get the neighbours of this node. + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - - An iterator over the neighbours of this node. + Node """ - @property - def in_neighbours(self): + def shrink_start(self, start: TimeInput): """ - Get the neighbours of this node that point into this node. + Set the start of the window to the larger of `start` and `self.start()` - Returns: + Arguments: + start (TimeInput): the new start time of the window - An iterator over the neighbours of this node that point into this node. + Returns: + Node """ - @property - def earliest_date_time(self): + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Returns the earliest datetime that the node exists. + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - Returns: - Datetime: The earliest datetime that the node exists as a Datetime. """ - @property - def edges(self): + def snapshot_at(self, time: TimeInput): """ - Get the edges that are incident to this node. + Create a view of the Node including all events that have not been explicitly deleted at `time`. - Returns: + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s - An iterator over the edges that are incident to this node. + Arguments: + time (TimeInput): The time of the window. + + Returns: + Node """ - @property - def latest_time(self): + def snapshot_latest(self): """ - Returns the latest time that the node exists. + Create a view of the Node including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - int: The latest time that the node exists as an integer. + Node """ @property - def out_edges(self): + def start(self): """ - Get the edges that point out of this node. + Gets the start time for rolling and expanding windows for this Node Returns: - - An iterator over the edges that point out of this node. + Optional[int]: The earliest time that this Node is valid or None if the Node is valid for all times. """ @property - def id(self): + def start_date_time(self): """ - Returns the id of the node. - This is a unique identifier for the node. + Gets the earliest datetime that this Node is valid Returns: - (str|int): The id of the node. + Optional[Datetime]: The earliest datetime that this Node is valid or None if the Node is valid for all times. """ - @property - def properties(self): + def valid_layers(self, names: list[str]) -> Node: """ - The properties of the node + Return a view of Node containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Properties: A list of properties. + Node: The layered view """ - @property - def name(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Returns the name of the node. + Create a view of the Node including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - str: The id of the node as a string. + r Node """ @property - def out_neighbours(self): + def window_size(self): """ - Get the neighbours of this node that point out of this node. - - Returns: - - An iterator over the neighbours of this node that point out of this node. - """ - - @property - def earliest_time(self): - """ - Returns the earliest time that the node exists. + Get the window size (difference between start and end) for this Node Returns: - int: The earliest time that the node exists as an integer. + Optional[int] """ class Nodes(object): """A list of nodes that can be iterated over.""" - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" - def __bool__(self): - """True if self else False""" + def __le__(self, value): + """Return self<=value.""" def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self list[Node]: """ - Returns the number of out edges of the nodes + Collect all nodes into a list Returns: - An iterator of the number of out edges of the nodes + list[Node]: the list of nodes """ - def to_df( - self, include_property_history: bool = False, convert_datetime: bool = False - ): + def default_layer(self) -> Nodes: """ - Converts the graph's nodes into a Pandas DataFrame. - - This method will create a DataFrame with the following columns: - - "name": The name of the node. - - "properties": The properties of the node. - - "update_history": The update history of the node. - - Args: - include_property_history (bool): A boolean, if set to `true`, the history of each property is included, if `false`, only the latest value is shown. - convert_datetime (bool): A boolean, if set to `true` will convert the timestamp to python datetimes, defaults to `false` - + Return a view of Nodes containing only the default edge layer Returns: - If successful, this PyObject will be a Pandas DataFrame. + Nodes: The layered view """ - def type_filter(self, node_types): ... - def collect(self) -> list[Node]: + def degree(self): """ - Collect all nodes into a list + Returns the number of edges of the nodes Returns: - list[Node]: the list of nodes + An iterator of the number of edges of the nodes """ - def filter_edges(self, filter) -> Nodes: + @property + def earliest_date_time(self): """ - Return a filtered view that only includes edges that satisfy the filter - - Arguments - filter (PropertyFilter): The filter to apply to the edge properties. Construct a - filter using `Prop`. + Returns the earliest time of the nodes. Returns: - Nodes: The filtered view + Earliest time of the nodes. """ - def filter_exploded_edges(self, filter: PropertyFilter) -> Nodes: - """ - Return a filtered view that only includes exploded edges that satisfy the filter + @property + def earliest_time(self): + """Returns an iterator over the nodes earliest time""" - Arguments: - filter (PropertyFilter): The filter to apply to the exploded edge properties. Construct a - filter using `Prop`. + @property + def edges(self): + """ + Get the edges that are incident to this node. Returns: - Nodes: The filtered view + + An iterator over the edges that are incident to this node. """ - def default_layer(self) -> Nodes: + @property + def end(self): """ - Return a view of Nodes containing only the default edge layer + Gets the latest time that this Nodes is valid. + Returns: - Nodes: The layered view + Optional[int]: The latest time that this Nodes is valid or None if the Nodes is valid for all times. """ - def layer(self, name: str) -> Nodes: + @property + def end_date_time(self): """ - Return a view of Nodes containing the layer `"name"` - Errors if the layer does not exist - - Arguments: - name (str): then name of the layer. + Gets the latest datetime that this Nodes is valid Returns: - Nodes: The layered view + Optional[Datetime]: The latest datetime that this Nodes is valid or None if the Nodes is valid for all times. """ def exclude_layer(self, name: str) -> Nodes: @@ -2718,71 +2706,73 @@ class Nodes(object): Nodes: The layered view """ - def exclude_valid_layer(self, name: str) -> Nodes: + def exclude_layers(self, names: list[str]) -> Nodes: """ - Return a view of Nodes containing all layers except the excluded `name` + Return a view of Nodes containing all layers except the excluded `names` + Errors if any of the layers do not exist. + Arguments: - name (str): layer name that is excluded for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: Nodes: The layered view """ - def has_layer(self, name: str): + def exclude_valid_layer(self, name: str) -> Nodes: """ - Check if Nodes has the layer `"name"` - + Return a view of Nodes containing all layers except the excluded `name` Arguments: - name (str): the name of the layer to check + name (str): layer name that is excluded for the new view Returns: - bool + Nodes: The layered view """ - def layers(self, names: list[str]) -> Nodes: + def exclude_valid_layers(self, names: list[str]) -> Nodes: """ - Return a view of Nodes containing all layers `names` - Errors if any of the layers do not exist. - + Return a view of Nodes containing all layers except the excluded `names` Arguments: - names (list[str]): list of layer names for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: Nodes: The layered view """ - def exclude_layers(self, names: list[str]) -> Nodes: + def expanding(self, step: int | str) -> WindowSet: """ - Return a view of Nodes containing all layers except the excluded `names` - Errors if any of the layers do not exist. + Creates a `WindowSet` with the given `step` size using an expanding window. + + An expanding window is a window that grows by `step` size at each iteration. Arguments: - names (list[str]): list of layer names that are excluded for the new view + step (int | str): The step size of the window. Returns: - Nodes: The layered view + WindowSet: A `WindowSet` object. """ - def exclude_valid_layers(self, names: list[str]) -> Nodes: + def filter_edges(self, filter) -> Nodes: """ - Return a view of Nodes containing all layers except the excluded `names` - Arguments: - names (list[str]): list of layer names that are excluded for the new view + Return a filtered view that only includes edges that satisfy the filter + + Arguments + filter (PropertyFilter): The filter to apply to the edge properties. Construct a + filter using `Prop`. Returns: - Nodes: The layered view + Nodes: The filtered view """ - def valid_layers(self, names: list[str]) -> Nodes: + def filter_exploded_edges(self, filter: PropertyFilter) -> Nodes: """ - Return a view of Nodes containing all layers `names` - Any layers that do not exist are ignored + Return a filtered view that only includes exploded edges that satisfy the filter Arguments: - names (list[str]): list of layer names for the new view + filter (PropertyFilter): The filter to apply to the exploded edge properties. Construct a + filter using `Prop`. Returns: - Nodes: The layered view + Nodes: The filtered view """ def filter_nodes(self, filter) -> Nodes: @@ -2797,304 +2787,319 @@ class Nodes(object): Nodes: The filtered view """ - def expanding(self, step: int | str) -> WindowSet: + def has_layer(self, name: str): """ - Creates a `WindowSet` with the given `step` size using an expanding window. - - An expanding window is a window that grows by `step` size at each iteration. + Check if Nodes has the layer `"name"` Arguments: - step (int | str): The step size of the window. + name (str): the name of the layer to check Returns: - WindowSet: A `WindowSet` object. + bool """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: + def history(self): """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - - A rolling window is a window that moves forward by `step` size at each iteration. - - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + Returns all timestamps of nodes, when an node is added or change to an node is made. Returns: - WindowSet: A `WindowSet` object. - """ + A list of unix timestamps. - def window(self, start: TimeInput | None, end: TimeInput | None): """ - Create a view of the Nodes including all events between `start` (inclusive) and `end` (exclusive) - Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + def history_date_time(self): + """ + Returns all timestamps of nodes, when an node is added or change to an node is made. Returns: - r Nodes - """ + An list of timestamps. - def at(self, time: TimeInput): """ - Create a view of the Nodes including all events at `time`. - Arguments: - time (TimeInput): The time of the window. + @property + def id(self): + """Returns an iterator over the nodes ids""" - Returns: - Nodes - """ - - def latest(self): + def in_degree(self): """ - Create a view of the Nodes including all events at the latest time. + Returns the number of in edges of the nodes Returns: - Nodes + An iterator of the number of in edges of the nodes """ - def snapshot_at(self, time: TimeInput): + @property + def in_edges(self): """ - Create a view of the Nodes including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s - - Arguments: - time (TimeInput): The time of the window. + Get the edges that point into this node. Returns: - Nodes - """ - def snapshot_latest(self): + An iterator over the edges that point into this node. """ - Create a view of the Nodes including all events that have not been explicitly deleted at the latest time. - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + @property + def in_neighbours(self): + """ + Get the neighbours of this node that point into this node. Returns: - Nodes - """ - def before(self, end: TimeInput): + An iterator over the neighbours of this node that point into this node. """ - Create a view of the Nodes including all events before `end` (exclusive). - Arguments: - end (TimeInput): The end time of the window. + def latest(self): + """ + Create a view of the Nodes including all events at the latest time. Returns: Nodes """ - def after(self, start: TimeInput): + @property + def latest_date_time(self): """ - Create a view of the Nodes including all events after `start` (exclusive). - - Arguments: - start (TimeInput): The start time of the window. + Returns the latest date time of the nodes. Returns: - Nodes + Latest date time of the nodes. """ - def shrink_start(self, start: TimeInput): + @property + def latest_time(self): + """Returns an iterator over the nodes latest time""" + + def layer(self, name: str) -> Nodes: """ - Set the start of the window to the larger of `start` and `self.start()` + Return a view of Nodes containing the layer `"name"` + Errors if the layer does not exist Arguments: - start (TimeInput): the new start time of the window + name (str): then name of the layer. Returns: - Nodes + Nodes: The layered view """ - def shrink_end(self, end: TimeInput): + def layers(self, names: list[str]) -> Nodes: """ - Set the end of the window to the smaller of `end` and `self.end()` + Return a view of Nodes containing all layers `names` + Errors if any of the layers do not exist. Arguments: - end (TimeInput): the new end time of the window + names (list[str]): list of layer names for the new view + Returns: - Nodes + Nodes: The layered view """ - def shrink_window(self, start: TimeInput, end: TimeInput): + @property + def name(self): + """Returns an iterator over the nodes name""" + + @property + def neighbours(self): """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + Get the neighbours of this node. - Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + Returns: + An iterator over the neighbours of this node. """ @property - def start(self): + def node_type(self): + """Returns the type of node""" + + def out_degree(self): """ - Gets the start time for rolling and expanding windows for this Nodes + Returns the number of out edges of the nodes Returns: - Optional[int]: The earliest time that this Nodes is valid or None if the Nodes is valid for all times. + An iterator of the number of out edges of the nodes """ @property - def start_date_time(self): + def out_edges(self): """ - Gets the earliest datetime that this Nodes is valid + Get the edges that point out of this node. Returns: - Optional[Datetime]: The earliest datetime that this Nodes is valid or None if the Nodes is valid for all times. + + An iterator over the edges that point out of this node. """ @property - def window_size(self): + def out_neighbours(self): """ - Get the window size (difference between start and end) for this Nodes + Get the neighbours of this node that point out of this node. Returns: - Optional[int] + + An iterator over the neighbours of this node that point out of this node. """ @property - def in_neighbours(self): + def properties(self): """ - Get the neighbours of this node that point into this node. + The properties of the node Returns: - - An iterator over the neighbours of this node that point into this node. + A List of properties """ - @property - def out_neighbours(self): + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Get the neighbours of this node that point out of this node. + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - Returns: + A rolling window is a window that moves forward by `step` size at each iteration. - An iterator over the neighbours of this node that point out of this node. + Arguments: + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. + + Returns: + WindowSet: A `WindowSet` object. """ - @property - def out_edges(self): + def shrink_end(self, end: TimeInput): """ - Get the edges that point out of this node. + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - - An iterator over the edges that point out of this node. + Nodes """ - @property - def neighbours(self): + def shrink_start(self, start: TimeInput): """ - Get the neighbours of this node. + Set the start of the window to the larger of `start` and `self.start()` + + Arguments: + start (TimeInput): the new start time of the window Returns: + Nodes + """ - An iterator over the neighbours of this node. + def shrink_window(self, start: TimeInput, end: TimeInput): """ + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - @property - def id(self): - """Returns an iterator over the nodes ids""" + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - @property - def in_edges(self): """ - Get the edges that point into this node. - Returns: + def snapshot_at(self, time: TimeInput): + """ + Create a view of the Nodes including all events that have not been explicitly deleted at `time`. - An iterator over the edges that point into this node. + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. + + Returns: + Nodes """ - @property - def latest_date_time(self): + def snapshot_latest(self): """ - Returns the latest date time of the nodes. + Create a view of the Nodes including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Latest date time of the nodes. + Nodes """ @property - def end(self): + def start(self): """ - Gets the latest time that this Nodes is valid. + Gets the start time for rolling and expanding windows for this Nodes Returns: - Optional[int]: The latest time that this Nodes is valid or None if the Nodes is valid for all times. + Optional[int]: The earliest time that this Nodes is valid or None if the Nodes is valid for all times. """ @property - def end_date_time(self): + def start_date_time(self): """ - Gets the latest datetime that this Nodes is valid + Gets the earliest datetime that this Nodes is valid Returns: - Optional[Datetime]: The latest datetime that this Nodes is valid or None if the Nodes is valid for all times. + Optional[Datetime]: The earliest datetime that this Nodes is valid or None if the Nodes is valid for all times. """ - @property - def latest_time(self): - """Returns an iterator over the nodes latest time""" + def to_df( + self, include_property_history: bool = False, convert_datetime: bool = False + ): + """ + Converts the graph's nodes into a Pandas DataFrame. - @property - def earliest_time(self): - """Returns an iterator over the nodes earliest time""" + This method will create a DataFrame with the following columns: + - "name": The name of the node. + - "properties": The properties of the node. + - "update_history": The update history of the node. - @property - def name(self): - """Returns an iterator over the nodes name""" + Args: + include_property_history (bool): A boolean, if set to `true`, the history of each property is included, if `false`, only the latest value is shown. + convert_datetime (bool): A boolean, if set to `true` will convert the timestamp to python datetimes, defaults to `false` - @property - def earliest_date_time(self): + Returns: + If successful, this PyObject will be a Pandas DataFrame. """ - Returns the earliest time of the nodes. - Returns: - Earliest time of the nodes. + def type_filter(self, node_types): ... + def valid_layers(self, names: list[str]) -> Nodes: """ + Return a view of Nodes containing all layers `names` + Any layers that do not exist are ignored - @property - def node_type(self): - """Returns the type of node""" + Arguments: + names (list[str]): list of layer names for the new view - @property - def edges(self): + Returns: + Nodes: The layered view """ - Get the edges that are incident to this node. - Returns: + def window(self, start: TimeInput | None, end: TimeInput | None): + """ + Create a view of the Nodes including all events between `start` (inclusive) and `end` (exclusive) - An iterator over the edges that are incident to this node. + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). + + Returns: + r Nodes """ @property - def properties(self): + def window_size(self): """ - The properties of the node + Get the window size (difference between start and end) for this Nodes Returns: - A List of properties + Optional[int] """ class MutableNode(Node): def __repr__(self): """Return repr(self).""" - def set_node_type(self, new_type: str): + def add_constant_properties(self, properties: PropInput): """ - Set the type on the node. This only works if the type has not been previously set, otherwise will - throw an error + Add constant properties to a node in the graph. + This function is used to add properties to a node that remain constant and do not + change over time. These properties are fundamental attributes of the node. Parameters: - new_type (str): The new type to be set + properties (PropInput): A dictionary of properties to be added to the node. Each key is a string representing the property name, and each value is of type Prop representing the property value. """ def add_updates( @@ -3122,14 +3127,13 @@ class MutableNode(Node): GraphError: If the operation fails. """ - def add_constant_properties(self, properties: PropInput): + def set_node_type(self, new_type: str): """ - Add constant properties to a node in the graph. - This function is used to add properties to a node that remain constant and do not - change over time. These properties are fundamental attributes of the node. + Set the type on the node. This only works if the type has not been previously set, otherwise will + throw an error Parameters: - properties (PropInput): A dictionary of properties to be added to the node. Each key is a string representing the property name, and each value is of type Prop representing the property value. + new_type (str): The new type to be set """ def update_constant_properties(self, properties: PropInput): @@ -3148,169 +3152,145 @@ class Edge(object): An edge is a directed connection between two nodes. """ - def __repr__(self): - """Return repr(self).""" - - def __hash__(self): - """Return hash(self).""" - - def __lt__(self, value): - """Return selfvalue.""" - def __ge__(self, value): """Return self>=value.""" def __getitem__(self, key): """Return self[key].""" - def history(self) -> List[int]: - """ - Returns a list of timestamps of when an edge is added or change to an edge is made. + def __gt__(self, value): + """Return self>value.""" - Returns: - List[int]: A list of unix timestamps. + def __hash__(self): + """Return hash(self).""" - """ + def __le__(self, value): + """Return self<=value.""" - def history_counts(self) -> int: - """ - Returns the number of times an edge is added or change to an edge is made. + def __lt__(self, value): + """Return self List[int]: + def at(self, time: TimeInput): """ - Returns a list of timestamps of when an edge is deleted + Create a view of the Edge including all events at `time`. + + Arguments: + time (TimeInput): The time of the window. Returns: - List[int]: A list of unix timestamps + Edge """ - def deletions_data_time(self): + def before(self, end: TimeInput): """ - Returns a list of timestamps of when an edge is deleted + Create a view of the Edge including all events before `end` (exclusive). - Returns: - List[Datetime] - """ + Arguments: + end (TimeInput): The end time of the window. - def is_valid(self): - """ - Check if the edge is currently valid (i.e., not deleted) Returns: - bool + Edge """ - def is_active(self): + @property + def date_time(self): """ - Check if the edge is currently active (i.e., has at least one update within this period) + Gets the datetime of an exploded edge. + Returns: - bool + Datetime: the datetime of an exploded edge """ - def is_deleted(self): + def default_layer(self) -> Edge: """ - Check if the edge is currently deleted + Return a view of Edge containing only the default edge layer Returns: - bool + Edge: The layered view """ - def is_self_loop(self): + def deletions(self) -> List[int]: """ - Check if the edge is on the same node + Returns a list of timestamps of when an edge is deleted + Returns: - bool + List[int]: A list of unix timestamps """ - def explode(self): - """Explodes returns an edge object for each update within the original edge.""" - - def explode_layers(self): - """Explode layers returns an edge object for each layer within the original edge. These new edge object contains only updates from respective layers.""" - - def default_layer(self) -> Edge: + def deletions_data_time(self): """ - Return a view of Edge containing only the default edge layer + Returns a list of timestamps of when an edge is deleted + Returns: - Edge: The layered view + List[Datetime] """ - def layer(self, name: str) -> Edge: - """ - Return a view of Edge containing the layer `"name"` - Errors if the layer does not exist + @property + def dst(self): + """Returns the destination node of the edge.""" - Arguments: - name (str): then name of the layer. + @property + def earliest_date_time(self): + """ + Gets of earliest datetime of an edge. Returns: - Edge: The layered view + Datetime: the earliest datetime of an edge """ - def exclude_layer(self, name: str) -> Edge: + @property + def earliest_time(self): """ - Return a view of Edge containing all layers except the excluded `name` - Errors if any of the layers do not exist. - - Arguments: - name (str): layer name that is excluded for the new view + Gets the earliest time of an edge. Returns: - Edge: The layered view + int: The earliest time of an edge """ - def exclude_valid_layer(self, name: str) -> Edge: + @property + def end(self): """ - Return a view of Edge containing all layers except the excluded `name` - Arguments: - name (str): layer name that is excluded for the new view + Gets the latest time that this Edge is valid. Returns: - Edge: The layered view + Optional[int]: The latest time that this Edge is valid or None if the Edge is valid for all times. """ - def has_layer(self, name: str): + @property + def end_date_time(self): """ - Check if Edge has the layer `"name"` - - Arguments: - name (str): the name of the layer to check + Gets the latest datetime that this Edge is valid Returns: - bool + Optional[Datetime]: The latest datetime that this Edge is valid or None if the Edge is valid for all times. """ - def layers(self, names: list[str]) -> Edge: + def exclude_layer(self, name: str) -> Edge: """ - Return a view of Edge containing all layers `names` + Return a view of Edge containing all layers except the excluded `name` Errors if any of the layers do not exist. Arguments: - names (list[str]): list of layer names for the new view + name (str): layer name that is excluded for the new view Returns: Edge: The layered view @@ -3328,23 +3308,21 @@ class Edge(object): Edge: The layered view """ - def exclude_valid_layers(self, names: list[str]) -> Edge: + def exclude_valid_layer(self, name: str) -> Edge: """ - Return a view of Edge containing all layers except the excluded `names` + Return a view of Edge containing all layers except the excluded `name` Arguments: - names (list[str]): list of layer names that are excluded for the new view + name (str): layer name that is excluded for the new view Returns: Edge: The layered view """ - def valid_layers(self, names: list[str]) -> Edge: + def exclude_valid_layers(self, names: list[str]) -> Edge: """ - Return a view of Edge containing all layers `names` - Any layers that do not exist are ignored - + Return a view of Edge containing all layers except the excluded `names` Arguments: - names (list[str]): list of layer names for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: Edge: The layered view @@ -3363,126 +3341,127 @@ class Edge(object): WindowSet: A `WindowSet` object. """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: - """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + def explode(self): + """Explodes returns an edge object for each update within the original edge.""" - A rolling window is a window that moves forward by `step` size at each iteration. + def explode_layers(self): + """Explode layers returns an edge object for each layer within the original edge. These new edge object contains only updates from respective layers.""" + + def has_layer(self, name: str): + """ + Check if Edge has the layer `"name"` Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + name (str): the name of the layer to check Returns: - WindowSet: A `WindowSet` object. + bool """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def history(self) -> List[int]: """ - Create a view of the Edge including all events between `start` (inclusive) and `end` (exclusive) - - Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + Returns a list of timestamps of when an edge is added or change to an edge is made. Returns: - r Edge - """ + List[int]: A list of unix timestamps. - def at(self, time: TimeInput): """ - Create a view of the Edge including all events at `time`. - Arguments: - time (TimeInput): The time of the window. + def history_counts(self) -> int: + """ + Returns the number of times an edge is added or change to an edge is made. Returns: - Edge + int: The number of times an edge is added or change to an edge is made. + """ - def latest(self): + def history_date_time(self): """ - Create a view of the Edge including all events at the latest time. + Returns a list of timestamps of when an edge is added or change to an edge is made. Returns: - Edge - """ + List[Datetime] - def snapshot_at(self, time: TimeInput): """ - Create a view of the Edge including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s - Arguments: - time (TimeInput): The time of the window. + @property + def id(self): + """The id of the edge.""" + def is_active(self): + """ + Check if the edge is currently active (i.e., has at least one update within this period) Returns: - Edge + bool """ - def snapshot_latest(self): + def is_deleted(self): + """ + Check if the edge is currently deleted + Returns: + bool """ - Create a view of the Edge including all events that have not been explicitly deleted at the latest time. - - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + def is_self_loop(self): + """ + Check if the edge is on the same node Returns: - Edge + bool """ - def before(self, end: TimeInput): + def is_valid(self): + """ + Check if the edge is currently valid (i.e., not deleted) + Returns: + bool """ - Create a view of the Edge including all events before `end` (exclusive). - Arguments: - end (TimeInput): The end time of the window. + def latest(self): + """ + Create a view of the Edge including all events at the latest time. Returns: Edge """ - def after(self, start: TimeInput): + @property + def latest_date_time(self): """ - Create a view of the Edge including all events after `start` (exclusive). - - Arguments: - start (TimeInput): The start time of the window. + Gets of latest datetime of an edge. Returns: - Edge + Datetime: the latest datetime of an edge """ - def shrink_start(self, start: TimeInput): + @property + def latest_time(self): """ - Set the start of the window to the larger of `start` and `self.start()` - - Arguments: - start (TimeInput): the new start time of the window + Gets the latest time of an edge. Returns: - Edge + int: The latest time of an edge """ - def shrink_end(self, end: TimeInput): + def layer(self, name: str) -> Edge: """ - Set the end of the window to the smaller of `end` and `self.end()` + Return a view of Edge containing the layer `"name"` + Errors if the layer does not exist Arguments: - end (TimeInput): the new end time of the window + name (str): then name of the layer. + Returns: - Edge + Edge: The layered view """ - def shrink_window(self, start: TimeInput, end: TimeInput): + @property + def layer_name(self): """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - - Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + Gets the name of the layer this edge belongs to - assuming it only belongs to one layer + Returns: + str: The name of the layer """ @property @@ -3494,80 +3473,98 @@ class Edge(object): List[str]- The name of the layer """ - @property - def earliest_date_time(self): + def layers(self, names: list[str]) -> Edge: """ - Gets of earliest datetime of an edge. + Return a view of Edge containing all layers `names` + Errors if any of the layers do not exist. + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Datetime: the earliest datetime of an edge + Edge: The layered view """ @property - def start(self): + def nbr(self): + """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" + + @property + def properties(self): """ - Gets the start time for rolling and expanding windows for this Edge + Returns a view of the properties of the edge. Returns: - Optional[int]: The earliest time that this Edge is valid or None if the Edge is valid for all times. + Properties on the Edge. """ - @property - def latest_date_time(self): + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Gets of latest datetime of an edge. + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + + A rolling window is a window that moves forward by `step` size at each iteration. + + Arguments: + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - Datetime: the latest datetime of an edge + WindowSet: A `WindowSet` object. """ - @property - def properties(self): + def shrink_end(self, end: TimeInput): """ - Returns a view of the properties of the edge. + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - Properties on the Edge. + Edge """ - @property - def time(self): + def shrink_start(self, start: TimeInput): """ - Gets the time of an exploded edge. + Set the start of the window to the larger of `start` and `self.start()` + + Arguments: + start (TimeInput): the new start time of the window Returns: - int: The time of an exploded edge + Edge """ - @property - def id(self): - """The id of the edge.""" - - @property - def latest_time(self): + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Gets the latest time of an edge. + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - Returns: - int: The latest time of an edge """ - @property - def earliest_time(self): + def snapshot_at(self, time: TimeInput): """ - Gets the earliest time of an edge. + Create a view of the Edge including all events that have not been explicitly deleted at `time`. + + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. Returns: - int: The earliest time of an edge + Edge """ - @property - def date_time(self): + def snapshot_latest(self): """ - Gets the datetime of an exploded edge. + Create a view of the Edge including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Datetime: the datetime of an exploded edge + Edge """ @property @@ -3575,93 +3572,138 @@ class Edge(object): """Returns the source node of the edge.""" @property - def dst(self): - """Returns the destination node of the edge.""" + def start(self): + """ + Gets the start time for rolling and expanding windows for this Edge - @property - def nbr(self): - """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" + Returns: + Optional[int]: The earliest time that this Edge is valid or None if the Edge is valid for all times. + """ @property - def end_date_time(self): + def start_date_time(self): """ - Gets the latest datetime that this Edge is valid + Gets the earliest datetime that this Edge is valid Returns: - Optional[Datetime]: The latest datetime that this Edge is valid or None if the Edge is valid for all times. + Optional[Datetime]: The earliest datetime that this Edge is valid or None if the Edge is valid for all times. """ @property - def window_size(self): + def time(self): """ - Get the window size (difference between start and end) for this Edge + Gets the time of an exploded edge. Returns: - Optional[int] + int: The time of an exploded edge """ - @property - def layer_name(self): + def valid_layers(self, names: list[str]) -> Edge: """ - Gets the name of the layer this edge belongs to - assuming it only belongs to one layer + Return a view of Edge containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - str: The name of the layer + Edge: The layered view """ - @property - def end(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Gets the latest time that this Edge is valid. + Create a view of the Edge including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - Optional[int]: The latest time that this Edge is valid or None if the Edge is valid for all times. + r Edge """ @property - def start_date_time(self): + def window_size(self): """ - Gets the earliest datetime that this Edge is valid + Get the window size (difference between start and end) for this Edge Returns: - Optional[Datetime]: The earliest datetime that this Edge is valid or None if the Edge is valid for all times. + Optional[int] """ class Edges(object): """A list of edges that can be iterated over.""" - def __repr__(self): - """Return repr(self).""" + def __bool__(self): + """True if self else False""" def __iter__(self): """Implement iter(self).""" - def __bool__(self): - """True if self else False""" - def __len__(self): """Return len(self).""" - def count(self): - """Returns the number of edges""" + def __repr__(self): + """Return repr(self).""" - def history(self): + def after(self, start: TimeInput): """ - Returns all timestamps of edges, when an edge is added or change to an edge is made. + Create a view of the Edges including all events after `start` (exclusive). + + Arguments: + start (TimeInput): The start time of the window. Returns: - A list of lists unix timestamps. + Edges + """ + def at(self, time: TimeInput): """ + Create a view of the Edges including all events at `time`. - def history_counts(self): ... - def history_date_time(self): + Arguments: + time (TimeInput): The time of the window. + + Returns: + Edges """ - Returns all timestamps of edges, when an edge is added or change to an edge is made. + + def before(self, end: TimeInput): + """ + Create a view of the Edges including all events before `end` (exclusive). + + Arguments: + end (TimeInput): The end time of the window. Returns: - A list of lists of timestamps. + Edges + """ + + def collect(self) -> list[Edge]: + """ + Collect all edges into a list + + Returns: + list[Edge]: the list of edges + """ + def count(self): + """Returns the number of edges""" + + @property + def date_time(self): + """ + Returns the date times of exploded edges + + Returns: + A list of date times. + """ + + def default_layer(self) -> Edges: + """ + Return a view of Edges containing only the default edge layer + Returns: + Edges: The layered view """ def deletions(self): @@ -3680,81 +3722,65 @@ class Edges(object): A list of lists of DateTime objects """ - def is_valid(self): - """Check if the edges are valid (i.e. not deleted)""" - - def is_active(self): ... - def is_self_loop(self): - """Check if the edges are on the same node""" - - def is_deleted(self): - """Check if the edges are deleted""" + @property + def dst(self): + """Returns the destination node of the edge.""" - def to_df( - self, - include_property_history: bool = True, - convert_datetime: bool = False, - explode: bool = False, - ) -> DataFrame: + @property + def earliest_date_time(self): """ - Converts the graph's edges into a Pandas DataFrame. - - This method will create a DataFrame with the following columns: - - "src": The source node of the edge. - - "dst": The destination node of the edge. - - "layer": The layer of the edge. - - "properties": The properties of the edge. - - "update_history": The update history of the edge. This column will be included if `include_update_history` is set to `true`. - - Args: - include_property_history (bool): A boolean, if set to `True`, the history of each property is included, if `False`, only the latest value is shown. Ignored if exploded. Defaults to True. - convert_datetime (bool): A boolean, if set to `True` will convert the timestamp to python datetimes. Defaults to False. - explode (bool): A boolean, if set to `True`, will explode each edge update into its own row. Defaults to False. + Returns the earliest date time of the edges. Returns: - DataFrame: If successful, this PyObject will be a Pandas DataFrame. + Earliest date time of the edges. """ - def collect(self) -> list[Edge]: + @property + def earliest_time(self): """ - Collect all edges into a list + Returns the earliest time of the edges. Returns: - list[Edge]: the list of edges + Earliest time of the edges. """ - def explode(self): - """Explodes returns an edge object for each update within the original edge.""" + @property + def end(self): + """ + Gets the latest time that this Edges is valid. - def explode_layers(self): - """Explode layers returns an edge object for each layer within the original edge. These new edge object contains only updates from respective layers.""" + Returns: + Optional[int]: The latest time that this Edges is valid or None if the Edges is valid for all times. + """ - def default_layer(self) -> Edges: + @property + def end_date_time(self): """ - Return a view of Edges containing only the default edge layer + Gets the latest datetime that this Edges is valid + Returns: - Edges: The layered view + Optional[Datetime]: The latest datetime that this Edges is valid or None if the Edges is valid for all times. """ - def layer(self, name: str) -> Edges: + def exclude_layer(self, name: str) -> Edges: """ - Return a view of Edges containing the layer `"name"` - Errors if the layer does not exist + Return a view of Edges containing all layers except the excluded `name` + Errors if any of the layers do not exist. Arguments: - name (str): then name of the layer. + name (str): layer name that is excluded for the new view Returns: Edges: The layered view """ - def exclude_layer(self, name: str) -> Edges: + def exclude_layers(self, names: list[str]) -> Edges: """ - Return a view of Edges containing all layers except the excluded `name` + Return a view of Edges containing all layers except the excluded `names` Errors if any of the layers do not exist. Arguments: - name (str): layer name that is excluded for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: Edges: The layered view @@ -3770,163 +3796,176 @@ class Edges(object): Edges: The layered view """ - def has_layer(self, name: str): + def exclude_valid_layers(self, names: list[str]) -> Edges: """ - Check if Edges has the layer `"name"` - + Return a view of Edges containing all layers except the excluded `names` Arguments: - name (str): the name of the layer to check + names (list[str]): list of layer names that are excluded for the new view Returns: - bool + Edges: The layered view """ - def layers(self, names: list[str]) -> Edges: + def expanding(self, step: int | str) -> WindowSet: """ - Return a view of Edges containing all layers `names` - Errors if any of the layers do not exist. + Creates a `WindowSet` with the given `step` size using an expanding window. + + An expanding window is a window that grows by `step` size at each iteration. Arguments: - names (list[str]): list of layer names for the new view + step (int | str): The step size of the window. Returns: - Edges: The layered view + WindowSet: A `WindowSet` object. """ - def exclude_layers(self, names: list[str]) -> Edges: + def explode(self): + """Explodes returns an edge object for each update within the original edge.""" + + def explode_layers(self): + """Explode layers returns an edge object for each layer within the original edge. These new edge object contains only updates from respective layers.""" + + def has_layer(self, name: str): """ - Return a view of Edges containing all layers except the excluded `names` - Errors if any of the layers do not exist. + Check if Edges has the layer `"name"` Arguments: - names (list[str]): list of layer names that are excluded for the new view + name (str): the name of the layer to check Returns: - Edges: The layered view + bool """ - def exclude_valid_layers(self, names: list[str]) -> Edges: + def history(self): """ - Return a view of Edges containing all layers except the excluded `names` - Arguments: - names (list[str]): list of layer names that are excluded for the new view + Returns all timestamps of edges, when an edge is added or change to an edge is made. Returns: - Edges: The layered view - """ + A list of lists unix timestamps. - def valid_layers(self, names: list[str]) -> Edges: """ - Return a view of Edges containing all layers `names` - Any layers that do not exist are ignored - Arguments: - names (list[str]): list of layer names for the new view + def history_counts(self): ... + def history_date_time(self): + """ + Returns all timestamps of edges, when an edge is added or change to an edge is made. Returns: - Edges: The layered view - """ + A list of lists of timestamps. - def expanding(self, step: int | str) -> WindowSet: """ - Creates a `WindowSet` with the given `step` size using an expanding window. - An expanding window is a window that grows by `step` size at each iteration. + @property + def id(self): + """Returns all ids of the edges.""" - Arguments: - step (int | str): The step size of the window. + def is_active(self): ... + def is_deleted(self): + """Check if the edges are deleted""" + + def is_self_loop(self): + """Check if the edges are on the same node""" + + def is_valid(self): + """Check if the edges are valid (i.e. not deleted)""" + + def latest(self): + """ + Create a view of the Edges including all events at the latest time. Returns: - WindowSet: A `WindowSet` object. + Edges """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: + @property + def latest_date_time(self): """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + Returns the latest date time of the edges. - A rolling window is a window that moves forward by `step` size at each iteration. + Returns: + Latest date time of the edges. + """ - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + @property + def latest_time(self): + """ + Returns the latest time of the edges. Returns: - WindowSet: A `WindowSet` object. + Latest time of the edges. """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def layer(self, name: str) -> Edges: """ - Create a view of the Edges including all events between `start` (inclusive) and `end` (exclusive) + Return a view of Edges containing the layer `"name"` + Errors if the layer does not exist Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + name (str): then name of the layer. Returns: - r Edges + Edges: The layered view """ - def at(self, time: TimeInput): + @property + def layer_name(self): """ - Create a view of the Edges including all events at `time`. - - Arguments: - time (TimeInput): The time of the window. + Get the layer name that all edges belong to - assuming they only belong to one layer Returns: - Edges + The name of the layer """ - def latest(self): + @property + def layer_names(self): """ - Create a view of the Edges including all events at the latest time. + Get the layer names that all edges belong to - assuming they only belong to one layer Returns: - Edges + A list of layer names """ - def snapshot_at(self, time: TimeInput): + def layers(self, names: list[str]) -> Edges: """ - Create a view of the Edges including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + Return a view of Edges containing all layers `names` + Errors if any of the layers do not exist. Arguments: - time (TimeInput): The time of the window. + names (list[str]): list of layer names for the new view Returns: - Edges + Edges: The layered view """ - def snapshot_latest(self): - """ - Create a view of the Edges including all events that have not been explicitly deleted at the latest time. + @property + def nbr(self): + """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + @property + def properties(self): + """Returns all properties of the edges""" - Returns: - Edges + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - def before(self, end: TimeInput): - """ - Create a view of the Edges including all events before `end` (exclusive). + A rolling window is a window that moves forward by `step` size at each iteration. Arguments: - end (TimeInput): The end time of the window. + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - Edges + WindowSet: A `WindowSet` object. """ - def after(self, start: TimeInput): + def shrink_end(self, end: TimeInput): """ - Create a view of the Edges including all events after `start` (exclusive). + Set the end of the window to the smaller of `end` and `self.end()` Arguments: - start (TimeInput): The start time of the window. - + end (TimeInput): the new end time of the window Returns: Edges """ @@ -3942,16 +3981,6 @@ class Edges(object): Edges """ - def shrink_end(self, end: TimeInput): - """ - Set the end of the window to the smaller of `end` and `self.end()` - - Arguments: - end (TimeInput): the new end time of the window - Returns: - Edges - """ - def shrink_window(self, start: TimeInput, end: TimeInput): """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -3962,62 +3991,40 @@ class Edges(object): """ - @property - def layer_name(self): + def snapshot_at(self, time: TimeInput): """ - Get the layer name that all edges belong to - assuming they only belong to one layer + Create a view of the Edges including all events that have not been explicitly deleted at `time`. - Returns: - The name of the layer - """ + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s - @property - def date_time(self): - """ - Returns the date times of exploded edges + Arguments: + time (TimeInput): The time of the window. Returns: - A list of date times. - """ - - @property - def nbr(self): - """Returns the node at the other end of the edge (same as `dst()` for out-edges and `src()` for in-edges)""" - - @property - def start(self): + Edges """ - Gets the start time for rolling and expanding windows for this Edges - Returns: - Optional[int]: The earliest time that this Edges is valid or None if the Edges is valid for all times. + def snapshot_latest(self): """ + Create a view of the Edges including all events that have not been explicitly deleted at the latest time. - @property - def end_date_time(self): - """ - Gets the latest datetime that this Edges is valid + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Optional[Datetime]: The latest datetime that this Edges is valid or None if the Edges is valid for all times. + Edges """ @property - def window_size(self): - """ - Get the window size (difference between start and end) for this Edges - - Returns: - Optional[int] - """ + def src(self): + """Returns the source node of the edge.""" @property - def latest_time(self): + def start(self): """ - Returns the latest time of the edges. + Gets the start time for rolling and expanding windows for this Edges Returns: - Latest time of the edges. + Optional[int]: The earliest time that this Edges is valid or None if the Edges is valid for all times. """ @property @@ -4029,10 +4036,6 @@ class Edges(object): Optional[Datetime]: The earliest datetime that this Edges is valid or None if the Edges is valid for all times. """ - @property - def dst(self): - """Returns the destination node of the edge.""" - @property def time(self): """ @@ -4042,66 +4045,80 @@ class Edges(object): Time of edge """ - @property - def earliest_time(self): + def to_df( + self, + include_property_history: bool = True, + convert_datetime: bool = False, + explode: bool = False, + ) -> DataFrame: """ - Returns the earliest time of the edges. + Converts the graph's edges into a Pandas DataFrame. - Returns: - Earliest time of the edges. - """ + This method will create a DataFrame with the following columns: + - "src": The source node of the edge. + - "dst": The destination node of the edge. + - "layer": The layer of the edge. + - "properties": The properties of the edge. + - "update_history": The update history of the edge. This column will be included if `include_update_history` is set to `true`. - @property - def earliest_date_time(self): - """ - Returns the earliest date time of the edges. + Args: + include_property_history (bool): A boolean, if set to `True`, the history of each property is included, if `False`, only the latest value is shown. Ignored if exploded. Defaults to True. + convert_datetime (bool): A boolean, if set to `True` will convert the timestamp to python datetimes. Defaults to False. + explode (bool): A boolean, if set to `True`, will explode each edge update into its own row. Defaults to False. Returns: - Earliest date time of the edges. + DataFrame: If successful, this PyObject will be a Pandas DataFrame. """ - @property - def latest_date_time(self): + def valid_layers(self, names: list[str]) -> Edges: """ - Returns the latest date time of the edges. + Return a view of Edges containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Latest date time of the edges. + Edges: The layered view """ - @property - def properties(self): - """Returns all properties of the edges""" - - @property - def layer_names(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Get the layer names that all edges belong to - assuming they only belong to one layer + Create a view of the Edges including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - A list of layer names + r Edges """ @property - def end(self): + def window_size(self): """ - Gets the latest time that this Edges is valid. + Get the window size (difference between start and end) for this Edges Returns: - Optional[int]: The latest time that this Edges is valid or None if the Edges is valid for all times. + Optional[int] """ - @property - def id(self): - """Returns all ids of the edges.""" +class MutableEdge(Edge): + def __repr__(self): + """Return repr(self).""" - @property - def src(self): - """Returns the source node of the edge.""" + def add_constant_properties( + self, properties: PropInput, layer: Optional[str] = None + ): + """ + Add constant properties to an edge in the graph. + This function is used to add properties to an edge that remain constant and do not + change over time. These properties are fundamental attributes of the edge. -class MutableEdge(Edge): - def __repr__(self): - """Return repr(self).""" + Parameters: + properties (PropInput): A dictionary of properties to be added to the edge. + layer (str, optional): The layer you want these properties to be added on to. + """ def add_updates( self, @@ -4136,19 +4153,6 @@ class MutableEdge(Edge): layer (str, optional): The layer you want the deletion applied to . """ - def add_constant_properties( - self, properties: PropInput, layer: Optional[str] = None - ): - """ - Add constant properties to an edge in the graph. - This function is used to add properties to an edge that remain constant and do not - change over time. These properties are fundamental attributes of the edge. - - Parameters: - properties (PropInput): A dictionary of properties to be added to the edge. - layer (str, optional): The layer you want these properties to be added on to. - """ - def update_constant_properties( self, properties: PropInput, layer: Optional[str] = None ): @@ -4165,38 +4169,45 @@ class MutableEdge(Edge): class Properties(object): """A view of the properties of an entity""" - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self list[str]: + def __repr__(self): + """Return repr(self).""" + + def as_dict(self) -> dict[str, PropValue]: """ - lists the available property keys + as_dict() -> dict[str, Any] + + convert the properties view to a python dict Returns: - list[str]: the property keys + dict[str, PropValue]: """ - def values(self): + def get(self, key: str): """ - lists the property values + get property value by key + + Arguments: + key (str): the name of the property Returns: - list | Array: the property values + PropValue | None: the property value or `None` if value for `key` does not exist """ def items(self) -> list[Tuple[str, PropValue]]: @@ -4291,83 +4300,66 @@ class ConstantProperties(object): list[Tuple[str, PropValue]]: the property keys with corresponding values """ - def get(self, key: str): + def keys(self) -> list[str]: """ - get property value by key - - Arguments: - key (str): the name of the property + lists the available property keys Returns: - PropValue | None: the property value or `None` if value for `key` does not exist + list[str]: the property keys """ - def as_dict(self) -> dict[str, PropValue]: + def values(self): """ - as_dict() -> dict[str, Any] - - convert the properties view to a python dict + lists the property values Returns: - dict[str, PropValue]: + list | Array: the property values """ class TemporalProperties(object): """A view of the temporal properties of an entity""" - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" - - def __contains__(self, key): - """Return bool(key in self).""" + def __lt__(self, value): + """Return self list[TemporalProp]: - """ - List the values of the properties + def __repr__(self): + """Return repr(self).""" - Returns: - list[TemporalProp]: the list of property views + def get(self, key): """ + get(key: str) -> Optional[TemporalProp] - def items(self): - """List the property keys together with the corresponding values""" - - def latest(self) -> dict[str, Any]: - """ - Get the latest value of all properties + Get property value for `key` if it exists Returns: - dict[str, Any]: the mapping of property keys to latest values + the property view if it exists, otherwise `None` """ def histories(self) -> dict[str, list[Tuple[int, PropValue]]]: @@ -4386,82 +4378,86 @@ class TemporalProperties(object): dict[str, list[Tuple[datetime, PropValue]]]: the mapping of property keys to histories """ - def get(self, key): + def items(self): + """List the property keys together with the corresponding values""" + + def keys(self): + """List the available property keys""" + + def latest(self) -> dict[str, Any]: """ - get(key: str) -> Optional[TemporalProp] + Get the latest value of all properties - Get property value for `key` if it exists + Returns: + dict[str, Any]: the mapping of property keys to latest values + """ + + def values(self) -> list[TemporalProp]: + """ + List the values of the properties Returns: - the property view if it exists, otherwise `None` + list[TemporalProp]: the list of property views """ class TemporalProp(object): """A view of a temporal property""" - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" - def history(self): - """Get the timestamps at which the property was updated""" - - def history_date_time(self): - """Get the timestamps at which the property was updated""" + def __le__(self, value): + """Return self<=value.""" - def values(self): - """Get the property values for each update""" + def __lt__(self, value): + """Return self Prop: + def average(self) -> Prop: """ - Compute the sum of all property values. + Compute the average of all property values. Alias for mean(). Returns: - Prop: The sum of all property values. + Prop: The average of each property values, or None if count is zero. """ - def min(self): + def count(self) -> int: """ - Find the minimum property value and its associated time. + Count the number of properties. Returns: - (i64, Prop): A tuple containing the time and the minimum property value. + int: The number of properties. """ + def history(self): + """Get the timestamps at which the property was updated""" + + def history_date_time(self): + """Get the timestamps at which the property was updated""" + + def items(self): + """List update timestamps and corresponding property values""" + + def items_date_time(self): + """List update timestamps and corresponding property values""" + def max(self): """ Find the maximum property value and its associated time. @@ -4470,38 +4466,46 @@ class TemporalProp(object): (i64, Prop): A tuple containing the time and the maximum property value. """ - def count(self) -> int: + def mean(self) -> Prop: """ - Count the number of properties. + Compute the mean of all property values. Alias for mean(). Returns: - int: The number of properties. + Prop: The mean of each property values, or None if count is zero. """ - def average(self) -> Prop: + def median(self): """ - Compute the average of all property values. Alias for mean(). + Compute the median of all property values. Returns: - Prop: The average of each property values, or None if count is zero. + (i64, Prop): A tuple containing the time and the median property value, or None if empty """ - def mean(self) -> Prop: + def min(self): """ - Compute the mean of all property values. Alias for mean(). + Find the minimum property value and its associated time. Returns: - Prop: The mean of each property values, or None if count is zero. + (i64, Prop): A tuple containing the time and the minimum property value. """ - def median(self): + def ordered_dedupe(self, latest_time): ... + def sum(self) -> Prop: """ - Compute the median of all property values. + Compute the sum of all property values. Returns: - (i64, Prop): A tuple containing the time and the median property value, or None if empty + Prop: The sum of all property values. """ + def unique(self): ... + def value(self): + """Get the latest value of the property""" + + def values(self): + """Get the property values for each update""" + class Prop(object): """ A reference to a property used for constructing filters @@ -4512,35 +4516,35 @@ class Prop(object): other kinds of filters. """ - def __new__(cls, name) -> Prop: - """Create and return a new object. See help(type) for accurate signature.""" + def __eq__(self, value): + """Return self==value.""" - def __lt__(self, value): - """Return self=value.""" + + def __gt__(self, value): + """Return self>value.""" def __le__(self, value): """Return self<=value.""" - def __eq__(self, value): - """Return self==value.""" + def __lt__(self, value): + """Return selfvalue.""" - - def __ge__(self, value): - """Return self>=value.""" + def __new__(cls, name) -> Prop: + """Create and return a new object. See help(type) for accurate signature.""" - def is_some(self): - """Create a filter that only keeps entities if they have the property""" + def any(self, values): + """Create a filter that keeps entities if their property value is in the set""" def is_none(self): """Create a filter that only keeps entities that do not have the property""" - def any(self, values): - """Create a filter that keeps entities if their property value is in the set""" + def is_some(self): + """Create a filter that only keeps entities if they have the property""" def not_any(self, values): """ @@ -4569,11 +4573,22 @@ class WindowSet(object): """ class AlgorithmResult(object): + def __len__(self): + """Return len(self).""" + def __repr__(self): """Return repr(self).""" - def __len__(self): - """Return len(self).""" + def get(self, key: InputNode) -> Optional[Any]: + """ + Returns the value corresponding to the provided key + + Arguments: + key (InputNode): The node for which the value is to be retrieved. + + Returns: + Optional[Any]: The value for the node or `None` if the value does not exist. + """ def get_all(self) -> dict[Node, Any]: """ @@ -4591,23 +4606,45 @@ class AlgorithmResult(object): list[Any]: the values for each node as a list """ - def get(self, key: InputNode) -> Optional[Any]: + def get_all_with_names(self) -> dict[str, Any]: """ - Returns the value corresponding to the provided key + Returns a dict with node names and values - Arguments: - key (InputNode): The node for which the value is to be retrieved. + Returns: + dict[str, Any]: a dict with node names and values + """ + + def group_by(self) -> dict[Any, list[str]]: + """ + Groups the `AlgorithmResult` by its values. Returns: - Optional[Any]: The value for the node or `None` if the value does not exist. + dict[Any, list[str]]: A mapping where keys are unique values from the `AlgorithmResult` and values are lists of nodes + that share the same value. """ - def get_all_with_names(self) -> dict[str, Any]: + def max(self) -> Tuple[Node, Any]: """ - Returns a dict with node names and values + Find node with maximum value Returns: - dict[str, Any]: a dict with node names and values + Tuple[Node, Any]: The node and maximum value. + """ + + def median(self): + """ + Returns a tuple of the median result with its key + + Returns: + Optional[Tuple[Node, Any]]: The node with median value or `None` if there are no nodes. + """ + + def min(self) -> Tuple[Node, Any]: + """ + Find node with minimum value + + Returns: + Tuple[Node, Any]: The node and minimum value. """ def sort_by_node(self, reverse: bool = True) -> list[Tuple[Node, Any]]: @@ -4621,12 +4658,18 @@ class AlgorithmResult(object): list[Tuple[Node, Any]]: A sorted list of tuples containing nodes and values. """ - def to_df(self) -> DataFrame: + def sort_by_node_name(self, reverse: bool = True) -> list[Tuple[Node, Any]]: """ - Creates a dataframe from the result + The function `sort_by_node_name` sorts a vector of tuples containing a node and an optional + value by the node name in either ascending or descending order. + + Arguments: + reverse (bool): A boolean value indicating whether the sorting should be done in reverse order or not. Defaults to True. + If reverse is true, the sorting will be done in descending order, otherwise it will be done in + ascending order. Returns: - DataFrame: A `pandas.DataFrame` containing the result + list[Tuple[Node, Any]]: The function sort_by_node_name returns a vector of tuples. Each tuple contains a Node and value """ def sort_by_value(self, reverse: bool = True) -> list[Tuple[Node, Any]]: @@ -4640,18 +4683,12 @@ class AlgorithmResult(object): list[Tuple[Node, Any]]: A sorted vector of tuples containing Nodes and values. """ - def sort_by_node_name(self, reverse: bool = True) -> list[Tuple[Node, Any]]: + def to_df(self) -> DataFrame: """ - The function `sort_by_node_name` sorts a vector of tuples containing a node and an optional - value by the node name in either ascending or descending order. - - Arguments: - reverse (bool): A boolean value indicating whether the sorting should be done in reverse order or not. Defaults to True. - If reverse is true, the sorting will be done in descending order, otherwise it will be done in - ascending order. + Creates a dataframe from the result Returns: - list[Tuple[Node, Any]]: The function sort_by_node_name returns a vector of tuples. Each tuple contains a Node and value + DataFrame: A `pandas.DataFrame` containing the result """ def top_k( @@ -4672,39 +4709,6 @@ class AlgorithmResult(object): Returns None if the result is empty or if `k` is 0. """ - def min(self) -> Tuple[Node, Any]: - """ - Find node with minimum value - - Returns: - Tuple[Node, Any]: The node and minimum value. - """ - - def max(self) -> Tuple[Node, Any]: - """ - Find node with maximum value - - Returns: - Tuple[Node, Any]: The node and maximum value. - """ - - def median(self): - """ - Returns a tuple of the median result with its key - - Returns: - Optional[Tuple[Node, Any]]: The node with median value or `None` if there are no nodes. - """ - - def group_by(self) -> dict[Any, list[str]]: - """ - Groups the `AlgorithmResult` by its values. - - Returns: - dict[Any, list[str]]: A mapping where keys are unique values from the `AlgorithmResult` and values are lists of nodes - that share the same value. - """ - class GraphIndex(object): """ A searchable Index for a `Graph`. This allows for fuzzy and exact searches of nodes and edges. @@ -4712,57 +4716,57 @@ class GraphIndex(object): To create a graph index, call `graph.index()` on any `Graph` object in python. """ - def fuzzy_search_nodes( + def fuzzy_search_edges( self, query: str, limit: int = 25, offset: int = 0, prefix: bool = False, levenshtein_distance: int = 0, - ) -> list[Node]: + ) -> list[Edge]: """ - Searches for nodes which match the given query. This uses Tantivy's fuzzy search. - If you would like to better understand the query syntax, please visit our documentation at https://docs.raphtory.com + Searches for edges which match the given query. This uses Tantivy's fuzzy search. Arguments: query(str): The query to search for. limit(int): The maximum number of results to return. Defaults to 25. - offset(int): The number of results to skip. This is useful for pagination. - Returns the first page of results by default. + offset(int): The number of results to skip. This is useful for pagination. Returns the first page of results by default. prefix(bool): If prefix is set to true, the fuzzy matching will be applied as a prefix search, meaning it matches terms that start with the query term. Defaults to False. levenshtein_distance(int): The levenshtein_distance parameter defines the maximum edit distance allowed for fuzzy matching. It specifies the number of changes (insertions, deletions, or substitutions) required to match the query term. Defaults to 0. - The default corresponds to exact matching. + The default value corresponds to exact matching. Returns: - list[Node]: A list of nodes which match the query. The list will be empty if no nodes match. + list[Edge]: A list of edges which match the query. The list will be empty if no edges match the query. """ - def fuzzy_search_edges( + def fuzzy_search_nodes( self, query: str, limit: int = 25, offset: int = 0, prefix: bool = False, levenshtein_distance: int = 0, - ) -> list[Edge]: + ) -> list[Node]: """ - Searches for edges which match the given query. This uses Tantivy's fuzzy search. + Searches for nodes which match the given query. This uses Tantivy's fuzzy search. + If you would like to better understand the query syntax, please visit our documentation at https://docs.raphtory.com Arguments: query(str): The query to search for. limit(int): The maximum number of results to return. Defaults to 25. - offset(int): The number of results to skip. This is useful for pagination. Returns the first page of results by default. + offset(int): The number of results to skip. This is useful for pagination. + Returns the first page of results by default. prefix(bool): If prefix is set to true, the fuzzy matching will be applied as a prefix search, meaning it matches terms that start with the query term. Defaults to False. levenshtein_distance(int): The levenshtein_distance parameter defines the maximum edit distance allowed for fuzzy matching. It specifies the number of changes (insertions, deletions, or substitutions) required to match the query term. Defaults to 0. - The default value corresponds to exact matching. + The default corresponds to exact matching. Returns: - list[Edge]: A list of edges which match the query. The list will be empty if no edges match the query. + list[Node]: A list of nodes which match the query. The list will be empty if no nodes match. """ - def search_nodes(self, query: str, limit: int = 25, offset: int = 0) -> list[Node]: + def search_edges(self, query: str, limit: int = 25, offset: int = 0) -> list[Edge]: """ - Searches for nodes which match the given query. This uses Tantivy's exact search. + Searches for edges which match the given query. This uses Tantivy's exact search. Arguments: query(str): The query to search for. @@ -4770,12 +4774,12 @@ class GraphIndex(object): offset(int): The number of results to skip. This is useful for pagination. Defaults to 0. Returns: - list[Node]: A list of nodes which match the query. The list will be empty if no nodes match. + list[Edge]: A list of edges which match the query. The list will be empty if no edges match the query. """ - def search_edges(self, query: str, limit: int = 25, offset: int = 0) -> list[Edge]: + def search_nodes(self, query: str, limit: int = 25, offset: int = 0) -> list[Node]: """ - Searches for edges which match the given query. This uses Tantivy's exact search. + Searches for nodes which match the given query. This uses Tantivy's exact search. Arguments: query(str): The query to search for. @@ -4783,21 +4787,20 @@ class GraphIndex(object): offset(int): The number of results to skip. This is useful for pagination. Defaults to 0. Returns: - list[Edge]: A list of edges which match the query. The list will be empty if no edges match the query. + list[Node]: A list of nodes which match the query. The list will be empty if no nodes match. """ class DiskGraphStorage(object): def __repr__(self): """Return repr(self).""" + def append_node_temporal_properties(self, location, chunk_size=20000000): ... def graph_dir(self): ... - def to_events(self): ... - def to_persistent(self): ... - @staticmethod - def load_from_pandas(graph_dir, edge_df, time_col, src_col, dst_col): ... @staticmethod def load_from_dir(graph_dir): ... @staticmethod + def load_from_pandas(graph_dir, edge_df, time_col, src_col, dst_col): ... + @staticmethod def load_from_parquets( graph_dir, layer_parquet_cols, @@ -4809,9 +4812,11 @@ class DiskGraphStorage(object): node_id_col=None, ): ... def load_node_const_properties(self, location, col_names=None, chunk_size=None): ... - def append_node_temporal_properties(self, location, chunk_size=20000000): ... def merge_by_sorted_gids(self, other, graph_dir): """ Merge this graph with another `DiskGraph`. Note that both graphs should have nodes that are sorted by their global ids or the resulting graph will be nonsense! """ + + def to_events(self): ... + def to_persistent(self): ... diff --git a/python/python/raphtory/algorithms/__init__.pyi b/python/python/raphtory/algorithms/__init__.pyi index ad4b0157ca..508d62aedf 100644 --- a/python/python/raphtory/algorithms/__init__.pyi +++ b/python/python/raphtory/algorithms/__init__.pyi @@ -692,32 +692,20 @@ def max_weight_matching( class Matching(object): """A Matching (i.e., a set of edges that do not share any nodes)""" - def __repr__(self): - """Return repr(self).""" - - def __iter__(self): - """Implement iter(self).""" - def __bool__(self): """True if self else False""" - def __len__(self): - """Return len(self).""" - def __contains__(self, key): """Return bool(key in self).""" - def src(self, dst: InputNode) -> Optional[Node]: - """ - Get the matched source node for a destination node - - Arguments: - dst (InputNode): The destination node + def __iter__(self): + """Implement iter(self).""" - Returns: - Optional[Node]: The matched source node if it exists + def __len__(self): + """Return len(self).""" - """ + def __repr__(self): + """Return repr(self).""" def dst(self, src: InputNode) -> Optional[Node]: """ @@ -731,12 +719,15 @@ class Matching(object): """ - def edges(self) -> Edges: + def edge_for_dst(self, dst: InputNode) -> Optional[Edge]: """ - Get a view of the matched edges + Get the matched edge for a destination node + + Arguments: + dst (InputNode): The source node Returns: - Edges: The edges in the matching + Optional[Edge]: The matched edge if it exists """ def edge_for_src(self, src: InputNode) -> Optional[Edge]: @@ -750,15 +741,24 @@ class Matching(object): Optional[Edge]: The matched edge if it exists """ - def edge_for_dst(self, dst: InputNode) -> Optional[Edge]: + def edges(self) -> Edges: """ - Get the matched edge for a destination node + Get a view of the matched edges + + Returns: + Edges: The edges in the matching + """ + + def src(self, dst: InputNode) -> Optional[Node]: + """ + Get the matched source node for a destination node Arguments: - dst (InputNode): The source node + dst (InputNode): The destination node Returns: - Optional[Edge]: The matched edge if it exists + Optional[Node]: The matched source node if it exists + """ def connected_components(g): ... diff --git a/python/python/raphtory/graphql/__init__.pyi b/python/python/raphtory/graphql/__init__.pyi index cb534a20dc..eef5a43703 100644 --- a/python/python/raphtory/graphql/__init__.pyi +++ b/python/python/raphtory/graphql/__init__.pyi @@ -23,6 +23,9 @@ class GraphqlGraphs(object): graph documents """ + def get(self, name): + """Return the `VectorisedGraph` with name `name` or `None` if it doesn't exist""" + def search_graph_documents(self, query, limit, window): """ Return the top documents with the smallest cosine distance to `query` @@ -39,9 +42,6 @@ class GraphqlGraphs(object): def search_graph_documents_with_scores(self, query, limit, window): """Same as `search_graph_documents` but it also returns the scores alongside the documents""" - def get(self, name): - """Return the `VectorisedGraph` with name `name` or `None` if it doesn't exist""" - class GraphServer(object): """A class for defining and running a Raphtory GraphQL server""" @@ -59,8 +59,14 @@ class GraphServer(object): ) -> GraphServer: """Create and return a new object. See help(type) for accurate signature.""" - def turn_off_index(self): - """Turn off index for all graphs""" + def run(self, port: int = 1736, timeout_ms: int = 180000): + """ + Run the server until completion. + + Arguments: + port (int): The port to use. Defaults to 1736. + timeout_ms (int): Timeout for waiting for the server to start. Defaults to 180000. + """ def set_embeddings( self, @@ -84,26 +90,22 @@ class GraphServer(object): GraphServer: A new server object with embeddings setup. """ - def with_vectorised_graphs( - self, - graph_names: list[str], - graphs: bool | str = ..., - nodes: bool | str = ..., - edges: bool | str = ..., - ) -> GraphServer: + def start(self, port: int = 1736, timeout_ms: int = 5000) -> RunningGraphServer: """ - Vectorise a subset of the graphs of the server. + Start the server and return a handle to it. Arguments: - graph_names (list[str]): the names of the graphs to vectorise. All by default. - graphs (bool | str): if graphs have to be embedded or not or the custom template to use if a str is provided (defaults to True) - nodes (bool | str): if nodes have to be embedded or not or the custom template to use if a str is provided (defaults to True) - edges (bool | str): if edges have to be embedded or not or the custom template to use if a str is provided (defaults to True) + port (int): the port to use. Defaults to 1736. + timeout_ms (int): wait for server to be online. Defaults to 5000. + The server is stopped if not online within timeout_ms but manages to come online as soon as timeout_ms finishes! Returns: - GraphServer: A new server object containing the vectorised graphs. + RunningGraphServer: The running server """ + def turn_off_index(self): + """Turn off index for all graphs""" + def with_global_search_function( self, name: str, input: dict, function: Callable ) -> GraphServer: @@ -124,123 +126,107 @@ class GraphServer(object): GraphServer: A new server object with the function registered """ - def start(self, port: int = 1736, timeout_ms: int = 5000) -> RunningGraphServer: + def with_vectorised_graphs( + self, + graph_names: list[str], + graphs: bool | str = ..., + nodes: bool | str = ..., + edges: bool | str = ..., + ) -> GraphServer: """ - Start the server and return a handle to it. + Vectorise a subset of the graphs of the server. Arguments: - port (int): the port to use. Defaults to 1736. - timeout_ms (int): wait for server to be online. Defaults to 5000. - The server is stopped if not online within timeout_ms but manages to come online as soon as timeout_ms finishes! + graph_names (list[str]): the names of the graphs to vectorise. All by default. + graphs (bool | str): if graphs have to be embedded or not or the custom template to use if a str is provided (defaults to True) + nodes (bool | str): if nodes have to be embedded or not or the custom template to use if a str is provided (defaults to True) + edges (bool | str): if edges have to be embedded or not or the custom template to use if a str is provided (defaults to True) Returns: - RunningGraphServer: The running server - """ - - def run(self, port: int = 1736, timeout_ms: int = 180000): - """ - Run the server until completion. - - Arguments: - port (int): The port to use. Defaults to 1736. - timeout_ms (int): Timeout for waiting for the server to start. Defaults to 180000. + GraphServer: A new server object containing the vectorised graphs. """ class RunningGraphServer(object): """A Raphtory server handler that also enables querying the server""" + def __enter__(self): ... + def __exit__(self, _exc_type, _exc_val, _exc_tb): ... def get_client(self): ... def stop(self): """Stop the server and wait for it to finish""" - def __enter__(self): ... - def __exit__(self, _exc_type, _exc_val, _exc_tb): ... - class RaphtoryClient(object): """A client for handling GraphQL operations in the context of Raphtory.""" def __new__(cls, url) -> RaphtoryClient: """Create and return a new object. See help(type) for accurate signature.""" - def is_server_online(self): - """ - Check if the server is online. - - Returns: - Returns true if server is online otherwise false. - """ - - def query(self, query, variables=None): + def copy_graph(self, path, new_path): """ - Make a graphQL query against the server. + Copy graph from a path `path` on the server to a `new_path` on the server Arguments: - * `query`: the query to make. - * `variables`: a dict of variables present on the query and their values. + * `path`: the path of the graph to be copied + * `new_path`: the new path of the copied graph Returns: - The `data` field from the graphQL response. + Copy status as boolean """ - def send_graph(self, path, graph, overwrite=False): + def delete_graph(self, path): """ - Send a graph to the server + Delete graph from a path `path` on the server Arguments: - * `path`: the path of the graph - * `graph`: the graph to send - * `overwrite`: overwrite existing graph (defaults to False) + * `path`: the path of the graph to be deleted Returns: - The `data` field from the graphQL response after executing the mutation. + Delete status as boolean """ - def upload_graph(self, path, file_path, overwrite=False): + def is_server_online(self): """ - Upload graph file from a path `file_path` on the client - - Arguments: - * `path`: the name of the graph - * `file_path`: the path of the graph on the client - * `overwrite`: overwrite existing graph (defaults to False) + Check if the server is online. Returns: - The `data` field from the graphQL response after executing the mutation. + Returns true if server is online otherwise false. """ - def copy_graph(self, path, new_path): + def move_graph(self, path, new_path): """ - Copy graph from a path `path` on the server to a `new_path` on the server + Move graph from a path `path` on the server to a `new_path` on the server Arguments: - * `path`: the path of the graph to be copied - * `new_path`: the new path of the copied graph + * `path`: the path of the graph to be moved + * `new_path`: the new path of the moved graph Returns: - Copy status as boolean + Move status as boolean """ - def move_graph(self, path, new_path): + def new_graph(self, path, graph_type): """ - Move graph from a path `path` on the server to a `new_path` on the server + Create a new Graph on the server at `path` Arguments: - * `path`: the path of the graph to be moved - * `new_path`: the new path of the moved graph + * `path`: the path of the graph to be created + * `graph_type`: the type of graph that should be created - this can be EVENT or PERSISTENT Returns: - Move status as boolean + None + """ - def delete_graph(self, path): + def query(self, query, variables=None): """ - Delete graph from a path `path` on the server + Make a graphQL query against the server. Arguments: - * `path`: the path of the graph to be deleted + * `query`: the query to make. + * `variables`: a dict of variables present on the query and their values. Returns: - Delete status as boolean + The `data` field from the graphQL response. """ def receive_graph(self, path): @@ -254,61 +240,73 @@ class RaphtoryClient(object): Graph as string """ - def new_graph(self, path, graph_type): + def remote_graph(self, path): """ - Create a new Graph on the server at `path` + Get a RemoteGraph reference to a graph on the server at `path` Arguments: * `path`: the path of the graph to be created - * `graph_type`: the type of graph that should be created - this can be EVENT or PERSISTENT Returns: - None + RemoteGraph """ - def remote_graph(self, path): + def send_graph(self, path, graph, overwrite=False): """ - Get a RemoteGraph reference to a graph on the server at `path` + Send a graph to the server Arguments: - * `path`: the path of the graph to be created + * `path`: the path of the graph + * `graph`: the graph to send + * `overwrite`: overwrite existing graph (defaults to False) Returns: - RemoteGraph - + The `data` field from the graphQL response after executing the mutation. """ -class RemoteGraph(object): - def node(self, id: str | int): + def upload_graph(self, path, file_path, overwrite=False): """ - Gets a remote node with the specified id + Upload graph file from a path `file_path` on the client Arguments: - id (str|int): the node id + * `path`: the name of the graph + * `file_path`: the path of the graph on the client + * `overwrite`: overwrite existing graph (defaults to False) Returns: - RemoteNode + The `data` field from the graphQL response after executing the mutation. """ - def edge(self, src: str | int, dst: str | int): +class RemoteGraph(object): + def add_constant_properties(self, properties: dict): """ - Gets a remote edge with the specified source and destination nodes + Adds constant properties to the remote graph. Arguments: - src (str|int): the source node id - dst (str|int): the destination node id - - Returns: - RemoteEdge + properties (dict): The constant properties of the graph. """ - def add_nodes(self, updates: List[RemoteNodeAddition]): + def add_edge( + self, + timestamp: int | str | datetime, + src: str | int, + dst: str | int, + properties: Optional[dict] = None, + layer: Optional[str] = None, + ): """ - Batch add node updates to the remote graph + Adds a new edge with the given source and destination nodes and properties to the remote graph. Arguments: - updates (List[RemoteNodeAddition]): The list of updates you want to apply to the remote graph + timestamp (int |str | datetime): The timestamp of the edge. + src (str | int): The id of the source node. + dst (str | int): The id of the destination node. + properties (dict, optional): The properties of the edge, as a dict of string and properties. + layer (str, optional): The layer of the edge. + + Returns: + RemoteEdge """ def add_edges(self, updates: List[RemoteEdgeAddition]): @@ -338,23 +336,12 @@ class RemoteGraph(object): RemoteNode """ - def create_node( - self, - timestamp: int | str | datetime, - id: str | int, - properties: Optional[dict] = None, - node_type: Optional[str] = None, - ): + def add_nodes(self, updates: List[RemoteNodeAddition]): """ - Create a new node with the given id and properties to the remote graph and fail if the node already exists. + Batch add node updates to the remote graph Arguments: - timestamp (int|str|datetime): The timestamp of the node. - id (str|int): The id of the node. - properties (dict, optional): The properties of the node. - node_type (str, optional): The optional string which will be used as a node type - Returns: - RemoteNode + updates (List[RemoteNodeAddition]): The list of updates you want to apply to the remote graph """ def add_property(self, timestamp: int | str | datetime, properties: dict): @@ -366,42 +353,23 @@ class RemoteGraph(object): properties (dict): The temporal properties of the graph. """ - def add_constant_properties(self, properties: dict): - """ - Adds constant properties to the remote graph. - - Arguments: - properties (dict): The constant properties of the graph. - """ - - def update_constant_properties(self, properties: dict): - """ - Updates constant properties on the remote graph. - - Arguments: - properties (dict): The constant properties of the graph. - """ - - def add_edge( + def create_node( self, timestamp: int | str | datetime, - src: str | int, - dst: str | int, + id: str | int, properties: Optional[dict] = None, - layer: Optional[str] = None, + node_type: Optional[str] = None, ): """ - Adds a new edge with the given source and destination nodes and properties to the remote graph. + Create a new node with the given id and properties to the remote graph and fail if the node already exists. Arguments: - timestamp (int |str | datetime): The timestamp of the edge. - src (str | int): The id of the source node. - dst (str | int): The id of the destination node. - properties (dict, optional): The properties of the edge, as a dict of string and properties. - layer (str, optional): The layer of the edge. - + timestamp (int|str|datetime): The timestamp of the node. + id (str|int): The id of the node. + properties (dict, optional): The properties of the node. + node_type (str, optional): The optional string which will be used as a node type Returns: - RemoteEdge + RemoteNode """ def delete_edge( @@ -424,10 +392,54 @@ class RemoteGraph(object): RemoteEdge """ + def edge(self, src: str | int, dst: str | int): + """ + Gets a remote edge with the specified source and destination nodes + + Arguments: + src (str|int): the source node id + dst (str|int): the destination node id + + Returns: + RemoteEdge + """ + + def node(self, id: str | int): + """ + Gets a remote node with the specified id + + Arguments: + id (str|int): the node id + + Returns: + RemoteNode + """ + + def update_constant_properties(self, properties: dict): + """ + Updates constant properties on the remote graph. + + Arguments: + properties (dict): The constant properties of the graph. + """ + class RemoteEdge(object): def __new__(cls, path, client, src, dst) -> RemoteEdge: """Create and return a new object. See help(type) for accurate signature.""" + def add_constant_properties( + self, properties: Dict[str, Prop], layer: Optional[str] = None + ): + """ + Add constant properties to the edge within the remote graph. + This function is used to add properties to an edge that remain constant and do not + change over time. These properties are fundamental attributes of the edge. + + Parameters: + properties (Dict[str, Prop]): A dictionary of properties to be added to the edge. + layer (str, optional): The layer you want these properties to be added on to. + """ + def add_updates( self, t: int | str | datetime, @@ -453,19 +465,6 @@ class RemoteEdge(object): layer (str, optional): The layer you want the deletion applied to. """ - def add_constant_properties( - self, properties: Dict[str, Prop], layer: Optional[str] = None - ): - """ - Add constant properties to the edge within the remote graph. - This function is used to add properties to an edge that remain constant and do not - change over time. These properties are fundamental attributes of the edge. - - Parameters: - properties (Dict[str, Prop]): A dictionary of properties to be added to the edge. - layer (str, optional): The layer you want these properties to be added on to. - """ - def update_constant_properties( self, properties: Dict[str, Prop], layer: Optional[str] = None ): @@ -483,13 +482,14 @@ class RemoteNode(object): def __new__(cls, path, client, id) -> RemoteNode: """Create and return a new object. See help(type) for accurate signature.""" - def set_node_type(self, new_type: str): + def add_constant_properties(self, properties: Dict[str, Prop]): """ - Set the type on the node. This only works if the type has not been previously set, otherwise will - throw an error + Add constant properties to a node in the remote graph. + This function is used to add properties to a node that remain constant and does not + change over time. These properties are fundamental attributes of the node. Parameters: - new_type (str): The new type to be set + properties (Dict[str, Prop]): A dictionary of properties to be added to the node. """ def add_updates( @@ -504,14 +504,13 @@ class RemoteNode(object): properties (Dict[str, Prop], optional): A dictionary of properties to update. """ - def add_constant_properties(self, properties: Dict[str, Prop]): + def set_node_type(self, new_type: str): """ - Add constant properties to a node in the remote graph. - This function is used to add properties to a node that remain constant and does not - change over time. These properties are fundamental attributes of the node. + Set the type on the node. This only works if the type has not been previously set, otherwise will + throw an error Parameters: - properties (Dict[str, Prop]): A dictionary of properties to be added to the node. + new_type (str): The new type to be set """ def update_constant_properties(self, properties: Dict[str, Prop]): @@ -541,3 +540,4 @@ class RemoteEdgeAddition(object): """Create and return a new object. See help(type) for accurate signature.""" def encode_graph(graph): ... +def decode_graph(graph): ... diff --git a/python/python/raphtory/node_state/__init__.pyi b/python/python/raphtory/node_state/__init__.pyi index 7cd55d8e13..2e2a7ebc95 100644 --- a/python/python/raphtory/node_state/__init__.pyi +++ b/python/python/raphtory/node_state/__init__.pyi @@ -20,103 +20,128 @@ from pandas import DataFrame class DegreeView(object): """A lazy view over node values""" - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self NodeGroups: + def __ne__(self, value): + """Return self!=value.""" + + def __repr__(self): + """Return repr(self).""" + + def after(self, start: TimeInput): """ - Group by value + Create a view of the DegreeView including all events after `start` (exclusive). + + Arguments: + start (TimeInput): The start time of the window. Returns: - NodeGroups: The grouped nodes + DegreeView """ - def default_layer(self) -> DegreeView: + def at(self, time: TimeInput): """ - Return a view of DegreeView containing only the default edge layer + Create a view of the DegreeView including all events at `time`. + + Arguments: + time (TimeInput): The time of the window. + Returns: - DegreeView: The layered view + DegreeView """ - def layer(self, name: str) -> DegreeView: + def before(self, end: TimeInput): """ - Return a view of DegreeView containing the layer `"name"` - Errors if the layer does not exist + Create a view of the DegreeView including all events before `end` (exclusive). Arguments: - name (str): then name of the layer. + end (TimeInput): The end time of the window. Returns: - DegreeView: The layered view + DegreeView """ - def exclude_layer(self, name: str) -> DegreeView: + def bottom_k(self, k: int) -> NodeStateUsize: """ - Return a view of DegreeView containing all layers except the excluded `name` - Errors if any of the layers do not exist. + Compute the k smallest values Arguments: - name (str): layer name that is excluded for the new view + k (int): The number of values to return Returns: - DegreeView: The layered view + NodeStateUsize: The k smallest values as a node state """ - def exclude_valid_layer(self, name: str) -> DegreeView: + def collect(self): + """ + Compute all values and return the result as a list + + Returns + list[int]: all values as a list + """ + + def compute(self): + """ + Compute all values and return the result as a node view + + Returns: + NodeStateUsize """ - Return a view of DegreeView containing all layers except the excluded `name` - Arguments: - name (str): layer name that is excluded for the new view + def default_layer(self) -> DegreeView: + """ + Return a view of DegreeView containing only the default edge layer Returns: DegreeView: The layered view """ - def has_layer(self, name: str): + @property + def end(self): """ - Check if DegreeView has the layer `"name"` + Gets the latest time that this DegreeView is valid. - Arguments: - name (str): the name of the layer to check + Returns: + Optional[int]: The latest time that this DegreeView is valid or None if the DegreeView is valid for all times. + """ + + @property + def end_date_time(self): + """ + Gets the latest datetime that this DegreeView is valid Returns: - bool + Optional[Datetime]: The latest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. """ - def layers(self, names: list[str]) -> DegreeView: + def exclude_layer(self, name: str) -> DegreeView: """ - Return a view of DegreeView containing all layers `names` + Return a view of DegreeView containing all layers except the excluded `name` Errors if any of the layers do not exist. Arguments: - names (list[str]): list of layer names for the new view + name (str): layer name that is excluded for the new view Returns: DegreeView: The layered view @@ -134,23 +159,21 @@ class DegreeView(object): DegreeView: The layered view """ - def exclude_valid_layers(self, names: list[str]) -> DegreeView: + def exclude_valid_layer(self, name: str) -> DegreeView: """ - Return a view of DegreeView containing all layers except the excluded `names` + Return a view of DegreeView containing all layers except the excluded `name` Arguments: - names (list[str]): list of layer names that are excluded for the new view + name (str): layer name that is excluded for the new view Returns: DegreeView: The layered view """ - def valid_layers(self, names: list[str]) -> DegreeView: + def exclude_valid_layers(self, names: list[str]) -> DegreeView: """ - Return a view of DegreeView containing all layers `names` - Any layers that do not exist are ignored - + Return a view of DegreeView containing all layers except the excluded `names` Arguments: - names (list[str]): list of layer names for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: DegreeView: The layered view @@ -169,42 +192,29 @@ class DegreeView(object): WindowSet: A `WindowSet` object. """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: + def groups(self) -> NodeGroups: """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - - A rolling window is a window that moves forward by `step` size at each iteration. - - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + Group by value Returns: - WindowSet: A `WindowSet` object. + NodeGroups: The grouped nodes """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def has_layer(self, name: str): """ - Create a view of the DegreeView including all events between `start` (inclusive) and `end` (exclusive) + Check if DegreeView has the layer `"name"` Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + name (str): the name of the layer to check Returns: - r DegreeView + bool """ - def at(self, time: TimeInput): + def items(self): """ - Create a view of the DegreeView including all events at `time`. - - Arguments: - time (TimeInput): The time of the window. - Returns: - DegreeView + Iterator[Tuple[Node, int]]: Iterator over items """ def latest(self): @@ -215,257 +225,247 @@ class DegreeView(object): DegreeView """ - def snapshot_at(self, time: TimeInput): + def layer(self, name: str) -> DegreeView: """ - Create a view of the DegreeView including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + Return a view of DegreeView containing the layer `"name"` + Errors if the layer does not exist Arguments: - time (TimeInput): The time of the window. + name (str): then name of the layer. Returns: - DegreeView + DegreeView: The layered view """ - def snapshot_latest(self): + def layers(self, names: list[str]) -> DegreeView: """ - Create a view of the DegreeView including all events that have not been explicitly deleted at the latest time. + Return a view of DegreeView containing all layers `names` + Errors if any of the layers do not exist. - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + Arguments: + names (list[str]): list of layer names for the new view Returns: - DegreeView + DegreeView: The layered view """ - def before(self, end: TimeInput): + def max(self) -> Optional[int]: """ - Create a view of the DegreeView including all events before `end` (exclusive). - - Arguments: - end (TimeInput): The end time of the window. + Return the maximum value Returns: - DegreeView + Optional[int]: The maximum value or `None` if empty """ - def after(self, start: TimeInput): + def max_item(self) -> Optional[Tuple[Node, int]]: """ - Create a view of the DegreeView including all events after `start` (exclusive). - - Arguments: - start (TimeInput): The start time of the window. + Return largest value and corresponding node Returns: - DegreeView + Optional[Tuple[Node, int]]: The Node and maximum value or `None` if empty """ - def shrink_start(self, start: TimeInput): + def mean(self) -> float: """ - Set the start of the window to the larger of `start` and `self.start()` - - Arguments: - start (TimeInput): the new start time of the window + mean of values over all nodes Returns: - DegreeView + float: mean value """ - def shrink_end(self, end: TimeInput): + def median(self): """ - Set the end of the window to the smaller of `end` and `self.end()` + Return the median value - Arguments: - end (TimeInput): the new end time of the window Returns: - DegreeView + Optional[int] """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def median_item(self) -> Optional[Tuple[Node, int]]: """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - - Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + Return median value and corresponding node + Returns: + Optional[Tuple[Node, int]]: The median value or `None` if empty """ - def sum(self) -> int: + def min(self) -> Optional[int]: """ - sum of values over all nodes + Return the minimum value Returns: - int: the sum + Optional[int]: The minimum value or `None` if empty """ - def mean(self) -> float: + def min_item(self) -> Optional[Tuple[Node, int]]: """ - mean of values over all nodes + Return smallest value and corresponding node Returns: - float: mean value + Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty """ - def sorted(self, reverse: bool = False) -> NodeStateUsize: + def nodes(self) -> Nodes: """ - Sort by value - - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Iterate over nodes Returns: - NodeStateUsize: Sorted node state + Nodes: The nodes """ - def top_k(self, k: int) -> NodeStateUsize: + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Compute the k largest values + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + + A rolling window is a window that moves forward by `step` size at each iteration. Arguments: - k (int): The number of values to return + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - NodeStateUsize: The k largest values as a node state + WindowSet: A `WindowSet` object. """ - def bottom_k(self, k: int) -> NodeStateUsize: + def shrink_end(self, end: TimeInput): """ - Compute the k smallest values + Set the end of the window to the smaller of `end` and `self.end()` Arguments: - k (int): The number of values to return - + end (TimeInput): the new end time of the window Returns: - NodeStateUsize: The k smallest values as a node state + DegreeView """ - def min_item(self) -> Optional[Tuple[Node, int]]: + def shrink_start(self, start: TimeInput): """ - Return smallest value and corresponding node + Set the start of the window to the larger of `start` and `self.start()` + + Arguments: + start (TimeInput): the new start time of the window Returns: - Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty + DegreeView """ - def min(self) -> Optional[int]: + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Return the minimum value + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - Returns: - Optional[int]: The minimum value or `None` if empty - """ + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - def max_item(self) -> Optional[Tuple[Node, int]]: """ - Return largest value and corresponding node - Returns: - Optional[Tuple[Node, int]]: The Node and maximum value or `None` if empty + def snapshot_at(self, time: TimeInput): """ + Create a view of the DegreeView including all events that have not been explicitly deleted at `time`. - def max(self) -> Optional[int]: - """ - Return the maximum value + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. Returns: - Optional[int]: The maximum value or `None` if empty + DegreeView """ - def median(self): + def snapshot_latest(self): """ - Return the median value + Create a view of the DegreeView including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Optional[int] + DegreeView """ - def median_item(self) -> Optional[Tuple[Node, int]]: + def sorted(self, reverse: bool = False) -> NodeStateUsize: """ - Return median value and corresponding node + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - Optional[Tuple[Node, int]]: The median value or `None` if empty + NodeStateUsize: Sorted node state """ - def nodes(self) -> Nodes: + def sorted_by_id(self) -> NodeStateUsize: """ - Iterate over nodes + Sort results by node id Returns: - Nodes: The nodes + NodeStateUsize: The sorted node state """ - def items(self): - """ - Returns: - Iterator[Tuple[Node, int]]: Iterator over items + @property + def start(self): """ + Gets the start time for rolling and expanding windows for this DegreeView - def values(self): - """ Returns: - Iterator[int]: Iterator over values + Optional[int]: The earliest time that this DegreeView is valid or None if the DegreeView is valid for all times. """ - def sorted_by_id(self) -> NodeStateUsize: + @property + def start_date_time(self): """ - Sort results by node id + Gets the earliest datetime that this DegreeView is valid Returns: - NodeStateUsize: The sorted node state + Optional[Datetime]: The earliest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. """ - def compute(self): + def sum(self) -> int: """ - Compute all values and return the result as a node view + sum of values over all nodes Returns: - NodeStateUsize - """ - - def collect(self): + int: the sum """ - Compute all values and return the result as a list - Returns - list[int]: all values as a list + def top_k(self, k: int) -> NodeStateUsize: """ + Compute the k largest values - @property - def end(self): - """ - Gets the latest time that this DegreeView is valid. + Arguments: + k (int): The number of values to return Returns: - Optional[int]: The latest time that this DegreeView is valid or None if the DegreeView is valid for all times. + NodeStateUsize: The k largest values as a node state """ - @property - def end_date_time(self): + def valid_layers(self, names: list[str]) -> DegreeView: """ - Gets the latest datetime that this DegreeView is valid + Return a view of DegreeView containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[Datetime]: The latest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. + DegreeView: The layered view """ - @property - def start(self): + def values(self): """ - Gets the start time for rolling and expanding windows for this DegreeView - Returns: - Optional[int]: The earliest time that this DegreeView is valid or None if the DegreeView is valid for all times. + Iterator[int]: Iterator over values """ - @property - def start_date_time(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Gets the earliest datetime that this DegreeView is valid + Create a view of the DegreeView including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - Optional[Datetime]: The earliest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. + r DegreeView """ @property @@ -478,107 +478,67 @@ class DegreeView(object): """ class NodeStateUsize(object): - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return selfvalue.""" - def __ge__(self, value): """Return self>=value.""" - def __iter__(self): - """Implement iter(self).""" - - def __len__(self): - """Return len(self).""" - def __getitem__(self, key): """Return self[key].""" - def groups(self) -> NodeGroups: - """ - Group by value - - Returns: - NodeGroups: The grouped nodes - """ - - def sum(self) -> int: - """ - sum of values over all nodes + def __gt__(self, value): + """Return self>value.""" - Returns: - int: the sum - """ + def __iter__(self): + """Implement iter(self).""" - def mean(self) -> float: - """ - mean of values over all nodes + def __le__(self, value): + """Return self<=value.""" - Returns: - float: mean value - """ + def __len__(self): + """Return len(self).""" - def sorted(self, reverse: bool = False) -> NodeStateUsize: - """ - Sort by value + def __lt__(self, value): + """Return self NodeStateUsize: + def bottom_k(self, k: int) -> NodeStateUsize: """ - Compute the k largest values + Compute the k smallest values Arguments: k (int): The number of values to return Returns: - NodeStateUsize: The k largest values as a node state + NodeStateUsize: The k smallest values as a node state """ - def bottom_k(self, k: int) -> NodeStateUsize: + def groups(self) -> NodeGroups: """ - Compute the k smallest values - - Arguments: - k (int): The number of values to return + Group by value Returns: - NodeStateUsize: The k smallest values as a node state + NodeGroups: The grouped nodes """ - def min_item(self) -> Optional[Tuple[Node, int]]: + def items(self): """ - Return smallest value and corresponding node - Returns: - Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty + Iterator[Tuple[Node, int]]: Iterator over items """ - def min(self) -> Optional[int]: + def max(self) -> Optional[int]: """ - Return the minimum value + Return the maximum value Returns: - Optional[int]: The minimum value or `None` if empty + Optional[int]: The maximum value or `None` if empty """ def max_item(self) -> Optional[Tuple[Node, int]]: @@ -589,12 +549,12 @@ class NodeStateUsize(object): Optional[Tuple[Node, int]]: The Node and maximum value or `None` if empty """ - def max(self) -> Optional[int]: + def mean(self) -> float: """ - Return the maximum value + mean of values over all nodes Returns: - Optional[int]: The maximum value or `None` if empty + float: mean value """ def median(self): @@ -613,64 +573,48 @@ class NodeStateUsize(object): Optional[Tuple[Node, int]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def min(self) -> Optional[int]: """ - Iterate over nodes + Return the minimum value Returns: - Nodes: The nodes + Optional[int]: The minimum value or `None` if empty """ - def items(self): - """ - Returns: - Iterator[Tuple[Node, int]]: Iterator over items + def min_item(self) -> Optional[Tuple[Node, int]]: """ + Return smallest value and corresponding node - def values(self): - """ Returns: - Iterator[int]: Iterator over values + Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty """ - def sorted_by_id(self) -> NodeStateUsize: + def nodes(self) -> Nodes: """ - Sort results by node id + Iterate over nodes Returns: - NodeStateUsize: The sorted node state + Nodes: The nodes """ -class NodeStateU64(object): - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return selfvalue.""" + def sorted(self, reverse: bool = False) -> NodeStateUsize: + """ + Sort by value - def __ge__(self, value): - """Return self>=value.""" + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - def __iter__(self): - """Implement iter(self).""" + Returns: + NodeStateUsize: Sorted node state + """ - def __len__(self): - """Return len(self).""" + def sorted_by_id(self) -> NodeStateUsize: + """ + Sort results by node id - def __getitem__(self, key): - """Return self[key].""" + Returns: + NodeStateUsize: The sorted node state + """ def sum(self) -> int: """ @@ -680,35 +624,53 @@ class NodeStateU64(object): int: the sum """ - def mean(self) -> float: + def top_k(self, k: int) -> NodeStateUsize: """ - mean of values over all nodes + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - float: mean value + NodeStateUsize: The k largest values as a node state """ - def sorted(self, reverse: bool = False) -> NodeStateU64: + def values(self): """ - Sort by value - - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - Returns: - NodeStateU64: Sorted node state + Iterator[int]: Iterator over values """ - def top_k(self, k: int) -> NodeStateU64: - """ - Compute the k largest values +class NodeStateU64(object): + def __eq__(self, value): + """Return self==value.""" - Arguments: - k (int): The number of values to return + def __ge__(self, value): + """Return self>=value.""" - Returns: - NodeStateU64: The k largest values as a node state - """ + def __getitem__(self, key): + """Return self[key].""" + + def __gt__(self, value): + """Return self>value.""" + + def __iter__(self): + """Implement iter(self).""" + + def __le__(self, value): + """Return self<=value.""" + + def __len__(self): + """Return len(self).""" + + def __lt__(self, value): + """Return self NodeStateU64: """ @@ -721,20 +683,18 @@ class NodeStateU64(object): NodeStateU64: The k smallest values as a node state """ - def min_item(self) -> Optional[Tuple[Node, int]]: + def items(self): """ - Return smallest value and corresponding node - Returns: - Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty + Iterator[Tuple[Node, int]]: Iterator over items """ - def min(self) -> Optional[int]: + def max(self) -> Optional[int]: """ - Return the minimum value + Return the maximum value Returns: - Optional[int]: The minimum value or `None` if empty + Optional[int]: The maximum value or `None` if empty """ def max_item(self) -> Optional[Tuple[Node, int]]: @@ -745,12 +705,12 @@ class NodeStateU64(object): Optional[Tuple[Node, int]]: The Node and maximum value or `None` if empty """ - def max(self) -> Optional[int]: + def mean(self) -> float: """ - Return the maximum value + mean of values over all nodes Returns: - Optional[int]: The maximum value or `None` if empty + float: mean value """ def median(self): @@ -769,24 +729,39 @@ class NodeStateU64(object): Optional[Tuple[Node, int]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def min(self) -> Optional[int]: """ - Iterate over nodes + Return the minimum value Returns: - Nodes: The nodes + Optional[int]: The minimum value or `None` if empty """ - def items(self): + def min_item(self) -> Optional[Tuple[Node, int]]: """ + Return smallest value and corresponding node + Returns: - Iterator[Tuple[Node, int]]: Iterator over items + Optional[Tuple[Node, int]]: The Node and minimum value or `None` if empty """ - def values(self): + def nodes(self) -> Nodes: """ + Iterate over nodes + Returns: - Iterator[int]: Iterator over values + Nodes: The nodes + """ + + def sorted(self, reverse: bool = False) -> NodeStateU64: + """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + + Returns: + NodeStateU64: Sorted node state """ def sorted_by_id(self) -> NodeStateU64: @@ -797,118 +772,133 @@ class NodeStateU64(object): NodeStateU64: The sorted node state """ -class IdView(object): - """A lazy view over node values""" + def sum(self) -> int: + """ + sum of values over all nodes - def __repr__(self): - """Return repr(self).""" + Returns: + int: the sum + """ - def __lt__(self, value): - """Return self NodeStateU64: + """ + Compute the k largest values - def __le__(self, value): - """Return self<=value.""" + Arguments: + k (int): The number of values to return + + Returns: + NodeStateU64: The k largest values as a node state + """ + + def values(self): + """ + Returns: + Iterator[int]: Iterator over values + """ +class NodeStateOptionI64(object): def __eq__(self, value): """Return self==value.""" - def __ne__(self, value): - """Return self!=value.""" + def __ge__(self, value): + """Return self>=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" - - def sorted(self, reverse: bool = False) -> NodeStateGID: - """ - Sort by value + def __lt__(self, value): + """Return self NodeStateGID: + def bottom_k(self, k: int) -> NodeStateOptionI64: """ - Compute the k largest values + Compute the k smallest values Arguments: k (int): The number of values to return Returns: - NodeStateGID: The k largest values as a node state + NodeStateOptionI64: The k smallest values as a node state """ - def bottom_k(self, k: int) -> NodeStateGID: + def groups(self) -> NodeGroups: """ - Compute the k smallest values + Group by value - Arguments: - k (int): The number of values to return + Returns: + NodeGroups: The grouped nodes + """ + def items(self): + """ Returns: - NodeStateGID: The k smallest values as a node state + Iterator[Tuple[Node, Optional[int]]]: Iterator over items """ - def min_item(self) -> Optional[Tuple[Node, GID]]: + def max(self) -> Optional[Optional[int]]: """ - Return smallest value and corresponding node + Return the maximum value Returns: - Optional[Tuple[Node, GID]]: The Node and minimum value or `None` if empty + Optional[Optional[int]]: The maximum value or `None` if empty """ - def min(self) -> Optional[GID]: + def max_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ - Return the minimum value + Return largest value and corresponding node Returns: - Optional[GID]: The minimum value or `None` if empty + Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty """ - def max_item(self) -> Optional[Tuple[Node, GID]]: + def median(self): """ - Return largest value and corresponding node + Return the median value Returns: - Optional[Tuple[Node, GID]]: The Node and maximum value or `None` if empty + Optional[Optional[int]] """ - def max(self) -> Optional[GID]: + def median_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ - Return the maximum value + Return median value and corresponding node Returns: - Optional[GID]: The maximum value or `None` if empty + Optional[Tuple[Node, Optional[int]]]: The median value or `None` if empty """ - def median(self): + def min(self) -> Optional[Optional[int]]: """ - Return the median value + Return the minimum value Returns: - Optional[GID] + Optional[Optional[int]]: The minimum value or `None` if empty """ - def median_item(self) -> Optional[Tuple[Node, GID]]: + def min_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ - Return median value and corresponding node + Return smallest value and corresponding node Returns: - Optional[Tuple[Node, GID]]: The median value or `None` if empty + Optional[Tuple[Node, Optional[int]]]: The Node and minimum value or `None` if empty """ def nodes(self) -> Nodes: @@ -919,94 +909,74 @@ class IdView(object): Nodes: The nodes """ - def items(self): - """ - Returns: - Iterator[Tuple[Node, GID]]: Iterator over items + def sorted(self, reverse: bool = False) -> NodeStateOptionI64: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - def values(self): - """ Returns: - Iterator[GID]: Iterator over values + NodeStateOptionI64: Sorted node state """ - def sorted_by_id(self) -> NodeStateGID: + def sorted_by_id(self) -> NodeStateOptionI64: """ Sort results by node id Returns: - NodeStateGID: The sorted node state + NodeStateOptionI64: The sorted node state """ - def compute(self): + def top_k(self, k: int) -> NodeStateOptionI64: """ - Compute all values and return the result as a node view + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - NodeStateGID + NodeStateOptionI64: The k largest values as a node state """ - def collect(self): + def values(self): """ - Compute all values and return the result as a list - - Returns - list[GID]: all values as a list + Returns: + Iterator[Optional[int]]: Iterator over values """ -class NodeStateGID(object): - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" - - def sorted(self, reverse: bool = False) -> NodeStateGID: - """ - Sort by value - - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - - Returns: - NodeStateGID: Sorted node state - """ - - def top_k(self, k: int) -> NodeStateGID: - """ - Compute the k largest values + def __lt__(self, value): + """Return self NodeStateGID: """ @@ -1019,28 +989,26 @@ class NodeStateGID(object): NodeStateGID: The k smallest values as a node state """ - def min_item(self) -> Optional[Tuple[Node, GID]]: + def collect(self): """ - Return smallest value and corresponding node + Compute all values and return the result as a list - Returns: - Optional[Tuple[Node, GID]]: The Node and minimum value or `None` if empty + Returns + list[GID]: all values as a list """ - def min(self) -> Optional[GID]: + def compute(self): """ - Return the minimum value + Compute all values and return the result as a node view Returns: - Optional[GID]: The minimum value or `None` if empty + NodeStateGID """ - def max_item(self) -> Optional[Tuple[Node, GID]]: + def items(self): """ - Return largest value and corresponding node - Returns: - Optional[Tuple[Node, GID]]: The Node and maximum value or `None` if empty + Iterator[Tuple[Node, GID]]: Iterator over items """ def max(self) -> Optional[GID]: @@ -1051,6 +1019,14 @@ class NodeStateGID(object): Optional[GID]: The maximum value or `None` if empty """ + def max_item(self) -> Optional[Tuple[Node, GID]]: + """ + Return largest value and corresponding node + + Returns: + Optional[Tuple[Node, GID]]: The Node and maximum value or `None` if empty + """ + def median(self): """ Return the median value @@ -1067,24 +1043,39 @@ class NodeStateGID(object): Optional[Tuple[Node, GID]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def min(self) -> Optional[GID]: """ - Iterate over nodes + Return the minimum value Returns: - Nodes: The nodes + Optional[GID]: The minimum value or `None` if empty """ - def items(self): + def min_item(self) -> Optional[Tuple[Node, GID]]: """ + Return smallest value and corresponding node + Returns: - Iterator[Tuple[Node, GID]]: Iterator over items + Optional[Tuple[Node, GID]]: The Node and minimum value or `None` if empty """ - def values(self): + def nodes(self) -> Nodes: """ + Iterate over nodes + Returns: - Iterator[GID]: Iterator over values + Nodes: The nodes + """ + + def sorted(self, reverse: bool = False) -> NodeStateGID: + """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + + Returns: + NodeStateGID: Sorted node state """ def sorted_by_id(self) -> NodeStateGID: @@ -1095,183 +1086,205 @@ class NodeStateGID(object): NodeStateGID: The sorted node state """ -class EarliestTimeView(object): - """A lazy view over node values""" + def top_k(self, k: int) -> NodeStateGID: + """ + Compute the k largest values - def __repr__(self): - """Return repr(self).""" + Arguments: + k (int): The number of values to return - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self NodeGroups: + def __ne__(self, value): + """Return self!=value.""" + + def __repr__(self): + """Return repr(self).""" + + def bottom_k(self, k: int) -> NodeStateGID: """ - Group by value + Compute the k smallest values + + Arguments: + k (int): The number of values to return Returns: - NodeGroups: The grouped nodes + NodeStateGID: The k smallest values as a node state """ - def default_layer(self) -> EarliestTimeView: + def items(self): """ - Return a view of EarliestTimeView containing only the default edge layer Returns: - EarliestTimeView: The layered view + Iterator[Tuple[Node, GID]]: Iterator over items """ - def layer(self, name: str) -> EarliestTimeView: + def max(self) -> Optional[GID]: """ - Return a view of EarliestTimeView containing the layer `"name"` - Errors if the layer does not exist - - Arguments: - name (str): then name of the layer. + Return the maximum value Returns: - EarliestTimeView: The layered view + Optional[GID]: The maximum value or `None` if empty """ - def exclude_layer(self, name: str) -> EarliestTimeView: + def max_item(self) -> Optional[Tuple[Node, GID]]: """ - Return a view of EarliestTimeView containing all layers except the excluded `name` - Errors if any of the layers do not exist. - - Arguments: - name (str): layer name that is excluded for the new view + Return largest value and corresponding node Returns: - EarliestTimeView: The layered view + Optional[Tuple[Node, GID]]: The Node and maximum value or `None` if empty """ - def exclude_valid_layer(self, name: str) -> EarliestTimeView: + def median(self): """ - Return a view of EarliestTimeView containing all layers except the excluded `name` - Arguments: - name (str): layer name that is excluded for the new view + Return the median value Returns: - EarliestTimeView: The layered view + Optional[GID] """ - def has_layer(self, name: str): + def median_item(self) -> Optional[Tuple[Node, GID]]: """ - Check if EarliestTimeView has the layer `"name"` - - Arguments: - name (str): the name of the layer to check + Return median value and corresponding node Returns: - bool + Optional[Tuple[Node, GID]]: The median value or `None` if empty """ - def layers(self, names: list[str]) -> EarliestTimeView: + def min(self) -> Optional[GID]: """ - Return a view of EarliestTimeView containing all layers `names` - Errors if any of the layers do not exist. - - Arguments: - names (list[str]): list of layer names for the new view + Return the minimum value Returns: - EarliestTimeView: The layered view + Optional[GID]: The minimum value or `None` if empty """ - def exclude_layers(self, names: list[str]) -> EarliestTimeView: + def min_item(self) -> Optional[Tuple[Node, GID]]: """ - Return a view of EarliestTimeView containing all layers except the excluded `names` - Errors if any of the layers do not exist. - - Arguments: - names (list[str]): list of layer names that are excluded for the new view + Return smallest value and corresponding node Returns: - EarliestTimeView: The layered view + Optional[Tuple[Node, GID]]: The Node and minimum value or `None` if empty """ - def exclude_valid_layers(self, names: list[str]) -> EarliestTimeView: + def nodes(self) -> Nodes: """ - Return a view of EarliestTimeView containing all layers except the excluded `names` - Arguments: - names (list[str]): list of layer names that are excluded for the new view + Iterate over nodes Returns: - EarliestTimeView: The layered view + Nodes: The nodes """ - def valid_layers(self, names: list[str]) -> EarliestTimeView: + def sorted(self, reverse: bool = False) -> NodeStateGID: """ - Return a view of EarliestTimeView containing all layers `names` - Any layers that do not exist are ignored + Sort by value Arguments: - names (list[str]): list of layer names for the new view + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - EarliestTimeView: The layered view + NodeStateGID: Sorted node state """ - def expanding(self, step: int | str) -> WindowSet: + def sorted_by_id(self) -> NodeStateGID: """ - Creates a `WindowSet` with the given `step` size using an expanding window. + Sort results by node id - An expanding window is a window that grows by `step` size at each iteration. + Returns: + NodeStateGID: The sorted node state + """ + + def top_k(self, k: int) -> NodeStateGID: + """ + Compute the k largest values Arguments: - step (int | str): The step size of the window. + k (int): The number of values to return Returns: - WindowSet: A `WindowSet` object. + NodeStateGID: The k largest values as a node state """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: + def values(self): + """ + Returns: + Iterator[GID]: Iterator over values """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - A rolling window is a window that moves forward by `step` size at each iteration. +class EarliestTimeView(object): + """A lazy view over node values""" - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + def __eq__(self, value): + """Return self==value.""" - Returns: - WindowSet: A `WindowSet` object. - """ + def __ge__(self, value): + """Return self>=value.""" - def window(self, start: TimeInput | None, end: TimeInput | None): + def __getitem__(self, key): + """Return self[key].""" + + def __gt__(self, value): + """Return self>value.""" + + def __iter__(self): + """Implement iter(self).""" + + def __le__(self, value): + """Return self<=value.""" + + def __len__(self): + """Return len(self).""" + + def __lt__(self, value): + """Return self NodeStateOptionI64: """ - Create a view of the EarliestTimeView including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + Compute the k smallest values Arguments: - time (TimeInput): The time of the window. + k (int): The number of values to return Returns: - EarliestTimeView + NodeStateOptionI64: The k smallest values as a node state """ - def snapshot_latest(self): + def collect(self): """ - Create a view of the EarliestTimeView including all events that have not been explicitly deleted at the latest time. + Compute all values and return the result as a list - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + Returns + list[Optional[int]]: all values as a list + """ + + def compute(self): + """ + Compute all values and return the result as a node view Returns: - EarliestTimeView + NodeStateOptionI64 """ - def before(self, end: TimeInput): + def default_layer(self) -> EarliestTimeView: + """ + Return a view of EarliestTimeView containing only the default edge layer + Returns: + EarliestTimeView: The layered view """ - Create a view of the EarliestTimeView including all events before `end` (exclusive). - Arguments: - end (TimeInput): The end time of the window. + @property + def end(self): + """ + Gets the latest time that this EarliestTimeView is valid. Returns: - EarliestTimeView + Optional[int]: The latest time that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ - def after(self, start: TimeInput): + @property + def end_date_time(self): """ - Create a view of the EarliestTimeView including all events after `start` (exclusive). - - Arguments: - start (TimeInput): The start time of the window. + Gets the latest datetime that this EarliestTimeView is valid Returns: - EarliestTimeView + Optional[Datetime]: The latest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ - def shrink_start(self, start: TimeInput): + def exclude_layer(self, name: str) -> EarliestTimeView: """ - Set the start of the window to the larger of `start` and `self.start()` + Return a view of EarliestTimeView containing all layers except the excluded `name` + Errors if any of the layers do not exist. Arguments: - start (TimeInput): the new start time of the window + name (str): layer name that is excluded for the new view Returns: - EarliestTimeView + EarliestTimeView: The layered view """ - def shrink_end(self, end: TimeInput): + def exclude_layers(self, names: list[str]) -> EarliestTimeView: """ - Set the end of the window to the smaller of `end` and `self.end()` + Return a view of EarliestTimeView containing all layers except the excluded `names` + Errors if any of the layers do not exist. Arguments: - end (TimeInput): the new end time of the window + names (list[str]): list of layer names that are excluded for the new view + Returns: - EarliestTimeView + EarliestTimeView: The layered view """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def exclude_valid_layer(self, name: str) -> EarliestTimeView: """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - + Return a view of EarliestTimeView containing all layers except the excluded `name` Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + name (str): layer name that is excluded for the new view + Returns: + EarliestTimeView: The layered view """ - def sorted(self, reverse: bool = False): + def exclude_valid_layers(self, names: list[str]) -> EarliestTimeView: """ - Sort by value - + Return a view of EarliestTimeView containing all layers except the excluded `names` Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + names (list[str]): list of layer names that are excluded for the new view Returns: - NodeStateOptionI64: Sorted node state + EarliestTimeView: The layered view """ - def top_k(self, k: int): + def expanding(self, step: int | str) -> WindowSet: """ - Compute the k largest values + Creates a `WindowSet` with the given `step` size using an expanding window. + + An expanding window is a window that grows by `step` size at each iteration. Arguments: - k (int): The number of values to return + step (int | str): The step size of the window. Returns: - NodeStateOptionI64: The k largest values as a node state + WindowSet: A `WindowSet` object. + """ + + def groups(self) -> NodeGroups: """ + Group by value - def bottom_k(self, k: int): + Returns: + NodeGroups: The grouped nodes """ - Compute the k smallest values + + def has_layer(self, name: str): + """ + Check if EarliestTimeView has the layer `"name"` Arguments: - k (int): The number of values to return + name (str): the name of the layer to check Returns: - NodeStateOptionI64: The k smallest values as a node state + bool """ - def min_item(self) -> Optional[Tuple[Node, Optional[int]]]: + def items(self): """ - Return smallest value and corresponding node + Returns: + Iterator[Tuple[Node, Optional[int]]]: Iterator over items + """ + + def latest(self): + """ + Create a view of the EarliestTimeView including all events at the latest time. Returns: - Optional[Tuple[Node, Optional[int]]]: The Node and minimum value or `None` if empty + EarliestTimeView """ - def min(self) -> Optional[Optional[int]]: + def layer(self, name: str) -> EarliestTimeView: """ - Return the minimum value + Return a view of EarliestTimeView containing the layer `"name"` + Errors if the layer does not exist + + Arguments: + name (str): then name of the layer. Returns: - Optional[Optional[int]]: The minimum value or `None` if empty + EarliestTimeView: The layered view """ - def max_item(self) -> Optional[Tuple[Node, Optional[int]]]: + def layers(self, names: list[str]) -> EarliestTimeView: """ - Return largest value and corresponding node + Return a view of EarliestTimeView containing all layers `names` + Errors if any of the layers do not exist. + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty + EarliestTimeView: The layered view """ def max(self) -> Optional[Optional[int]]: @@ -1434,6 +1483,14 @@ class EarliestTimeView(object): Optional[Optional[int]]: The maximum value or `None` if empty """ + def max_item(self) -> Optional[Tuple[Node, Optional[int]]]: + """ + Return largest value and corresponding node + + Returns: + Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty + """ + def median(self): """ Return the median value @@ -1450,57 +1507,116 @@ class EarliestTimeView(object): Optional[Tuple[Node, Optional[int]]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def min(self) -> Optional[Optional[int]]: """ - Iterate over nodes + Return the minimum value Returns: - Nodes: The nodes + Optional[Optional[int]]: The minimum value or `None` if empty """ - def items(self): + def min_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ + Return smallest value and corresponding node + Returns: - Iterator[Tuple[Node, Optional[int]]]: Iterator over items + Optional[Tuple[Node, Optional[int]]]: The Node and minimum value or `None` if empty """ - def values(self): + def nodes(self) -> Nodes: """ + Iterate over nodes + Returns: - Iterator[Optional[int]]: Iterator over values + Nodes: The nodes """ - def sorted_by_id(self): + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Sort results by node id + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + + A rolling window is a window that moves forward by `step` size at each iteration. + + Arguments: + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - NodeStateOptionI64: The sorted node state + WindowSet: A `WindowSet` object. """ - def compute(self): + def shrink_end(self, end: TimeInput): """ - Compute all values and return the result as a node view + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - NodeStateOptionI64 + EarliestTimeView """ - def collect(self): + def shrink_start(self, start: TimeInput): """ - Compute all values and return the result as a list + Set the start of the window to the larger of `start` and `self.start()` - Returns - list[Optional[int]]: all values as a list + Arguments: + start (TimeInput): the new start time of the window + + Returns: + EarliestTimeView """ - @property - def start_date_time(self): + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Gets the earliest datetime that this EarliestTimeView is valid + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window + + """ + + def snapshot_at(self, time: TimeInput): + """ + Create a view of the EarliestTimeView including all events that have not been explicitly deleted at `time`. + + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. Returns: - Optional[Datetime]: The earliest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + EarliestTimeView + """ + + def snapshot_latest(self): + """ + Create a view of the EarliestTimeView including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + + Returns: + EarliestTimeView + """ + + def sorted(self, reverse: bool = False) -> NodeStateOptionI64: + """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + + Returns: + NodeStateOptionI64: Sorted node state + """ + + def sorted_by_id(self) -> NodeStateOptionI64: + """ + Sort results by node id + + Returns: + NodeStateOptionI64: The sorted node state """ @property @@ -1513,345 +1629,326 @@ class EarliestTimeView(object): """ @property - def end_date_time(self): + def start_date_time(self): """ - Gets the latest datetime that this EarliestTimeView is valid + Gets the earliest datetime that this EarliestTimeView is valid Returns: - Optional[Datetime]: The latest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + Optional[Datetime]: The earliest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ - @property - def window_size(self): + def top_k(self, k: int) -> NodeStateOptionI64: """ - Get the window size (difference between start and end) for this EarliestTimeView + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - Optional[int] + NodeStateOptionI64: The k largest values as a node state """ - @property - def end(self): + def valid_layers(self, names: list[str]) -> EarliestTimeView: """ - Gets the latest time that this EarliestTimeView is valid. + Return a view of EarliestTimeView containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[int]: The latest time that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + EarliestTimeView: The layered view """ -class LatestTimeView(object): - """A lazy view over node values""" + def values(self): + """ + Returns: + Iterator[Optional[int]]: Iterator over values + """ - def __repr__(self): - """Return repr(self).""" + def window(self, start: TimeInput | None, end: TimeInput | None): + """ + Create a view of the EarliestTimeView including all events between `start` (inclusive) and `end` (exclusive) - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" - - def groups(self) -> NodeGroups: - """ - Group by value + def __lt__(self, value): + """Return self LatestTimeView: - """ - Return a view of LatestTimeView containing only the default edge layer - Returns: - LatestTimeView: The layered view - """ + def __repr__(self): + """Return repr(self).""" - def layer(self, name: str) -> LatestTimeView: + def after(self, start: TimeInput): """ - Return a view of LatestTimeView containing the layer `"name"` - Errors if the layer does not exist + Create a view of the LatestTimeView including all events after `start` (exclusive). Arguments: - name (str): then name of the layer. + start (TimeInput): The start time of the window. Returns: - LatestTimeView: The layered view + LatestTimeView """ - def exclude_layer(self, name: str) -> LatestTimeView: + def at(self, time: TimeInput): """ - Return a view of LatestTimeView containing all layers except the excluded `name` - Errors if any of the layers do not exist. + Create a view of the LatestTimeView including all events at `time`. Arguments: - name (str): layer name that is excluded for the new view + time (TimeInput): The time of the window. Returns: - LatestTimeView: The layered view + LatestTimeView """ - def exclude_valid_layer(self, name: str) -> LatestTimeView: + def before(self, end: TimeInput): """ - Return a view of LatestTimeView containing all layers except the excluded `name` + Create a view of the LatestTimeView including all events before `end` (exclusive). + Arguments: - name (str): layer name that is excluded for the new view + end (TimeInput): The end time of the window. Returns: - LatestTimeView: The layered view + LatestTimeView """ - def has_layer(self, name: str): + def bottom_k(self, k: int) -> NodeStateOptionI64: """ - Check if LatestTimeView has the layer `"name"` + Compute the k smallest values Arguments: - name (str): the name of the layer to check + k (int): The number of values to return Returns: - bool + NodeStateOptionI64: The k smallest values as a node state """ - def layers(self, names: list[str]) -> LatestTimeView: + def collect(self): """ - Return a view of LatestTimeView containing all layers `names` - Errors if any of the layers do not exist. - - Arguments: - names (list[str]): list of layer names for the new view + Compute all values and return the result as a list - Returns: - LatestTimeView: The layered view + Returns + list[Optional[int]]: all values as a list """ - def exclude_layers(self, names: list[str]) -> LatestTimeView: + def compute(self): """ - Return a view of LatestTimeView containing all layers except the excluded `names` - Errors if any of the layers do not exist. - - Arguments: - names (list[str]): list of layer names that are excluded for the new view + Compute all values and return the result as a node view Returns: - LatestTimeView: The layered view + NodeStateOptionI64 """ - def exclude_valid_layers(self, names: list[str]) -> LatestTimeView: + def default_layer(self) -> LatestTimeView: """ - Return a view of LatestTimeView containing all layers except the excluded `names` - Arguments: - names (list[str]): list of layer names that are excluded for the new view - + Return a view of LatestTimeView containing only the default edge layer Returns: LatestTimeView: The layered view """ - def valid_layers(self, names: list[str]) -> LatestTimeView: + @property + def end(self): """ - Return a view of LatestTimeView containing all layers `names` - Any layers that do not exist are ignored - - Arguments: - names (list[str]): list of layer names for the new view + Gets the latest time that this LatestTimeView is valid. Returns: - LatestTimeView: The layered view + Optional[int]: The latest time that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. """ - def expanding(self, step: int | str) -> WindowSet: + @property + def end_date_time(self): """ - Creates a `WindowSet` with the given `step` size using an expanding window. - - An expanding window is a window that grows by `step` size at each iteration. - - Arguments: - step (int | str): The step size of the window. + Gets the latest datetime that this LatestTimeView is valid Returns: - WindowSet: A `WindowSet` object. + Optional[Datetime]: The latest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: + def exclude_layer(self, name: str) -> LatestTimeView: """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - - A rolling window is a window that moves forward by `step` size at each iteration. + Return a view of LatestTimeView containing all layers except the excluded `name` + Errors if any of the layers do not exist. Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + name (str): layer name that is excluded for the new view Returns: - WindowSet: A `WindowSet` object. + LatestTimeView: The layered view """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def exclude_layers(self, names: list[str]) -> LatestTimeView: """ - Create a view of the LatestTimeView including all events between `start` (inclusive) and `end` (exclusive) + Return a view of LatestTimeView containing all layers except the excluded `names` + Errors if any of the layers do not exist. Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + names (list[str]): list of layer names that are excluded for the new view Returns: - r LatestTimeView + LatestTimeView: The layered view """ - def at(self, time: TimeInput): + def exclude_valid_layer(self, name: str) -> LatestTimeView: """ - Create a view of the LatestTimeView including all events at `time`. - + Return a view of LatestTimeView containing all layers except the excluded `name` Arguments: - time (TimeInput): The time of the window. + name (str): layer name that is excluded for the new view Returns: - LatestTimeView + LatestTimeView: The layered view """ - def latest(self): + def exclude_valid_layers(self, names: list[str]) -> LatestTimeView: """ - Create a view of the LatestTimeView including all events at the latest time. + Return a view of LatestTimeView containing all layers except the excluded `names` + Arguments: + names (list[str]): list of layer names that are excluded for the new view Returns: - LatestTimeView + LatestTimeView: The layered view """ - def snapshot_at(self, time: TimeInput): + def expanding(self, step: int | str) -> WindowSet: """ - Create a view of the LatestTimeView including all events that have not been explicitly deleted at `time`. + Creates a `WindowSet` with the given `step` size using an expanding window. - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + An expanding window is a window that grows by `step` size at each iteration. Arguments: - time (TimeInput): The time of the window. - - Returns: - LatestTimeView - """ - - def snapshot_latest(self): - """ - Create a view of the LatestTimeView including all events that have not been explicitly deleted at the latest time. - - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + step (int | str): The step size of the window. Returns: - LatestTimeView + WindowSet: A `WindowSet` object. """ - def before(self, end: TimeInput): + def groups(self) -> NodeGroups: """ - Create a view of the LatestTimeView including all events before `end` (exclusive). - - Arguments: - end (TimeInput): The end time of the window. + Group by value Returns: - LatestTimeView + NodeGroups: The grouped nodes """ - def after(self, start: TimeInput): + def has_layer(self, name: str): """ - Create a view of the LatestTimeView including all events after `start` (exclusive). + Check if LatestTimeView has the layer `"name"` Arguments: - start (TimeInput): The start time of the window. + name (str): the name of the layer to check Returns: - LatestTimeView + bool """ - def shrink_start(self, start: TimeInput): + def items(self): """ - Set the start of the window to the larger of `start` and `self.start()` - - Arguments: - start (TimeInput): the new start time of the window - Returns: - LatestTimeView + Iterator[Tuple[Node, Optional[int]]]: Iterator over items """ - def shrink_end(self, end: TimeInput): + def latest(self): """ - Set the end of the window to the smaller of `end` and `self.end()` + Create a view of the LatestTimeView including all events at the latest time. - Arguments: - end (TimeInput): the new end time of the window Returns: LatestTimeView """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def layer(self, name: str) -> LatestTimeView: """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + Return a view of LatestTimeView containing the layer `"name"` + Errors if the layer does not exist Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + name (str): then name of the layer. + Returns: + LatestTimeView: The layered view """ - def sorted(self, reverse: bool = False): + def layers(self, names: list[str]) -> LatestTimeView: """ - Sort by value + Return a view of LatestTimeView containing all layers `names` + Errors if any of the layers do not exist. Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + names (list[str]): list of layer names for the new view Returns: - NodeStateOptionI64: Sorted node state + LatestTimeView: The layered view """ - def top_k(self, k: int): + def max(self) -> Optional[Optional[int]]: """ - Compute the k largest values - - Arguments: - k (int): The number of values to return + Return the maximum value Returns: - NodeStateOptionI64: The k largest values as a node state + Optional[Optional[int]]: The maximum value or `None` if empty """ - def bottom_k(self, k: int): + def max_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ - Compute the k smallest values + Return largest value and corresponding node - Arguments: - k (int): The number of values to return + Returns: + Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty + """ + + def median(self): + """ + Return the median value Returns: - NodeStateOptionI64: The k smallest values as a node state + Optional[Optional[int]] """ - def min_item(self) -> Optional[Tuple[Node, Optional[int]]]: + def median_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ - Return smallest value and corresponding node + Return median value and corresponding node Returns: - Optional[Tuple[Node, Optional[int]]]: The Node and minimum value or `None` if empty + Optional[Tuple[Node, Optional[int]]]: The median value or `None` if empty """ def min(self) -> Optional[Optional[int]]: @@ -1862,89 +1959,117 @@ class LatestTimeView(object): Optional[Optional[int]]: The minimum value or `None` if empty """ - def max_item(self) -> Optional[Tuple[Node, Optional[int]]]: + def min_item(self) -> Optional[Tuple[Node, Optional[int]]]: """ - Return largest value and corresponding node + Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty + Optional[Tuple[Node, Optional[int]]]: The Node and minimum value or `None` if empty """ - def max(self) -> Optional[Optional[int]]: + def nodes(self) -> Nodes: """ - Return the maximum value + Iterate over nodes Returns: - Optional[Optional[int]]: The maximum value or `None` if empty + Nodes: The nodes """ - def median(self): + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Return the median value + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + + A rolling window is a window that moves forward by `step` size at each iteration. + + Arguments: + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - Optional[Optional[int]] + WindowSet: A `WindowSet` object. """ - def median_item(self) -> Optional[Tuple[Node, Optional[int]]]: + def shrink_end(self, end: TimeInput): """ - Return median value and corresponding node + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - Optional[Tuple[Node, Optional[int]]]: The median value or `None` if empty + LatestTimeView """ - def nodes(self) -> Nodes: + def shrink_start(self, start: TimeInput): """ - Iterate over nodes + Set the start of the window to the larger of `start` and `self.start()` + + Arguments: + start (TimeInput): the new start time of the window Returns: - Nodes: The nodes + LatestTimeView """ - def items(self): + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Returns: - Iterator[Tuple[Node, Optional[int]]]: Iterator over items + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window + """ - def values(self): + def snapshot_at(self, time: TimeInput): """ + Create a view of the LatestTimeView including all events that have not been explicitly deleted at `time`. + + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. + Returns: - Iterator[Optional[int]]: Iterator over values + LatestTimeView """ - def sorted_by_id(self): + def snapshot_latest(self): """ - Sort results by node id + Create a view of the LatestTimeView including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - NodeStateOptionI64: The sorted node state + LatestTimeView """ - def compute(self): + def sorted(self, reverse: bool = False) -> NodeStateOptionI64: """ - Compute all values and return the result as a node view + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. Returns: - NodeStateOptionI64 + NodeStateOptionI64: Sorted node state """ - def collect(self): + def sorted_by_id(self) -> NodeStateOptionI64: """ - Compute all values and return the result as a list + Sort results by node id - Returns - list[Optional[int]]: all values as a list + Returns: + NodeStateOptionI64: The sorted node state """ @property - def end(self): + def start(self): """ - Gets the latest time that this LatestTimeView is valid. + Gets the start time for rolling and expanding windows for this LatestTimeView Returns: - Optional[int]: The latest time that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + Optional[int]: The earliest time that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. """ @property @@ -1956,22 +2081,45 @@ class LatestTimeView(object): Optional[Datetime]: The earliest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. """ - @property - def end_date_time(self): + def top_k(self, k: int) -> NodeStateOptionI64: """ - Gets the latest datetime that this LatestTimeView is valid + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - Optional[Datetime]: The latest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + NodeStateOptionI64: The k largest values as a node state """ - @property - def start(self): + def valid_layers(self, names: list[str]) -> LatestTimeView: """ - Gets the start time for rolling and expanding windows for this LatestTimeView + Return a view of LatestTimeView containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[int]: The earliest time that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + LatestTimeView: The layered view + """ + + def values(self): + """ + Returns: + Iterator[Optional[int]]: Iterator over values + """ + + def window(self, start: TimeInput | None, end: TimeInput | None): + """ + Create a view of the LatestTimeView including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). + + Returns: + r LatestTimeView """ @property @@ -1986,107 +2134,91 @@ class LatestTimeView(object): class NameView(object): """A lazy view over node values""" - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self NodeGroups: - """ - Group by value + def __ne__(self, value): + """Return self!=value.""" - Returns: - NodeGroups: The grouped nodes - """ + def __repr__(self): + """Return repr(self).""" - def sorted(self, reverse: bool = False) -> NodeStateString: + def bottom_k(self, k: int) -> NodeStateString: """ - Sort by value + Compute the k smallest values Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + k (int): The number of values to return Returns: - NodeStateString: Sorted node state + NodeStateString: The k smallest values as a node state """ - def top_k(self, k: int) -> NodeStateString: + def collect(self): """ - Compute the k largest values - - Arguments: - k (int): The number of values to return + Compute all values and return the result as a list - Returns: - NodeStateString: The k largest values as a node state + Returns + list[str]: all values as a list """ - def bottom_k(self, k: int) -> NodeStateString: + def compute(self): """ - Compute the k smallest values - - Arguments: - k (int): The number of values to return + Compute all values and return the result as a node view Returns: - NodeStateString: The k smallest values as a node state + NodeStateString """ - def min_item(self) -> Optional[Tuple[Node, str]]: + def groups(self) -> NodeGroups: """ - Return smallest value and corresponding node + Group by value Returns: - Optional[Tuple[Node, str]]: The Node and minimum value or `None` if empty + NodeGroups: The grouped nodes """ - def min(self) -> Optional[str]: + def items(self): """ - Return the minimum value - Returns: - Optional[str]: The minimum value or `None` if empty + Iterator[Tuple[Node, str]]: Iterator over items """ - def max_item(self) -> Optional[Tuple[Node, str]]: + def max(self) -> Optional[str]: """ - Return largest value and corresponding node + Return the maximum value Returns: - Optional[Tuple[Node, str]]: The Node and maximum value or `None` if empty + Optional[str]: The maximum value or `None` if empty """ - def max(self) -> Optional[str]: + def max_item(self) -> Optional[Tuple[Node, str]]: """ - Return the maximum value + Return largest value and corresponding node Returns: - Optional[str]: The maximum value or `None` if empty + Optional[Tuple[Node, str]]: The Node and maximum value or `None` if empty """ def median(self): @@ -2105,24 +2237,39 @@ class NameView(object): Optional[Tuple[Node, str]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def min(self) -> Optional[str]: """ - Iterate over nodes + Return the minimum value Returns: - Nodes: The nodes + Optional[str]: The minimum value or `None` if empty """ - def items(self): + def min_item(self) -> Optional[Tuple[Node, str]]: """ + Return smallest value and corresponding node + Returns: - Iterator[Tuple[Node, str]]: Iterator over items + Optional[Tuple[Node, str]]: The Node and minimum value or `None` if empty """ - def values(self): + def nodes(self) -> Nodes: + """ + Iterate over nodes + + Returns: + Nodes: The nodes + """ + + def sorted(self, reverse: bool = False) -> NodeStateString: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Returns: - Iterator[str]: Iterator over values + NodeStateString: Sorted node state """ def sorted_by_id(self) -> NodeStateString: @@ -2133,82 +2280,53 @@ class NameView(object): NodeStateString: The sorted node state """ - def compute(self): + def top_k(self, k: int) -> NodeStateString: """ - Compute all values and return the result as a node view + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - NodeStateString + NodeStateString: The k largest values as a node state """ - def collect(self): + def values(self): """ - Compute all values and return the result as a list - - Returns - list[str]: all values as a list + Returns: + Iterator[str]: Iterator over values """ class NodeStateString(object): - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return selfvalue.""" - def __ge__(self, value): """Return self>=value.""" - def __iter__(self): - """Implement iter(self).""" - - def __len__(self): - """Return len(self).""" - def __getitem__(self, key): """Return self[key].""" - def groups(self) -> NodeGroups: - """ - Group by value - - Returns: - NodeGroups: The grouped nodes - """ + def __gt__(self, value): + """Return self>value.""" - def sorted(self, reverse: bool = False) -> NodeStateString: - """ - Sort by value + def __iter__(self): + """Implement iter(self).""" - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + def __le__(self, value): + """Return self<=value.""" - Returns: - NodeStateString: Sorted node state - """ + def __len__(self): + """Return len(self).""" - def top_k(self, k: int) -> NodeStateString: - """ - Compute the k largest values + def __lt__(self, value): + """Return self NodeStateString: """ @@ -2221,36 +2339,34 @@ class NodeStateString(object): NodeStateString: The k smallest values as a node state """ - def min_item(self) -> Optional[Tuple[Node, str]]: + def groups(self) -> NodeGroups: """ - Return smallest value and corresponding node + Group by value Returns: - Optional[Tuple[Node, str]]: The Node and minimum value or `None` if empty + NodeGroups: The grouped nodes """ - def min(self) -> Optional[str]: + def items(self): """ - Return the minimum value - Returns: - Optional[str]: The minimum value or `None` if empty + Iterator[Tuple[Node, str]]: Iterator over items """ - def max_item(self) -> Optional[Tuple[Node, str]]: + def max(self) -> Optional[str]: """ - Return largest value and corresponding node + Return the maximum value Returns: - Optional[Tuple[Node, str]]: The Node and maximum value or `None` if empty + Optional[str]: The maximum value or `None` if empty """ - def max(self) -> Optional[str]: + def max_item(self) -> Optional[Tuple[Node, str]]: """ - Return the maximum value + Return largest value and corresponding node Returns: - Optional[str]: The maximum value or `None` if empty + Optional[Tuple[Node, str]]: The Node and maximum value or `None` if empty """ def median(self): @@ -2269,24 +2385,39 @@ class NodeStateString(object): Optional[Tuple[Node, str]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def min(self) -> Optional[str]: """ - Iterate over nodes + Return the minimum value Returns: - Nodes: The nodes + Optional[str]: The minimum value or `None` if empty """ - def items(self): + def min_item(self) -> Optional[Tuple[Node, str]]: """ + Return smallest value and corresponding node + Returns: - Iterator[Tuple[Node, str]]: Iterator over items + Optional[Tuple[Node, str]]: The Node and minimum value or `None` if empty """ - def values(self): + def nodes(self) -> Nodes: + """ + Iterate over nodes + + Returns: + Nodes: The nodes + """ + + def sorted(self, reverse: bool = False) -> NodeStateString: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Returns: - Iterator[str]: Iterator over values + NodeStateString: Sorted node state """ def sorted_by_id(self) -> NodeStateString: @@ -2297,106 +2428,148 @@ class NodeStateString(object): NodeStateString: The sorted node state """ -class EarliestDateTimeView(object): - """A lazy view over node values""" + def top_k(self, k: int) -> NodeStateString: + """ + Compute the k largest values - def __repr__(self): - """Return repr(self).""" + Arguments: + k (int): The number of values to return - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self NodeGroups: + def __ne__(self, value): + """Return self!=value.""" + + def __repr__(self): + """Return repr(self).""" + + def after(self, start: TimeInput): """ - Group by value + Create a view of the EarliestDateTimeView including all events after `start` (exclusive). + + Arguments: + start (TimeInput): The start time of the window. Returns: - NodeGroups: The grouped nodes + EarliestDateTimeView """ - def default_layer(self) -> EarliestDateTimeView: + def at(self, time: TimeInput): """ - Return a view of EarliestDateTimeView containing only the default edge layer + Create a view of the EarliestDateTimeView including all events at `time`. + + Arguments: + time (TimeInput): The time of the window. + Returns: - EarliestDateTimeView: The layered view + EarliestDateTimeView """ - def layer(self, name: str) -> EarliestDateTimeView: + def before(self, end: TimeInput): """ - Return a view of EarliestDateTimeView containing the layer `"name"` - Errors if the layer does not exist + Create a view of the EarliestDateTimeView including all events before `end` (exclusive). Arguments: - name (str): then name of the layer. + end (TimeInput): The end time of the window. Returns: - EarliestDateTimeView: The layered view + EarliestDateTimeView """ - def exclude_layer(self, name: str) -> EarliestDateTimeView: + def bottom_k(self, k: int) -> NodeStateOptionDateTime: """ - Return a view of EarliestDateTimeView containing all layers except the excluded `name` - Errors if any of the layers do not exist. + Compute the k smallest values Arguments: - name (str): layer name that is excluded for the new view + k (int): The number of values to return + + Returns: + NodeStateOptionDateTime: The k smallest values as a node state + """ + + def collect(self): + """ + Compute all values and return the result as a list + + Returns + list[Optional[datetime]]: all values as a list + """ + + def compute(self): + """ + Compute all values and return the result as a node view + + Returns: + NodeStateOptionDateTime + """ + def default_layer(self) -> EarliestDateTimeView: + """ + Return a view of EarliestDateTimeView containing only the default edge layer Returns: EarliestDateTimeView: The layered view """ - def exclude_valid_layer(self, name: str) -> EarliestDateTimeView: + @property + def end(self): """ - Return a view of EarliestDateTimeView containing all layers except the excluded `name` - Arguments: - name (str): layer name that is excluded for the new view + Gets the latest time that this EarliestDateTimeView is valid. Returns: - EarliestDateTimeView: The layered view + Optional[int]: The latest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ - def has_layer(self, name: str): + @property + def end_date_time(self): """ - Check if EarliestDateTimeView has the layer `"name"` - - Arguments: - name (str): the name of the layer to check + Gets the latest datetime that this EarliestDateTimeView is valid Returns: - bool + Optional[Datetime]: The latest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ - def layers(self, names: list[str]) -> EarliestDateTimeView: + def exclude_layer(self, name: str) -> EarliestDateTimeView: """ - Return a view of EarliestDateTimeView containing all layers `names` + Return a view of EarliestDateTimeView containing all layers except the excluded `name` Errors if any of the layers do not exist. Arguments: - names (list[str]): list of layer names for the new view + name (str): layer name that is excluded for the new view Returns: EarliestDateTimeView: The layered view @@ -2414,23 +2587,21 @@ class EarliestDateTimeView(object): EarliestDateTimeView: The layered view """ - def exclude_valid_layers(self, names: list[str]) -> EarliestDateTimeView: + def exclude_valid_layer(self, name: str) -> EarliestDateTimeView: """ - Return a view of EarliestDateTimeView containing all layers except the excluded `names` + Return a view of EarliestDateTimeView containing all layers except the excluded `name` Arguments: - names (list[str]): list of layer names that are excluded for the new view + name (str): layer name that is excluded for the new view Returns: EarliestDateTimeView: The layered view """ - def valid_layers(self, names: list[str]) -> EarliestDateTimeView: + def exclude_valid_layers(self, names: list[str]) -> EarliestDateTimeView: """ - Return a view of EarliestDateTimeView containing all layers `names` - Any layers that do not exist are ignored - + Return a view of EarliestDateTimeView containing all layers except the excluded `names` Arguments: - names (list[str]): list of layer names for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: EarliestDateTimeView: The layered view @@ -2449,42 +2620,29 @@ class EarliestDateTimeView(object): WindowSet: A `WindowSet` object. """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: + def groups(self) -> NodeGroups: """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - - A rolling window is a window that moves forward by `step` size at each iteration. - - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + Group by value Returns: - WindowSet: A `WindowSet` object. + NodeGroups: The grouped nodes """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def has_layer(self, name: str): """ - Create a view of the EarliestDateTimeView including all events between `start` (inclusive) and `end` (exclusive) + Check if EarliestDateTimeView has the layer `"name"` Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + name (str): the name of the layer to check Returns: - r EarliestDateTimeView + bool """ - def at(self, time: TimeInput): + def items(self): """ - Create a view of the EarliestDateTimeView including all events at `time`. - - Arguments: - time (TimeInput): The time of the window. - Returns: - EarliestDateTimeView + Iterator[Tuple[Node, Optional[datetime]]]: Iterator over items """ def latest(self): @@ -2495,181 +2653,164 @@ class EarliestDateTimeView(object): EarliestDateTimeView """ - def snapshot_at(self, time: TimeInput): + def layer(self, name: str) -> EarliestDateTimeView: """ - Create a view of the EarliestDateTimeView including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + Return a view of EarliestDateTimeView containing the layer `"name"` + Errors if the layer does not exist Arguments: - time (TimeInput): The time of the window. + name (str): then name of the layer. Returns: - EarliestDateTimeView + EarliestDateTimeView: The layered view """ - def snapshot_latest(self): + def layers(self, names: list[str]) -> EarliestDateTimeView: """ - Create a view of the EarliestDateTimeView including all events that have not been explicitly deleted at the latest time. + Return a view of EarliestDateTimeView containing all layers `names` + Errors if any of the layers do not exist. - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + Arguments: + names (list[str]): list of layer names for the new view Returns: - EarliestDateTimeView + EarliestDateTimeView: The layered view """ - def before(self, end: TimeInput): + def max(self) -> Optional[Optional[datetime]]: """ - Create a view of the EarliestDateTimeView including all events before `end` (exclusive). - - Arguments: - end (TimeInput): The end time of the window. + Return the maximum value Returns: - EarliestDateTimeView + Optional[Optional[datetime]]: The maximum value or `None` if empty """ - def after(self, start: TimeInput): + def max_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ - Create a view of the EarliestDateTimeView including all events after `start` (exclusive). - - Arguments: - start (TimeInput): The start time of the window. + Return largest value and corresponding node Returns: - EarliestDateTimeView + Optional[Tuple[Node, Optional[datetime]]]: The Node and maximum value or `None` if empty """ - def shrink_start(self, start: TimeInput): + def median(self): """ - Set the start of the window to the larger of `start` and `self.start()` - - Arguments: - start (TimeInput): the new start time of the window + Return the median value Returns: - EarliestDateTimeView + Optional[Optional[datetime]] """ - def shrink_end(self, end: TimeInput): + def median_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ - Set the end of the window to the smaller of `end` and `self.end()` + Return median value and corresponding node - Arguments: - end (TimeInput): the new end time of the window Returns: - EarliestDateTimeView + Optional[Tuple[Node, Optional[datetime]]]: The median value or `None` if empty """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def min(self) -> Optional[Optional[datetime]]: """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - - Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + Return the minimum value + Returns: + Optional[Optional[datetime]]: The minimum value or `None` if empty """ - def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: + def min_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ - Sort by value - - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Return smallest value and corresponding node Returns: - NodeStateOptionDateTime: Sorted node state + Optional[Tuple[Node, Optional[datetime]]]: The Node and minimum value or `None` if empty """ - def top_k(self, k: int) -> NodeStateOptionDateTime: + def nodes(self) -> Nodes: """ - Compute the k largest values - - Arguments: - k (int): The number of values to return + Iterate over nodes Returns: - NodeStateOptionDateTime: The k largest values as a node state + Nodes: The nodes """ - def bottom_k(self, k: int) -> NodeStateOptionDateTime: + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Compute the k smallest values + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + + A rolling window is a window that moves forward by `step` size at each iteration. Arguments: - k (int): The number of values to return + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - NodeStateOptionDateTime: The k smallest values as a node state + WindowSet: A `WindowSet` object. """ - def min_item(self): + def shrink_end(self, end: TimeInput): """ - Return smallest value and corresponding node + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The Node and minimum value or `None` if empty - """ - - def min(self): + EarliestDateTimeView """ - Return the minimum value - Returns: - Optional[Optional[Datetime]]: The minimum value or `None` if empty + def shrink_start(self, start: TimeInput): """ + Set the start of the window to the larger of `start` and `self.start()` - def max_item(self): - """ - Return largest value and corresponding node + Arguments: + start (TimeInput): the new start time of the window Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The Node and maximum value or `None` if empty + EarliestDateTimeView """ - def max(self): + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Return the maximum value + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - Returns: - Optional[Optional[Datetime]]: The maximum value or `None` if empty - """ + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - def median(self): """ - Return the median value - Returns: - Optional[Optional[Datetime]] + def snapshot_at(self, time: TimeInput): """ + Create a view of the EarliestDateTimeView including all events that have not been explicitly deleted at `time`. - def median_item(self): - """ - Return median value and corresponding node + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The median value or `None` if empty + EarliestDateTimeView """ - def nodes(self) -> Nodes: + def snapshot_latest(self): """ - Iterate over nodes + Create a view of the EarliestDateTimeView including all events that have not been explicitly deleted at the latest time. - Returns: - Nodes: The nodes - """ + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s - def items(self): - """ Returns: - Iterator[Tuple[Node, Optional[Datetime]]]: Iterator over items + EarliestDateTimeView """ - def values(self): + def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Returns: - Iterator[Optional[Datetime]]: Iterator over values + NodeStateOptionDateTime: Sorted node state """ def sorted_by_id(self) -> NodeStateOptionDateTime: @@ -2680,167 +2821,199 @@ class EarliestDateTimeView(object): NodeStateOptionDateTime: The sorted node state """ - def compute(self): + @property + def start(self): """ - Compute all values and return the result as a node view + Gets the start time for rolling and expanding windows for this EarliestDateTimeView Returns: - NodeStateOptionDateTime + Optional[int]: The earliest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ - def collect(self): + @property + def start_date_time(self): """ - Compute all values and return the result as a list + Gets the earliest datetime that this EarliestDateTimeView is valid - Returns - list[Optional[Datetime]]: all values as a list + Returns: + Optional[Datetime]: The earliest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ - @property - def window_size(self): + def top_k(self, k: int) -> NodeStateOptionDateTime: """ - Get the window size (difference between start and end) for this EarliestDateTimeView + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - Optional[int] + NodeStateOptionDateTime: The k largest values as a node state """ - @property - def start(self): + def valid_layers(self, names: list[str]) -> EarliestDateTimeView: """ - Gets the start time for rolling and expanding windows for this EarliestDateTimeView + Return a view of EarliestDateTimeView containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[int]: The earliest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + EarliestDateTimeView: The layered view """ - @property - def start_date_time(self): + def values(self): """ - Gets the earliest datetime that this EarliestDateTimeView is valid - Returns: - Optional[Datetime]: The earliest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Iterator[Optional[datetime]]: Iterator over values """ - @property - def end_date_time(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Gets the latest datetime that this EarliestDateTimeView is valid + Create a view of the EarliestDateTimeView including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - Optional[Datetime]: The latest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + r EarliestDateTimeView """ @property - def end(self): + def window_size(self): """ - Gets the latest time that this EarliestDateTimeView is valid. + Get the window size (difference between start and end) for this EarliestDateTimeView Returns: - Optional[int]: The latest time that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[int] """ class LatestDateTimeView(object): """A lazy view over node values""" - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self NodeGroups: + def __ne__(self, value): + """Return self!=value.""" + + def __repr__(self): + """Return repr(self).""" + + def after(self, start: TimeInput): """ - Group by value + Create a view of the LatestDateTimeView including all events after `start` (exclusive). + + Arguments: + start (TimeInput): The start time of the window. Returns: - NodeGroups: The grouped nodes + LatestDateTimeView """ - def default_layer(self) -> LatestDateTimeView: + def at(self, time: TimeInput): """ - Return a view of LatestDateTimeView containing only the default edge layer + Create a view of the LatestDateTimeView including all events at `time`. + + Arguments: + time (TimeInput): The time of the window. + Returns: - LatestDateTimeView: The layered view + LatestDateTimeView """ - def layer(self, name: str) -> LatestDateTimeView: + def before(self, end: TimeInput): """ - Return a view of LatestDateTimeView containing the layer `"name"` - Errors if the layer does not exist + Create a view of the LatestDateTimeView including all events before `end` (exclusive). Arguments: - name (str): then name of the layer. + end (TimeInput): The end time of the window. Returns: - LatestDateTimeView: The layered view + LatestDateTimeView """ - def exclude_layer(self, name: str) -> LatestDateTimeView: + def bottom_k(self, k: int) -> NodeStateOptionDateTime: """ - Return a view of LatestDateTimeView containing all layers except the excluded `name` - Errors if any of the layers do not exist. + Compute the k smallest values Arguments: - name (str): layer name that is excluded for the new view + k (int): The number of values to return Returns: - LatestDateTimeView: The layered view + NodeStateOptionDateTime: The k smallest values as a node state """ - def exclude_valid_layer(self, name: str) -> LatestDateTimeView: + def collect(self): + """ + Compute all values and return the result as a list + + Returns + list[Optional[datetime]]: all values as a list """ - Return a view of LatestDateTimeView containing all layers except the excluded `name` - Arguments: - name (str): layer name that is excluded for the new view + def compute(self): + """ + Compute all values and return the result as a node view + + Returns: + NodeStateOptionDateTime + """ + + def default_layer(self) -> LatestDateTimeView: + """ + Return a view of LatestDateTimeView containing only the default edge layer Returns: LatestDateTimeView: The layered view """ - def has_layer(self, name: str): + @property + def end(self): """ - Check if LatestDateTimeView has the layer `"name"` + Gets the latest time that this LatestDateTimeView is valid. - Arguments: - name (str): the name of the layer to check + Returns: + Optional[int]: The latest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + """ + + @property + def end_date_time(self): + """ + Gets the latest datetime that this LatestDateTimeView is valid Returns: - bool + Optional[Datetime]: The latest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ - def layers(self, names: list[str]) -> LatestDateTimeView: + def exclude_layer(self, name: str) -> LatestDateTimeView: """ - Return a view of LatestDateTimeView containing all layers `names` + Return a view of LatestDateTimeView containing all layers except the excluded `name` Errors if any of the layers do not exist. Arguments: - names (list[str]): list of layer names for the new view + name (str): layer name that is excluded for the new view Returns: LatestDateTimeView: The layered view @@ -2858,23 +3031,21 @@ class LatestDateTimeView(object): LatestDateTimeView: The layered view """ - def exclude_valid_layers(self, names: list[str]) -> LatestDateTimeView: + def exclude_valid_layer(self, name: str) -> LatestDateTimeView: """ - Return a view of LatestDateTimeView containing all layers except the excluded `names` + Return a view of LatestDateTimeView containing all layers except the excluded `name` Arguments: - names (list[str]): list of layer names that are excluded for the new view + name (str): layer name that is excluded for the new view Returns: LatestDateTimeView: The layered view """ - def valid_layers(self, names: list[str]) -> LatestDateTimeView: + def exclude_valid_layers(self, names: list[str]) -> LatestDateTimeView: """ - Return a view of LatestDateTimeView containing all layers `names` - Any layers that do not exist are ignored - + Return a view of LatestDateTimeView containing all layers except the excluded `names` Arguments: - names (list[str]): list of layer names for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: LatestDateTimeView: The layered view @@ -2893,42 +3064,29 @@ class LatestDateTimeView(object): WindowSet: A `WindowSet` object. """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: + def groups(self) -> NodeGroups: """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - - A rolling window is a window that moves forward by `step` size at each iteration. - - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. + Group by value Returns: - WindowSet: A `WindowSet` object. + NodeGroups: The grouped nodes """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def has_layer(self, name: str): """ - Create a view of the LatestDateTimeView including all events between `start` (inclusive) and `end` (exclusive) + Check if LatestDateTimeView has the layer `"name"` Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + name (str): the name of the layer to check Returns: - r LatestDateTimeView + bool """ - def at(self, time: TimeInput): + def items(self): """ - Create a view of the LatestDateTimeView including all events at `time`. - - Arguments: - time (TimeInput): The time of the window. - Returns: - LatestDateTimeView + Iterator[Tuple[Node, Optional[datetime]]]: Iterator over items """ def latest(self): @@ -2939,181 +3097,164 @@ class LatestDateTimeView(object): LatestDateTimeView """ - def snapshot_at(self, time: TimeInput): - """ - Create a view of the LatestDateTimeView including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s - - Arguments: - time (TimeInput): The time of the window. - - Returns: - LatestDateTimeView - """ - - def snapshot_latest(self): - """ - Create a view of the LatestDateTimeView including all events that have not been explicitly deleted at the latest time. - - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s - - Returns: - LatestDateTimeView - """ - - def before(self, end: TimeInput): - """ - Create a view of the LatestDateTimeView including all events before `end` (exclusive). - - Arguments: - end (TimeInput): The end time of the window. - - Returns: - LatestDateTimeView - """ - - def after(self, start: TimeInput): + def layer(self, name: str) -> LatestDateTimeView: """ - Create a view of the LatestDateTimeView including all events after `start` (exclusive). + Return a view of LatestDateTimeView containing the layer `"name"` + Errors if the layer does not exist Arguments: - start (TimeInput): The start time of the window. + name (str): then name of the layer. Returns: - LatestDateTimeView + LatestDateTimeView: The layered view """ - def shrink_start(self, start: TimeInput): + def layers(self, names: list[str]) -> LatestDateTimeView: """ - Set the start of the window to the larger of `start` and `self.start()` + Return a view of LatestDateTimeView containing all layers `names` + Errors if any of the layers do not exist. Arguments: - start (TimeInput): the new start time of the window + names (list[str]): list of layer names for the new view Returns: - LatestDateTimeView + LatestDateTimeView: The layered view """ - def shrink_end(self, end: TimeInput): + def max(self) -> Optional[Optional[datetime]]: """ - Set the end of the window to the smaller of `end` and `self.end()` + Return the maximum value - Arguments: - end (TimeInput): the new end time of the window Returns: - LatestDateTimeView - """ - - def shrink_window(self, start: TimeInput, end: TimeInput): - """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - - Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window - + Optional[Optional[datetime]]: The maximum value or `None` if empty """ - def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: + def max_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ - Sort by value - - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Return largest value and corresponding node Returns: - NodeStateOptionDateTime: Sorted node state + Optional[Tuple[Node, Optional[datetime]]]: The Node and maximum value or `None` if empty """ - def top_k(self, k: int) -> NodeStateOptionDateTime: + def median(self): """ - Compute the k largest values - - Arguments: - k (int): The number of values to return + Return the median value Returns: - NodeStateOptionDateTime: The k largest values as a node state + Optional[Optional[datetime]] """ - def bottom_k(self, k: int) -> NodeStateOptionDateTime: + def median_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ - Compute the k smallest values + Return median value and corresponding node - Arguments: - k (int): The number of values to return + Returns: + Optional[Tuple[Node, Optional[datetime]]]: The median value or `None` if empty + """ + + def min(self) -> Optional[Optional[datetime]]: + """ + Return the minimum value Returns: - NodeStateOptionDateTime: The k smallest values as a node state + Optional[Optional[datetime]]: The minimum value or `None` if empty """ - def min_item(self): + def min_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The Node and minimum value or `None` if empty + Optional[Tuple[Node, Optional[datetime]]]: The Node and minimum value or `None` if empty """ - def min(self): + def nodes(self) -> Nodes: """ - Return the minimum value + Iterate over nodes Returns: - Optional[Optional[Datetime]]: The minimum value or `None` if empty + Nodes: The nodes """ - def max_item(self): + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Return largest value and corresponding node + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + + A rolling window is a window that moves forward by `step` size at each iteration. + + Arguments: + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The Node and maximum value or `None` if empty + WindowSet: A `WindowSet` object. """ - def max(self): + def shrink_end(self, end: TimeInput): """ - Return the maximum value + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - Optional[Optional[Datetime]]: The maximum value or `None` if empty + LatestDateTimeView """ - def median(self): + def shrink_start(self, start: TimeInput): """ - Return the median value + Set the start of the window to the larger of `start` and `self.start()` + + Arguments: + start (TimeInput): the new start time of the window Returns: - Optional[Optional[Datetime]] + LatestDateTimeView """ - def median_item(self): + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Return median value and corresponding node + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def snapshot_at(self, time: TimeInput): """ - Iterate over nodes + Create a view of the LatestDateTimeView including all events that have not been explicitly deleted at `time`. + + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. Returns: - Nodes: The nodes + LatestDateTimeView """ - def items(self): + def snapshot_latest(self): """ + Create a view of the LatestDateTimeView including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + Returns: - Iterator[Tuple[Node, Optional[Datetime]]]: Iterator over items + LatestDateTimeView """ - def values(self): + def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Returns: - Iterator[Optional[Datetime]]: Iterator over values + NodeStateOptionDateTime: Sorted node state """ def sorted_by_id(self) -> NodeStateOptionDateTime: @@ -3124,185 +3265,176 @@ class LatestDateTimeView(object): NodeStateOptionDateTime: The sorted node state """ - def compute(self): + @property + def start(self): """ - Compute all values and return the result as a node view + Gets the start time for rolling and expanding windows for this LatestDateTimeView Returns: - NodeStateOptionDateTime + Optional[int]: The earliest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ - def collect(self): + @property + def start_date_time(self): """ - Compute all values and return the result as a list + Gets the earliest datetime that this LatestDateTimeView is valid - Returns - list[Optional[Datetime]]: all values as a list + Returns: + Optional[Datetime]: The earliest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ - @property - def window_size(self): + def top_k(self, k: int) -> NodeStateOptionDateTime: """ - Get the window size (difference between start and end) for this LatestDateTimeView + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - Optional[int] + NodeStateOptionDateTime: The k largest values as a node state """ - @property - def end(self): + def valid_layers(self, names: list[str]) -> LatestDateTimeView: """ - Gets the latest time that this LatestDateTimeView is valid. + Return a view of LatestDateTimeView containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[int]: The latest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + LatestDateTimeView: The layered view """ - @property - def start_date_time(self): + def values(self): """ - Gets the earliest datetime that this LatestDateTimeView is valid - Returns: - Optional[Datetime]: The earliest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + Iterator[Optional[datetime]]: Iterator over values """ - @property - def end_date_time(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Gets the latest datetime that this LatestDateTimeView is valid + Create a view of the LatestDateTimeView including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - Optional[Datetime]: The latest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + r LatestDateTimeView """ @property - def start(self): + def window_size(self): """ - Gets the start time for rolling and expanding windows for this LatestDateTimeView + Get the window size (difference between start and end) for this LatestDateTimeView Returns: - Optional[int]: The earliest time that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + Optional[int] """ class NodeStateOptionDateTime(object): - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self NodeGroups: - """ - Group by value + def __ne__(self, value): + """Return self!=value.""" - Returns: - NodeGroups: The grouped nodes - """ + def __repr__(self): + """Return repr(self).""" - def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: + def bottom_k(self, k: int) -> NodeStateOptionDateTime: """ - Sort by value + Compute the k smallest values Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + k (int): The number of values to return Returns: - NodeStateOptionDateTime: Sorted node state + NodeStateOptionDateTime: The k smallest values as a node state """ - def top_k(self, k: int) -> NodeStateOptionDateTime: + def groups(self) -> NodeGroups: """ - Compute the k largest values - - Arguments: - k (int): The number of values to return + Group by value Returns: - NodeStateOptionDateTime: The k largest values as a node state + NodeGroups: The grouped nodes """ - def bottom_k(self, k: int) -> NodeStateOptionDateTime: + def items(self): """ - Compute the k smallest values - - Arguments: - k (int): The number of values to return - Returns: - NodeStateOptionDateTime: The k smallest values as a node state + Iterator[Tuple[Node, Optional[datetime]]]: Iterator over items """ - def min_item(self): + def max(self) -> Optional[Optional[datetime]]: """ - Return smallest value and corresponding node + Return the maximum value Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The Node and minimum value or `None` if empty + Optional[Optional[datetime]]: The maximum value or `None` if empty """ - def min(self): + def max_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ - Return the minimum value + Return largest value and corresponding node Returns: - Optional[Optional[Datetime]]: The minimum value or `None` if empty + Optional[Tuple[Node, Optional[datetime]]]: The Node and maximum value or `None` if empty """ - def max_item(self): + def median(self): """ - Return largest value and corresponding node + Return the median value Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The Node and maximum value or `None` if empty + Optional[Optional[datetime]] """ - def max(self): + def median_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ - Return the maximum value + Return median value and corresponding node Returns: - Optional[Optional[Datetime]]: The maximum value or `None` if empty + Optional[Tuple[Node, Optional[datetime]]]: The median value or `None` if empty """ - def median(self): + def min(self) -> Optional[Optional[datetime]]: """ - Return the median value + Return the minimum value Returns: - Optional[Optional[Datetime]] + Optional[Optional[datetime]]: The minimum value or `None` if empty """ - def median_item(self): + def min_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: """ - Return median value and corresponding node + Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[Datetime]]]: The median value or `None` if empty + Optional[Tuple[Node, Optional[datetime]]]: The Node and minimum value or `None` if empty """ def nodes(self) -> Nodes: @@ -3313,16 +3445,15 @@ class NodeStateOptionDateTime(object): Nodes: The nodes """ - def items(self): - """ - Returns: - Iterator[Tuple[Node, Optional[Datetime]]]: Iterator over items + def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - def values(self): - """ Returns: - Iterator[Optional[Datetime]]: Iterator over values + NodeStateOptionDateTime: Sorted node state """ def sorted_by_id(self) -> NodeStateOptionDateTime: @@ -3333,98 +3464,148 @@ class NodeStateOptionDateTime(object): NodeStateOptionDateTime: The sorted node state """ -class HistoryView(object): - """A lazy view over node values""" + def top_k(self, k: int) -> NodeStateOptionDateTime: + """ + Compute the k largest values - def __repr__(self): - """Return repr(self).""" + Arguments: + k (int): The number of values to return - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self HistoryView: + def __ne__(self, value): + """Return self!=value.""" + + def __repr__(self): + """Return repr(self).""" + + def after(self, start: TimeInput): """ - Return a view of HistoryView containing only the default edge layer + Create a view of the HistoryView including all events after `start` (exclusive). + + Arguments: + start (TimeInput): The start time of the window. + Returns: - HistoryView: The layered view + HistoryView """ - def layer(self, name: str) -> HistoryView: + def at(self, time: TimeInput): """ - Return a view of HistoryView containing the layer `"name"` - Errors if the layer does not exist + Create a view of the HistoryView including all events at `time`. Arguments: - name (str): then name of the layer. + time (TimeInput): The time of the window. Returns: - HistoryView: The layered view + HistoryView """ - def exclude_layer(self, name: str) -> HistoryView: + def before(self, end: TimeInput): """ - Return a view of HistoryView containing all layers except the excluded `name` - Errors if any of the layers do not exist. + Create a view of the HistoryView including all events before `end` (exclusive). Arguments: - name (str): layer name that is excluded for the new view + end (TimeInput): The end time of the window. Returns: - HistoryView: The layered view + HistoryView """ - def exclude_valid_layer(self, name: str) -> HistoryView: + def bottom_k(self, k: int) -> NodeStateListI64: """ - Return a view of HistoryView containing all layers except the excluded `name` + Compute the k smallest values + Arguments: - name (str): layer name that is excluded for the new view + k (int): The number of values to return + + Returns: + NodeStateListI64: The k smallest values as a node state + """ + + def collect(self): + """ + Compute all values and return the result as a list + + Returns + list[list[int]]: all values as a list + """ + + def compute(self): + """ + Compute all values and return the result as a node view + + Returns: + NodeStateListI64 + """ + def default_layer(self) -> HistoryView: + """ + Return a view of HistoryView containing only the default edge layer Returns: HistoryView: The layered view """ - def has_layer(self, name: str): + @property + def end(self): """ - Check if HistoryView has the layer `"name"` + Gets the latest time that this HistoryView is valid. - Arguments: - name (str): the name of the layer to check + Returns: + Optional[int]: The latest time that this HistoryView is valid or None if the HistoryView is valid for all times. + """ + + @property + def end_date_time(self): + """ + Gets the latest datetime that this HistoryView is valid Returns: - bool + Optional[Datetime]: The latest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. """ - def layers(self, names: list[str]) -> HistoryView: + def exclude_layer(self, name: str) -> HistoryView: """ - Return a view of HistoryView containing all layers `names` + Return a view of HistoryView containing all layers except the excluded `name` Errors if any of the layers do not exist. Arguments: - names (list[str]): list of layer names for the new view + name (str): layer name that is excluded for the new view Returns: HistoryView: The layered view @@ -3442,23 +3623,21 @@ class HistoryView(object): HistoryView: The layered view """ - def exclude_valid_layers(self, names: list[str]) -> HistoryView: + def exclude_valid_layer(self, name: str) -> HistoryView: """ - Return a view of HistoryView containing all layers except the excluded `names` + Return a view of HistoryView containing all layers except the excluded `name` Arguments: - names (list[str]): list of layer names that are excluded for the new view + name (str): layer name that is excluded for the new view Returns: HistoryView: The layered view """ - def valid_layers(self, names: list[str]) -> HistoryView: + def exclude_valid_layers(self, names: list[str]) -> HistoryView: """ - Return a view of HistoryView containing all layers `names` - Any layers that do not exist are ignored - + Return a view of HistoryView containing all layers except the excluded `names` Arguments: - names (list[str]): list of layer names for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: HistoryView: The layered view @@ -3477,42 +3656,21 @@ class HistoryView(object): WindowSet: A `WindowSet` object. """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: - """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - - A rolling window is a window that moves forward by `step` size at each iteration. - - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. - - Returns: - WindowSet: A `WindowSet` object. - """ - - def window(self, start: TimeInput | None, end: TimeInput | None): + def has_layer(self, name: str): """ - Create a view of the HistoryView including all events between `start` (inclusive) and `end` (exclusive) + Check if HistoryView has the layer `"name"` Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + name (str): the name of the layer to check Returns: - r HistoryView + bool """ - def at(self, time: TimeInput): + def items(self): """ - Create a view of the HistoryView including all events at `time`. - - Arguments: - time (TimeInput): The time of the window. - Returns: - HistoryView + Iterator[Tuple[Node, list[int]]]: Iterator over items """ def latest(self): @@ -3523,113 +3681,68 @@ class HistoryView(object): HistoryView """ - def snapshot_at(self, time: TimeInput): - """ - Create a view of the HistoryView including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s - - Arguments: - time (TimeInput): The time of the window. - - Returns: - HistoryView - """ - - def snapshot_latest(self): - """ - Create a view of the HistoryView including all events that have not been explicitly deleted at the latest time. - - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s - - Returns: - HistoryView - """ - - def before(self, end: TimeInput): + def layer(self, name: str) -> HistoryView: """ - Create a view of the HistoryView including all events before `end` (exclusive). + Return a view of HistoryView containing the layer `"name"` + Errors if the layer does not exist Arguments: - end (TimeInput): The end time of the window. + name (str): then name of the layer. Returns: - HistoryView + HistoryView: The layered view """ - def after(self, start: TimeInput): + def layers(self, names: list[str]) -> HistoryView: """ - Create a view of the HistoryView including all events after `start` (exclusive). + Return a view of HistoryView containing all layers `names` + Errors if any of the layers do not exist. Arguments: - start (TimeInput): The start time of the window. + names (list[str]): list of layer names for the new view Returns: - HistoryView + HistoryView: The layered view """ - def shrink_start(self, start: TimeInput): + def max(self) -> Optional[list[int]]: """ - Set the start of the window to the larger of `start` and `self.start()` - - Arguments: - start (TimeInput): the new start time of the window + Return the maximum value Returns: - HistoryView + Optional[list[int]]: The maximum value or `None` if empty """ - def shrink_end(self, end: TimeInput): + def max_item(self) -> Optional[Tuple[Node, list[int]]]: """ - Set the end of the window to the smaller of `end` and `self.end()` + Return largest value and corresponding node - Arguments: - end (TimeInput): the new end time of the window Returns: - HistoryView - """ - - def shrink_window(self, start: TimeInput, end: TimeInput): - """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - - Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window - + Optional[Tuple[Node, list[int]]]: The Node and maximum value or `None` if empty """ - def sorted(self, reverse: bool = False) -> NodeStateListI64: + def median(self): """ - Sort by value - - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Return the median value Returns: - NodeStateListI64: Sorted node state + Optional[list[int]] """ - def top_k(self, k: int) -> NodeStateListI64: + def median_item(self) -> Optional[Tuple[Node, list[int]]]: """ - Compute the k largest values - - Arguments: - k (int): The number of values to return + Return median value and corresponding node Returns: - NodeStateListI64: The k largest values as a node state + Optional[Tuple[Node, list[int]]]: The median value or `None` if empty """ - def bottom_k(self, k: int) -> NodeStateListI64: + def min(self) -> Optional[list[int]]: """ - Compute the k smallest values - - Arguments: - k (int): The number of values to return + Return the minimum value Returns: - NodeStateListI64: The k smallest values as a node state + Optional[list[int]]: The minimum value or `None` if empty """ def min_item(self) -> Optional[Tuple[Node, list[int]]]: @@ -3640,64 +3753,92 @@ class HistoryView(object): Optional[Tuple[Node, list[int]]]: The Node and minimum value or `None` if empty """ - def min(self) -> Optional[list[int]]: + def nodes(self) -> Nodes: """ - Return the minimum value + Iterate over nodes Returns: - Optional[list[int]]: The minimum value or `None` if empty + Nodes: The nodes """ - def max_item(self) -> Optional[Tuple[Node, list[int]]]: + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Return largest value and corresponding node + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + + A rolling window is a window that moves forward by `step` size at each iteration. + + Arguments: + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - Optional[Tuple[Node, list[int]]]: The Node and maximum value or `None` if empty + WindowSet: A `WindowSet` object. """ - def max(self) -> Optional[list[int]]: + def shrink_end(self, end: TimeInput): """ - Return the maximum value + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - Optional[list[int]]: The maximum value or `None` if empty + HistoryView """ - def median(self): + def shrink_start(self, start: TimeInput): """ - Return the median value + Set the start of the window to the larger of `start` and `self.start()` + + Arguments: + start (TimeInput): the new start time of the window Returns: - Optional[list[int]] + HistoryView """ - def median_item(self) -> Optional[Tuple[Node, list[int]]]: + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Return median value and corresponding node + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) + + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - Returns: - Optional[Tuple[Node, list[int]]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def snapshot_at(self, time: TimeInput): """ - Iterate over nodes + Create a view of the HistoryView including all events that have not been explicitly deleted at `time`. + + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. Returns: - Nodes: The nodes + HistoryView """ - def items(self): + def snapshot_latest(self): """ + Create a view of the HistoryView including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + Returns: - Iterator[Tuple[Node, list[int]]]: Iterator over items + HistoryView """ - def values(self): + def sorted(self, reverse: bool = False) -> NodeStateListI64: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Returns: - Iterator[list[int]]: Iterator over values + NodeStateListI64: Sorted node state """ def sorted_by_id(self) -> NodeStateListI64: @@ -3708,56 +3849,63 @@ class HistoryView(object): NodeStateListI64: The sorted node state """ - def compute(self): + @property + def start(self): """ - Compute all values and return the result as a node view + Gets the start time for rolling and expanding windows for this HistoryView Returns: - NodeStateListI64 + Optional[int]: The earliest time that this HistoryView is valid or None if the HistoryView is valid for all times. """ - def collect(self): + @property + def start_date_time(self): """ - Compute all values and return the result as a list + Gets the earliest datetime that this HistoryView is valid - Returns - list[list[int]]: all values as a list + Returns: + Optional[Datetime]: The earliest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. """ - @property - def end_date_time(self): + def top_k(self, k: int) -> NodeStateListI64: """ - Gets the latest datetime that this HistoryView is valid + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - Optional[Datetime]: The latest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. + NodeStateListI64: The k largest values as a node state """ - @property - def start_date_time(self): + def valid_layers(self, names: list[str]) -> HistoryView: """ - Gets the earliest datetime that this HistoryView is valid + Return a view of HistoryView containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[Datetime]: The earliest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. + HistoryView: The layered view """ - @property - def end(self): + def values(self): """ - Gets the latest time that this HistoryView is valid. - Returns: - Optional[int]: The latest time that this HistoryView is valid or None if the HistoryView is valid for all times. + Iterator[list[int]]: Iterator over values """ - @property - def start(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Gets the start time for rolling and expanding windows for this HistoryView + Create a view of the HistoryView including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - Optional[int]: The earliest time that this HistoryView is valid or None if the HistoryView is valid for all times. + r HistoryView """ @property @@ -3770,57 +3918,35 @@ class HistoryView(object): """ class NodeStateListI64(object): - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" - - def sorted(self, reverse: bool = False) -> NodeStateListI64: - """ - Sort by value - - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - - Returns: - NodeStateListI64: Sorted node state - """ - - def top_k(self, k: int) -> NodeStateListI64: - """ - Compute the k largest values + def __lt__(self, value): + """Return self NodeStateListI64: """ @@ -3833,20 +3959,18 @@ class NodeStateListI64(object): NodeStateListI64: The k smallest values as a node state """ - def min_item(self) -> Optional[Tuple[Node, list[int]]]: + def items(self): """ - Return smallest value and corresponding node - Returns: - Optional[Tuple[Node, list[int]]]: The Node and minimum value or `None` if empty + Iterator[Tuple[Node, list[int]]]: Iterator over items """ - def min(self) -> Optional[list[int]]: + def max(self) -> Optional[list[int]]: """ - Return the minimum value + Return the maximum value Returns: - Optional[list[int]]: The minimum value or `None` if empty + Optional[list[int]]: The maximum value or `None` if empty """ def max_item(self) -> Optional[Tuple[Node, list[int]]]: @@ -3857,14 +3981,6 @@ class NodeStateListI64(object): Optional[Tuple[Node, list[int]]]: The Node and maximum value or `None` if empty """ - def max(self) -> Optional[list[int]]: - """ - Return the maximum value - - Returns: - Optional[list[int]]: The maximum value or `None` if empty - """ - def median(self): """ Return the median value @@ -3881,24 +3997,39 @@ class NodeStateListI64(object): Optional[Tuple[Node, list[int]]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def min(self) -> Optional[list[int]]: """ - Iterate over nodes + Return the minimum value Returns: - Nodes: The nodes + Optional[list[int]]: The minimum value or `None` if empty """ - def items(self): + def min_item(self) -> Optional[Tuple[Node, list[int]]]: """ + Return smallest value and corresponding node + Returns: - Iterator[Tuple[Node, list[int]]]: Iterator over items + Optional[Tuple[Node, list[int]]]: The Node and minimum value or `None` if empty """ - def values(self): + def nodes(self) -> Nodes: + """ + Iterate over nodes + + Returns: + Nodes: The nodes + """ + + def sorted(self, reverse: bool = False) -> NodeStateListI64: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Returns: - Iterator[list[int]]: Iterator over values + NodeStateListI64: Sorted node state """ def sorted_by_id(self) -> NodeStateListI64: @@ -3909,98 +4040,148 @@ class NodeStateListI64(object): NodeStateListI64: The sorted node state """ -class HistoryDateTimeView(object): - """A lazy view over node values""" + def top_k(self, k: int) -> NodeStateListI64: + """ + Compute the k largest values - def __repr__(self): - """Return repr(self).""" + Arguments: + k (int): The number of values to return - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" - def __len__(self): - """Return len(self).""" + def __le__(self, value): + """Return self<=value.""" + + def __len__(self): + """Return len(self).""" + + def __lt__(self, value): + """Return self HistoryDateTimeView: + def at(self, time: TimeInput): """ - Return a view of HistoryDateTimeView containing only the default edge layer + Create a view of the HistoryDateTimeView including all events at `time`. + + Arguments: + time (TimeInput): The time of the window. + Returns: - HistoryDateTimeView: The layered view + HistoryDateTimeView """ - def layer(self, name: str) -> HistoryDateTimeView: + def before(self, end: TimeInput): """ - Return a view of HistoryDateTimeView containing the layer `"name"` - Errors if the layer does not exist + Create a view of the HistoryDateTimeView including all events before `end` (exclusive). Arguments: - name (str): then name of the layer. + end (TimeInput): The end time of the window. Returns: - HistoryDateTimeView: The layered view + HistoryDateTimeView """ - def exclude_layer(self, name: str) -> HistoryDateTimeView: + def bottom_k(self, k: int) -> NodeStateOptionListDateTime: """ - Return a view of HistoryDateTimeView containing all layers except the excluded `name` - Errors if any of the layers do not exist. + Compute the k smallest values Arguments: - name (str): layer name that is excluded for the new view + k (int): The number of values to return Returns: - HistoryDateTimeView: The layered view + NodeStateOptionListDateTime: The k smallest values as a node state """ - def exclude_valid_layer(self, name: str) -> HistoryDateTimeView: + def collect(self): + """ + Compute all values and return the result as a list + + Returns + list[Optional[list[datetime]]]: all values as a list """ - Return a view of HistoryDateTimeView containing all layers except the excluded `name` - Arguments: - name (str): layer name that is excluded for the new view + def compute(self): + """ + Compute all values and return the result as a node view + + Returns: + NodeStateOptionListDateTime + """ + + def default_layer(self) -> HistoryDateTimeView: + """ + Return a view of HistoryDateTimeView containing only the default edge layer Returns: HistoryDateTimeView: The layered view """ - def has_layer(self, name: str): + @property + def end(self): """ - Check if HistoryDateTimeView has the layer `"name"` + Gets the latest time that this HistoryDateTimeView is valid. - Arguments: - name (str): the name of the layer to check + Returns: + Optional[int]: The latest time that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + """ + + @property + def end_date_time(self): + """ + Gets the latest datetime that this HistoryDateTimeView is valid Returns: - bool + Optional[Datetime]: The latest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ - def layers(self, names: list[str]) -> HistoryDateTimeView: + def exclude_layer(self, name: str) -> HistoryDateTimeView: """ - Return a view of HistoryDateTimeView containing all layers `names` + Return a view of HistoryDateTimeView containing all layers except the excluded `name` Errors if any of the layers do not exist. Arguments: - names (list[str]): list of layer names for the new view + name (str): layer name that is excluded for the new view Returns: HistoryDateTimeView: The layered view @@ -4018,23 +4199,21 @@ class HistoryDateTimeView(object): HistoryDateTimeView: The layered view """ - def exclude_valid_layers(self, names: list[str]) -> HistoryDateTimeView: + def exclude_valid_layer(self, name: str) -> HistoryDateTimeView: """ - Return a view of HistoryDateTimeView containing all layers except the excluded `names` + Return a view of HistoryDateTimeView containing all layers except the excluded `name` Arguments: - names (list[str]): list of layer names that are excluded for the new view + name (str): layer name that is excluded for the new view Returns: HistoryDateTimeView: The layered view """ - def valid_layers(self, names: list[str]) -> HistoryDateTimeView: + def exclude_valid_layers(self, names: list[str]) -> HistoryDateTimeView: """ - Return a view of HistoryDateTimeView containing all layers `names` - Any layers that do not exist are ignored - + Return a view of HistoryDateTimeView containing all layers except the excluded `names` Arguments: - names (list[str]): list of layer names for the new view + names (list[str]): list of layer names that are excluded for the new view Returns: HistoryDateTimeView: The layered view @@ -4053,42 +4232,21 @@ class HistoryDateTimeView(object): WindowSet: A `WindowSet` object. """ - def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: - """ - Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. - - A rolling window is a window that moves forward by `step` size at each iteration. - - Arguments: - window (int | str): The size of the window. - step (int | str | None): The step size of the window. - `step` defaults to `window`. - - Returns: - WindowSet: A `WindowSet` object. - """ - - def window(self, start: TimeInput | None, end: TimeInput | None): + def has_layer(self, name: str): """ - Create a view of the HistoryDateTimeView including all events between `start` (inclusive) and `end` (exclusive) + Check if HistoryDateTimeView has the layer `"name"` Arguments: - start (TimeInput | None): The start time of the window (unbounded if `None`). - end (TimeInput | None): The end time of the window (unbounded if `None`). + name (str): the name of the layer to check Returns: - r HistoryDateTimeView + bool """ - def at(self, time: TimeInput): + def items(self): """ - Create a view of the HistoryDateTimeView including all events at `time`. - - Arguments: - time (TimeInput): The time of the window. - Returns: - HistoryDateTimeView + Iterator[Tuple[Node, Optional[list[datetime]]]]: Iterator over items """ def latest(self): @@ -4099,181 +4257,164 @@ class HistoryDateTimeView(object): HistoryDateTimeView """ - def snapshot_at(self, time: TimeInput): + def layer(self, name: str) -> HistoryDateTimeView: """ - Create a view of the HistoryDateTimeView including all events that have not been explicitly deleted at `time`. - - This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + Return a view of HistoryDateTimeView containing the layer `"name"` + Errors if the layer does not exist Arguments: - time (TimeInput): The time of the window. + name (str): then name of the layer. Returns: - HistoryDateTimeView + HistoryDateTimeView: The layered view """ - def snapshot_latest(self): + def layers(self, names: list[str]) -> HistoryDateTimeView: """ - Create a view of the HistoryDateTimeView including all events that have not been explicitly deleted at the latest time. + Return a view of HistoryDateTimeView containing all layers `names` + Errors if any of the layers do not exist. - This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s + Arguments: + names (list[str]): list of layer names for the new view Returns: - HistoryDateTimeView + HistoryDateTimeView: The layered view """ - def before(self, end: TimeInput): + def max(self) -> Optional[Optional[list[datetime]]]: """ - Create a view of the HistoryDateTimeView including all events before `end` (exclusive). - - Arguments: - end (TimeInput): The end time of the window. + Return the maximum value Returns: - HistoryDateTimeView + Optional[Optional[list[datetime]]]: The maximum value or `None` if empty """ - def after(self, start: TimeInput): + def max_item(self) -> Optional[Tuple[Node, Optional[list[datetime]]]]: """ - Create a view of the HistoryDateTimeView including all events after `start` (exclusive). - - Arguments: - start (TimeInput): The start time of the window. + Return largest value and corresponding node Returns: - HistoryDateTimeView + Optional[Tuple[Node, Optional[list[datetime]]]]: The Node and maximum value or `None` if empty """ - def shrink_start(self, start: TimeInput): + def median(self): """ - Set the start of the window to the larger of `start` and `self.start()` - - Arguments: - start (TimeInput): the new start time of the window + Return the median value Returns: - HistoryDateTimeView + Optional[Optional[list[datetime]]] """ - def shrink_end(self, end: TimeInput): + def median_item(self) -> Optional[Tuple[Node, Optional[list[datetime]]]]: """ - Set the end of the window to the smaller of `end` and `self.end()` + Return median value and corresponding node - Arguments: - end (TimeInput): the new end time of the window Returns: - HistoryDateTimeView + Optional[Tuple[Node, Optional[list[datetime]]]]: The median value or `None` if empty """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def min(self) -> Optional[Optional[list[datetime]]]: """ - Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - - Arguments: - start (TimeInput): the new start time for the window - end (TimeInput): the new end time for the window + Return the minimum value + Returns: + Optional[Optional[list[datetime]]]: The minimum value or `None` if empty """ - def sorted(self, reverse: bool = False) -> NodeStateOptionListDateTime: + def min_item(self) -> Optional[Tuple[Node, Optional[list[datetime]]]]: """ - Sort by value - - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + Return smallest value and corresponding node Returns: - NodeStateOptionListDateTime: Sorted node state + Optional[Tuple[Node, Optional[list[datetime]]]]: The Node and minimum value or `None` if empty """ - def top_k(self, k: int) -> NodeStateOptionListDateTime: + def nodes(self) -> Nodes: """ - Compute the k largest values - - Arguments: - k (int): The number of values to return + Iterate over nodes Returns: - NodeStateOptionListDateTime: The k largest values as a node state + Nodes: The nodes """ - def bottom_k(self, k: int) -> NodeStateOptionListDateTime: + def rolling(self, window: int | str, step: int | str | None = None) -> WindowSet: """ - Compute the k smallest values + Creates a `WindowSet` with the given `window` size and optional `step` using a rolling window. + + A rolling window is a window that moves forward by `step` size at each iteration. Arguments: - k (int): The number of values to return + window (int | str): The size of the window. + step (int | str | None): The step size of the window. + `step` defaults to `window`. Returns: - NodeStateOptionListDateTime: The k smallest values as a node state + WindowSet: A `WindowSet` object. """ - def min_item(self): + def shrink_end(self, end: TimeInput): """ - Return smallest value and corresponding node + Set the end of the window to the smaller of `end` and `self.end()` + Arguments: + end (TimeInput): the new end time of the window Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]]: The Node and minimum value or `None` if empty - """ - - def min(self): + HistoryDateTimeView """ - Return the minimum value - Returns: - Optional[Optional[list[Datetime]]]: The minimum value or `None` if empty + def shrink_start(self, start: TimeInput): """ + Set the start of the window to the larger of `start` and `self.start()` - def max_item(self): - """ - Return largest value and corresponding node + Arguments: + start (TimeInput): the new start time of the window Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]]: The Node and maximum value or `None` if empty + HistoryDateTimeView """ - def max(self): + def shrink_window(self, start: TimeInput, end: TimeInput): """ - Return the maximum value + Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) - Returns: - Optional[Optional[list[Datetime]]]: The maximum value or `None` if empty - """ + Arguments: + start (TimeInput): the new start time for the window + end (TimeInput): the new end time for the window - def median(self): """ - Return the median value - Returns: - Optional[Optional[list[Datetime]]] + def snapshot_at(self, time: TimeInput): """ + Create a view of the HistoryDateTimeView including all events that have not been explicitly deleted at `time`. - def median_item(self): - """ - Return median value and corresponding node + This is equivalent to `before(time + 1)` for `EventGraph`s and `at(time)` for `PersitentGraph`s + + Arguments: + time (TimeInput): The time of the window. Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]]: The median value or `None` if empty + HistoryDateTimeView """ - def nodes(self) -> Nodes: + def snapshot_latest(self): """ - Iterate over nodes + Create a view of the HistoryDateTimeView including all events that have not been explicitly deleted at the latest time. + + This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Nodes: The nodes + HistoryDateTimeView """ - def items(self): - """ - Returns: - Iterator[Tuple[Node, Optional[list[Datetime]]]]: Iterator over items + def sorted(self, reverse: bool = False) -> NodeStateOptionListDateTime: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - def values(self): - """ Returns: - Iterator[Optional[list[Datetime]]]: Iterator over values + NodeStateOptionListDateTime: Sorted node state """ def sorted_by_id(self) -> NodeStateOptionListDateTime: @@ -4284,56 +4425,63 @@ class HistoryDateTimeView(object): NodeStateOptionListDateTime: The sorted node state """ - def compute(self): + @property + def start(self): """ - Compute all values and return the result as a node view + Gets the start time for rolling and expanding windows for this HistoryDateTimeView Returns: - NodeStateOptionListDateTime + Optional[int]: The earliest time that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ - def collect(self): + @property + def start_date_time(self): """ - Compute all values and return the result as a list + Gets the earliest datetime that this HistoryDateTimeView is valid - Returns - list[Optional[list[Datetime]]]: all values as a list + Returns: + Optional[Datetime]: The earliest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ - @property - def end(self): + def top_k(self, k: int) -> NodeStateOptionListDateTime: """ - Gets the latest time that this HistoryDateTimeView is valid. + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - Optional[int]: The latest time that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + NodeStateOptionListDateTime: The k largest values as a node state """ - @property - def start(self): + def valid_layers(self, names: list[str]) -> HistoryDateTimeView: """ - Gets the start time for rolling and expanding windows for this HistoryDateTimeView + Return a view of HistoryDateTimeView containing all layers `names` + Any layers that do not exist are ignored + + Arguments: + names (list[str]): list of layer names for the new view Returns: - Optional[int]: The earliest time that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + HistoryDateTimeView: The layered view """ - @property - def end_date_time(self): + def values(self): """ - Gets the latest datetime that this HistoryDateTimeView is valid - Returns: - Optional[Datetime]: The latest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + Iterator[Optional[list[datetime]]]: Iterator over values """ - @property - def start_date_time(self): + def window(self, start: TimeInput | None, end: TimeInput | None): """ - Gets the earliest datetime that this HistoryDateTimeView is valid + Create a view of the HistoryDateTimeView including all events between `start` (inclusive) and `end` (exclusive) + + Arguments: + start (TimeInput | None): The start time of the window (unbounded if `None`). + end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - Optional[Datetime]: The earliest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + r HistoryDateTimeView """ @property @@ -4346,115 +4494,99 @@ class HistoryDateTimeView(object): """ class NodeStateOptionListDateTime(object): - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" - - def sorted(self, reverse: bool = False) -> NodeStateOptionListDateTime: - """ - Sort by value + def __lt__(self, value): + """Return self NodeStateOptionListDateTime: + def bottom_k(self, k: int) -> NodeStateOptionListDateTime: """ - Compute the k largest values + Compute the k smallest values Arguments: k (int): The number of values to return Returns: - NodeStateOptionListDateTime: The k largest values as a node state + NodeStateOptionListDateTime: The k smallest values as a node state """ - def bottom_k(self, k: int) -> NodeStateOptionListDateTime: + def items(self): """ - Compute the k smallest values - - Arguments: - k (int): The number of values to return - Returns: - NodeStateOptionListDateTime: The k smallest values as a node state + Iterator[Tuple[Node, Optional[list[datetime]]]]: Iterator over items """ - def min_item(self): + def max(self) -> Optional[Optional[list[datetime]]]: """ - Return smallest value and corresponding node + Return the maximum value Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]]: The Node and minimum value or `None` if empty + Optional[Optional[list[datetime]]]: The maximum value or `None` if empty """ - def min(self): + def max_item(self) -> Optional[Tuple[Node, Optional[list[datetime]]]]: """ - Return the minimum value + Return largest value and corresponding node Returns: - Optional[Optional[list[Datetime]]]: The minimum value or `None` if empty + Optional[Tuple[Node, Optional[list[datetime]]]]: The Node and maximum value or `None` if empty """ - def max_item(self): + def median(self): """ - Return largest value and corresponding node + Return the median value Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]]: The Node and maximum value or `None` if empty + Optional[Optional[list[datetime]]] """ - def max(self): + def median_item(self) -> Optional[Tuple[Node, Optional[list[datetime]]]]: """ - Return the maximum value + Return median value and corresponding node Returns: - Optional[Optional[list[Datetime]]]: The maximum value or `None` if empty + Optional[Tuple[Node, Optional[list[datetime]]]]: The median value or `None` if empty """ - def median(self): + def min(self) -> Optional[Optional[list[datetime]]]: """ - Return the median value + Return the minimum value Returns: - Optional[Optional[list[Datetime]]] + Optional[Optional[list[datetime]]]: The minimum value or `None` if empty """ - def median_item(self): + def min_item(self) -> Optional[Tuple[Node, Optional[list[datetime]]]]: """ - Return median value and corresponding node + Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[list[Datetime]]]]: The median value or `None` if empty + Optional[Tuple[Node, Optional[list[datetime]]]]: The Node and minimum value or `None` if empty """ def nodes(self) -> Nodes: @@ -4465,16 +4597,15 @@ class NodeStateOptionListDateTime(object): Nodes: The nodes """ - def items(self): - """ - Returns: - Iterator[Tuple[Node, Optional[list[Datetime]]]]: Iterator over items + def sorted(self, reverse: bool = False) -> NodeStateOptionListDateTime: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - def values(self): - """ Returns: - Iterator[Optional[list[Datetime]]]: Iterator over values + NodeStateOptionListDateTime: Sorted node state """ def sorted_by_id(self) -> NodeStateOptionListDateTime: @@ -4485,94 +4616,103 @@ class NodeStateOptionListDateTime(object): NodeStateOptionListDateTime: The sorted node state """ -class NodeTypeView(object): - """A lazy view over node values""" + def top_k(self, k: int) -> NodeStateOptionListDateTime: + """ + Compute the k largest values - def __repr__(self): - """Return repr(self).""" + Arguments: + k (int): The number of values to return - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" + def __lt__(self, value): + """Return self NodeGroups: - """ - Group by value + def __ne__(self, value): + """Return self!=value.""" - Returns: - NodeGroups: The grouped nodes - """ + def __repr__(self): + """Return repr(self).""" - def sorted(self, reverse: bool = False) -> NodeStateOptionStr: + def bottom_k(self, k: int) -> NodeStateOptionStr: """ - Sort by value + Compute the k smallest values Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + k (int): The number of values to return Returns: - NodeStateOptionStr: Sorted node state + NodeStateOptionStr: The k smallest values as a node state """ - def top_k(self, k: int) -> NodeStateOptionStr: + def collect(self): """ - Compute the k largest values + Compute all values and return the result as a list - Arguments: - k (int): The number of values to return + Returns + list[Optional[str]]: all values as a list + """ - Returns: - NodeStateOptionStr: The k largest values as a node state + def compute(self): """ + Compute all values and return the result as a node view - def bottom_k(self, k: int) -> NodeStateOptionStr: + Returns: + NodeStateOptionStr """ - Compute the k smallest values - Arguments: - k (int): The number of values to return + def groups(self) -> NodeGroups: + """ + Group by value Returns: - NodeStateOptionStr: The k smallest values as a node state + NodeGroups: The grouped nodes """ - def min_item(self) -> Optional[Tuple[Node, Optional[str]]]: + def items(self): """ - Return smallest value and corresponding node - Returns: - Optional[Tuple[Node, Optional[str]]]: The Node and minimum value or `None` if empty + Iterator[Tuple[Node, Optional[str]]]: Iterator over items """ - def min(self) -> Optional[Optional[str]]: + def max(self) -> Optional[Optional[str]]: """ - Return the minimum value + Return the maximum value Returns: - Optional[Optional[str]]: The minimum value or `None` if empty + Optional[Optional[str]]: The maximum value or `None` if empty """ def max_item(self) -> Optional[Tuple[Node, Optional[str]]]: @@ -4583,28 +4723,36 @@ class NodeTypeView(object): Optional[Tuple[Node, Optional[str]]]: The Node and maximum value or `None` if empty """ - def max(self) -> Optional[Optional[str]]: + def median(self): """ - Return the maximum value + Return the median value Returns: - Optional[Optional[str]]: The maximum value or `None` if empty + Optional[Optional[str]] """ - def median(self): + def median_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ - Return the median value + Return median value and corresponding node + + Returns: + Optional[Tuple[Node, Optional[str]]]: The median value or `None` if empty + """ + + def min(self) -> Optional[Optional[str]]: + """ + Return the minimum value Returns: - Optional[Optional[str]] + Optional[Optional[str]]: The minimum value or `None` if empty """ - def median_item(self) -> Optional[Tuple[Node, Optional[str]]]: + def min_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ - Return median value and corresponding node + Return smallest value and corresponding node Returns: - Optional[Tuple[Node, Optional[str]]]: The median value or `None` if empty + Optional[Tuple[Node, Optional[str]]]: The Node and minimum value or `None` if empty """ def nodes(self) -> Nodes: @@ -4615,16 +4763,15 @@ class NodeTypeView(object): Nodes: The nodes """ - def items(self): - """ - Returns: - Iterator[Tuple[Node, Optional[str]]]: Iterator over items + def sorted(self, reverse: bool = False) -> NodeStateOptionStr: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - def values(self): - """ Returns: - Iterator[Optional[str]]: Iterator over values + NodeStateOptionStr: Sorted node state """ def sorted_by_id(self) -> NodeStateOptionStr: @@ -4635,82 +4782,53 @@ class NodeTypeView(object): NodeStateOptionStr: The sorted node state """ - def compute(self): + def top_k(self, k: int) -> NodeStateOptionStr: """ - Compute all values and return the result as a node view + Compute the k largest values + + Arguments: + k (int): The number of values to return Returns: - NodeStateOptionStr + NodeStateOptionStr: The k largest values as a node state """ - def collect(self): + def values(self): """ - Compute all values and return the result as a list - - Returns - list[Optional[str]]: all values as a list + Returns: + Iterator[Optional[str]]: Iterator over values """ class NodeStateOptionStr(object): - def __repr__(self): - """Return repr(self).""" - - def __lt__(self, value): - """Return selfvalue.""" - def __ge__(self, value): """Return self>=value.""" - def __iter__(self): - """Implement iter(self).""" - - def __len__(self): - """Return len(self).""" - def __getitem__(self, key): """Return self[key].""" - def groups(self) -> NodeGroups: - """ - Group by value - - Returns: - NodeGroups: The grouped nodes - """ + def __gt__(self, value): + """Return self>value.""" - def sorted(self, reverse: bool = False) -> NodeStateOptionStr: - """ - Sort by value + def __iter__(self): + """Implement iter(self).""" - Arguments: - reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + def __le__(self, value): + """Return self<=value.""" - Returns: - NodeStateOptionStr: Sorted node state - """ + def __len__(self): + """Return len(self).""" - def top_k(self, k: int) -> NodeStateOptionStr: - """ - Compute the k largest values + def __lt__(self, value): + """Return self NodeStateOptionStr: """ @@ -4723,36 +4841,34 @@ class NodeStateOptionStr(object): NodeStateOptionStr: The k smallest values as a node state """ - def min_item(self) -> Optional[Tuple[Node, Optional[str]]]: + def groups(self) -> NodeGroups: """ - Return smallest value and corresponding node + Group by value Returns: - Optional[Tuple[Node, Optional[str]]]: The Node and minimum value or `None` if empty + NodeGroups: The grouped nodes """ - def min(self) -> Optional[Optional[str]]: + def items(self): """ - Return the minimum value - Returns: - Optional[Optional[str]]: The minimum value or `None` if empty + Iterator[Tuple[Node, Optional[str]]]: Iterator over items """ - def max_item(self) -> Optional[Tuple[Node, Optional[str]]]: + def max(self) -> Optional[Optional[str]]: """ - Return largest value and corresponding node + Return the maximum value Returns: - Optional[Tuple[Node, Optional[str]]]: The Node and maximum value or `None` if empty + Optional[Optional[str]]: The maximum value or `None` if empty """ - def max(self) -> Optional[Optional[str]]: + def max_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ - Return the maximum value + Return largest value and corresponding node Returns: - Optional[Optional[str]]: The maximum value or `None` if empty + Optional[Tuple[Node, Optional[str]]]: The Node and maximum value or `None` if empty """ def median(self): @@ -4771,24 +4887,39 @@ class NodeStateOptionStr(object): Optional[Tuple[Node, Optional[str]]]: The median value or `None` if empty """ - def nodes(self) -> Nodes: + def min(self) -> Optional[Optional[str]]: """ - Iterate over nodes + Return the minimum value Returns: - Nodes: The nodes + Optional[Optional[str]]: The minimum value or `None` if empty """ - def items(self): + def min_item(self) -> Optional[Tuple[Node, Optional[str]]]: """ + Return smallest value and corresponding node + Returns: - Iterator[Tuple[Node, Optional[str]]]: Iterator over items + Optional[Tuple[Node, Optional[str]]]: The Node and minimum value or `None` if empty """ - def values(self): + def nodes(self) -> Nodes: """ + Iterate over nodes + Returns: - Iterator[Optional[str]]: Iterator over values + Nodes: The nodes + """ + + def sorted(self, reverse: bool = False) -> NodeStateOptionStr: + """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. + + Returns: + NodeStateOptionStr: Sorted node state """ def sorted_by_id(self) -> NodeStateOptionStr: @@ -4799,116 +4930,117 @@ class NodeStateOptionStr(object): NodeStateOptionStr: The sorted node state """ -class NodeStateListDateTime(object): - def __repr__(self): - """Return repr(self).""" + def top_k(self, k: int) -> NodeStateOptionStr: + """ + Compute the k largest values - def __lt__(self, value): - """Return self=value.""" + + def __getitem__(self, key): + """Return self[key].""" def __gt__(self, value): """Return self>value.""" - def __ge__(self, value): - """Return self>=value.""" - def __iter__(self): """Implement iter(self).""" + def __le__(self, value): + """Return self<=value.""" + def __len__(self): """Return len(self).""" - def __getitem__(self, key): - """Return self[key].""" - - def sorted(self, reverse: bool = False) -> NodeStateListDateTime: - """ - Sort by value + def __lt__(self, value): + """Return self NodeStateListDateTime: + def bottom_k(self, k: int) -> NodeStateListDateTime: """ - Compute the k largest values + Compute the k smallest values Arguments: k (int): The number of values to return Returns: - NodeStateListDateTime: The k largest values as a node state + NodeStateListDateTime: The k smallest values as a node state """ - def bottom_k(self, k: int) -> NodeStateListDateTime: + def items(self): """ - Compute the k smallest values - - Arguments: - k (int): The number of values to return - Returns: - NodeStateListDateTime: The k smallest values as a node state + Iterator[Tuple[Node, list[datetime]]]: Iterator over items """ - def min_item(self): + def max(self) -> Optional[list[datetime]]: """ - Return smallest value and corresponding node + Return the maximum value Returns: - Optional[Tuple[Node, list[Datetime]]]: The Node and minimum value or `None` if empty + Optional[list[datetime]]: The maximum value or `None` if empty """ - def min(self): + def max_item(self) -> Optional[Tuple[Node, list[datetime]]]: """ - Return the minimum value + Return largest value and corresponding node Returns: - Optional[list[Datetime]]: The minimum value or `None` if empty + Optional[Tuple[Node, list[datetime]]]: The Node and maximum value or `None` if empty """ - def max_item(self): + def median(self): """ - Return largest value and corresponding node + Return the median value Returns: - Optional[Tuple[Node, list[Datetime]]]: The Node and maximum value or `None` if empty + Optional[list[datetime]] """ - def max(self): + def median_item(self) -> Optional[Tuple[Node, list[datetime]]]: """ - Return the maximum value + Return median value and corresponding node Returns: - Optional[list[Datetime]]: The maximum value or `None` if empty + Optional[Tuple[Node, list[datetime]]]: The median value or `None` if empty """ - def median(self): + def min(self) -> Optional[list[datetime]]: """ - Return the median value + Return the minimum value Returns: - Optional[list[Datetime]] + Optional[list[datetime]]: The minimum value or `None` if empty """ - def median_item(self): + def min_item(self) -> Optional[Tuple[Node, list[datetime]]]: """ - Return median value and corresponding node + Return smallest value and corresponding node Returns: - Optional[Tuple[Node, list[Datetime]]]: The median value or `None` if empty + Optional[Tuple[Node, list[datetime]]]: The Node and minimum value or `None` if empty """ def nodes(self) -> Nodes: @@ -4919,16 +5051,15 @@ class NodeStateListDateTime(object): Nodes: The nodes """ - def items(self): - """ - Returns: - Iterator[Tuple[Node, list[Datetime]]]: Iterator over items + def sorted(self, reverse: bool = False) -> NodeStateListDateTime: """ + Sort by value + + Arguments: + reverse (bool): If `True`, sort in descending order, otherwise ascending. Defaults to False. - def values(self): - """ Returns: - Iterator[list[Datetime]]: Iterator over values + NodeStateListDateTime: Sorted node state """ def sorted_by_id(self) -> NodeStateListDateTime: @@ -4938,3 +5069,20 @@ class NodeStateListDateTime(object): Returns: NodeStateListDateTime: The sorted node state """ + + def top_k(self, k: int) -> NodeStateListDateTime: + """ + Compute the k largest values + + Arguments: + k (int): The number of values to return + + Returns: + NodeStateListDateTime: The k largest values as a node state + """ + + def values(self): + """ + Returns: + Iterator[list[datetime]]: Iterator over values + """ diff --git a/python/python/raphtory/vectors/__init__.pyi b/python/python/raphtory/vectors/__init__.pyi index bd0b523fa5..b82a86dc9e 100644 --- a/python/python/raphtory/vectors/__init__.pyi +++ b/python/python/raphtory/vectors/__init__.pyi @@ -18,12 +18,6 @@ from datetime import datetime from pandas import DataFrame class VectorisedGraph(object): - def save_embeddings(self, file): - """Save the embeddings present in this graph to `file` so they can be further used in a call to `vectorise`""" - - def empty_selection(self): - """Return an empty selection of documents""" - def documents_by_similarity( self, query: str | list, @@ -42,60 +36,66 @@ class VectorisedGraph(object): VectorSelection: The vector selection resulting from the search """ - def entities_by_similarity( + def edges_by_similarity( self, query: str | list, limit: int, window: Optional[Tuple[int | str, int | str]] = None, ) -> VectorSelection: """ - Search the top scoring entities according to `query` with no more than `limit` entities + Search the top scoring edges according to `query` with no more than `limit` edges Args: query (str | list): the text or the embedding to score against - limit (int): the maximum number of new entities to search + limit (int): the maximum number of new edges to search window (Tuple[int | str, int | str], optional): the window where documents need to belong to in order to be considered Returns: VectorSelection: The vector selection resulting from the search """ - def nodes_by_similarity( + def empty_selection(self): + """Return an empty selection of documents""" + + def entities_by_similarity( self, query: str | list, limit: int, window: Optional[Tuple[int | str, int | str]] = None, ) -> VectorSelection: """ - Search the top scoring nodes according to `query` with no more than `limit` nodes + Search the top scoring entities according to `query` with no more than `limit` entities Args: query (str | list): the text or the embedding to score against - limit (int): the maximum number of new nodes to search + limit (int): the maximum number of new entities to search window (Tuple[int | str, int | str], optional): the window where documents need to belong to in order to be considered Returns: VectorSelection: The vector selection resulting from the search """ - def edges_by_similarity( + def nodes_by_similarity( self, query: str | list, limit: int, window: Optional[Tuple[int | str, int | str]] = None, ) -> VectorSelection: """ - Search the top scoring edges according to `query` with no more than `limit` edges + Search the top scoring nodes according to `query` with no more than `limit` nodes Args: query (str | list): the text or the embedding to score against - limit (int): the maximum number of new edges to search + limit (int): the maximum number of new nodes to search window (Tuple[int | str, int | str], optional): the window where documents need to belong to in order to be considered Returns: VectorSelection: The vector selection resulting from the search """ + def save_embeddings(self, file): + """Save the embeddings present in this graph to `file` so they can be further used in a call to `vectorise`""" + class Document(object): def __new__(cls, content, life=None) -> Document: """Create and return a new object. See help(type) for accurate signature.""" @@ -104,45 +104,33 @@ class Document(object): """Return repr(self).""" @property - def life(self): ... - @property - def entity(self): ... + def content(self): ... @property def embedding(self): ... @property - def content(self): ... + def entity(self): ... + @property + def life(self): ... class VectorSelection(object): - def nodes(self): - """Return the nodes present in the current selection""" - - def edges(self): - """Return the edges present in the current selection""" - - def get_documents(self): - """Return the documents present in the current selection""" - - def get_documents_with_scores(self): - """Return the documents alongside their scores present in the current selection""" - - def add_nodes(self, nodes: list): + def add_edges(self, edges: list): """ - Add all the documents associated with the `nodes` to the current selection + Add all the documents associated with the `edges` to the current selection Documents added by this call are assumed to have a score of 0. Args: - nodes (list): a list of the node ids or nodes to add + edges (list): a list of the edge ids or edges to add """ - def add_edges(self, edges: list): + def add_nodes(self, nodes: list): """ - Add all the documents associated with the `edges` to the current selection + Add all the documents associated with the `nodes` to the current selection Documents added by this call are assumed to have a score of 0. Args: - edges (list): a list of the edge ids or edges to add + nodes (list): a list of the node ids or nodes to add """ def append(self, selection: Any): @@ -156,6 +144,9 @@ class VectorSelection(object): The selection with the new documents """ + def edges(self): + """Return the edges present in the current selection""" + def expand(self, hops: int, window: Optional[Tuple[int | str, int | str]] = None): """ Add all the documents `hops` hops away to the selection @@ -193,6 +184,23 @@ class VectorSelection(object): window (Tuple[int | str, int | str], optional): the window where documents need to belong to in order to be considered """ + def expand_edges_by_similarity( + self, + query: str | list, + limit: int, + window: Optional[Tuple[int | str, int | str]] = None, + ): + """ + Add the top `limit` adjacent edges with higher score for `query` to the selection + + This function has the same behavior as expand_entities_by_similarity but it only considers edges. + + Args: + query (str | list): the text or the embedding to score against + limit (int): the maximum number of new edges to add + window (Tuple[int | str, int | str], optional): the window where documents need to belong to in order to be considered + """ + def expand_entities_by_similarity( self, query: str | list, @@ -233,19 +241,11 @@ class VectorSelection(object): window (Tuple[int | str, int | str], optional): the window where documents need to belong to in order to be considered """ - def expand_edges_by_similarity( - self, - query: str | list, - limit: int, - window: Optional[Tuple[int | str, int | str]] = None, - ): - """ - Add the top `limit` adjacent edges with higher score for `query` to the selection + def get_documents(self): + """Return the documents present in the current selection""" - This function has the same behavior as expand_entities_by_similarity but it only considers edges. + def get_documents_with_scores(self): + """Return the documents alongside their scores present in the current selection""" - Args: - query (str | list): the text or the embedding to score against - limit (int): the maximum number of new edges to add - window (Tuple[int | str, int | str], optional): the window where documents need to belong to in order to be considered - """ + def nodes(self): + """Return the nodes present in the current selection""" diff --git a/python/scripts/stub_gen/stub_gen.py b/python/scripts/stub_gen/stub_gen.py index 3ed65ec211..34c498cd89 100644 --- a/python/scripts/stub_gen/stub_gen.py +++ b/python/scripts/stub_gen/stub_gen.py @@ -329,7 +329,7 @@ def gen_bases(cls: type) -> str: def gen_class(cls: type, name) -> str: contents = list(vars(cls).items()) - # contents.sort(key=lambda x: x[0]) + contents.sort(key=lambda x: x[0]) entities: list[str] = [] global cls_logger global fn_logger From dda5b0ce74e7a8b4423c2776cfca4fc4a3df35e5 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 10 Jan 2025 12:06:16 +0100 Subject: [PATCH 17/29] move stub_gen and make sure properties get the warnings as well --- .../stub_gen => stub_gen}/pyproject.toml | 0 .../scripts/stub_gen => stub_gen}/stub_gen.py | 56 ++++++++++++------- 2 files changed, 35 insertions(+), 21 deletions(-) rename {python/scripts/stub_gen => stub_gen}/pyproject.toml (100%) rename {python/scripts/stub_gen => stub_gen}/stub_gen.py (93%) diff --git a/python/scripts/stub_gen/pyproject.toml b/stub_gen/pyproject.toml similarity index 100% rename from python/scripts/stub_gen/pyproject.toml rename to stub_gen/pyproject.toml diff --git a/python/scripts/stub_gen/stub_gen.py b/stub_gen/stub_gen.py similarity index 93% rename from python/scripts/stub_gen/stub_gen.py rename to stub_gen/stub_gen.py index 34c498cd89..7c9faff132 100644 --- a/python/scripts/stub_gen/stub_gen.py +++ b/stub_gen/stub_gen.py @@ -13,6 +13,7 @@ GetSetDescriptorType, MethodDescriptorType, ModuleType, + ClassMethodDescriptorType, ) from typing import * @@ -163,17 +164,9 @@ def clean_parameter( def clean_signature( sig: inspect.Signature, - is_method: bool, type_annotations: dict[str, dict[str, Any]], return_type: Optional[str] = None, -) -> Tuple[str, Optional[str]]: - decorator = None - if is_method: - decorator = "@staticmethod" - if "cls" in sig.parameters: - decorator = "@classmethod" - if "self" in sig.parameters: - decorator = None +) -> str: new_params = [clean_parameter(p, type_annotations) for p in sig.parameters.values()] for param_name, annotations in type_annotations.items(): @@ -183,7 +176,7 @@ def clean_signature( sig = sig.replace(parameters=new_params) if return_type is not None: sig = sig.replace(return_annotation=return_type) - return format_signature(sig), decorator + return format_signature(sig) def insert_self(signature: inspect.Signature) -> inspect.Signature: @@ -264,7 +257,10 @@ def extract_types( param.arg_name: extract_param_annotation(param) for param in parse_result.params } - if parse_result.returns is not None: + if ( + parse_result.returns is not None + and parse_result.returns.type_name is not None + ): return_type = parse_result.returns.type_name try: validate_annotation(return_type) @@ -283,6 +279,21 @@ def extract_types( return dict(), None +def get_decorator(method): + if (inspect.ismethod(method) and inspect.isclass(method.__self__)) or isinstance( + method, ClassMethodDescriptorType + ): + return "@classmethod" + + if inspect.isgetsetdescriptor(method): + return "@property" + + if inspect.isfunction(method): + return "@staticmethod" + + return None + + def gen_fn( function: Union[BuiltinFunctionType, BuiltinMethodType, MethodDescriptorType], name: str, @@ -297,12 +308,15 @@ def gen_fn( function, docs_overwrite, signature.return_annotation is signature.empty ) docstr = format_docstring(function.__doc__, tab=fn_tab, ellipsis=True) - signature, decorator = clean_signature( + signature = clean_signature( signature, # type: ignore - is_method, type_annotations, return_type, ) + decorator = None + if is_method: + decorator = get_decorator(function) + if name == "__new__": # new is special and not a class method decorator = None @@ -312,13 +326,6 @@ def gen_fn( return f"{init_tab}{decorator}\n{fn_str}" if decorator else fn_str -def gen_property(prop: GetSetDescriptorType, name: str) -> str: - prop_tab = TAB * 2 - docstr = format_docstring(prop.__doc__, tab=prop_tab, ellipsis=True) - - return f"{TAB}@property\n{TAB}def {name}(self):\n{docstr}" - - def gen_bases(cls: type) -> str: if cls.__bases__: bases = "(" + ", ".join(format_type(obj) for obj in cls.__bases__) + ")" @@ -364,7 +371,14 @@ def gen_class(cls: type, name) -> str: if isinstance(entity, MethodTypes) or inspect.ismethoddescriptor(entity): entities.append(gen_fn(entity, obj_name, is_method=True)) elif isinstance(entity, GetSetDescriptorType): - entities.append(gen_property(entity, obj_name)) + entities.append( + gen_fn( + entity, + obj_name, + is_method=True, + signature_overwrite=insert_self(inspect.Signature()), + ) + ) else: logger.debug(f"ignoring {repr(obj_name)}: {repr(entity)}") From 0433a3d65db024320b1e62516a9a3443ad0bd805 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 10 Jan 2025 12:25:47 +0100 Subject: [PATCH 18/29] fix static method check --- stub_gen/stub_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stub_gen/stub_gen.py b/stub_gen/stub_gen.py index 7c9faff132..460cedf367 100644 --- a/stub_gen/stub_gen.py +++ b/stub_gen/stub_gen.py @@ -288,7 +288,7 @@ def get_decorator(method): if inspect.isgetsetdescriptor(method): return "@property" - if inspect.isfunction(method): + if inspect.isfunction(method) or isinstance(method, BuiltinFunctionType): return "@staticmethod" return None From b2488febd6e7cf4f215bb77104dbc6299db2f2b9 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 10 Jan 2025 12:27:30 +0100 Subject: [PATCH 19/29] ignore some python stuff --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 991f01c70b..7aa3941b08 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ __pycache__/ # C extensions *.so + +# Python +*.egg-info From 1bbcd307cf2d4cf4033d2a5d217df66e7545d83e Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 10 Jan 2025 12:27:45 +0100 Subject: [PATCH 20/29] move stub-gen --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1e8ffc5507..9cfcd7be44 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ pull-storage: activate-storage git submodule update --init --recursive install-stub-gen: - python -mpip install ./python/scripts/stub_gen + python -mpip install -e stub_gen stubs: install-stub-gen cd python && ./scripts/gen-stubs.py && mypy -m raphtory From 683cbaa1d158f846ddadc19a4ad9dab270e252a0 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 10 Jan 2025 12:55:15 +0100 Subject: [PATCH 21/29] fix some docs --- raphtory/src/python/graph/edge.rs | 26 ++++++------------- raphtory/src/python/graph/node.rs | 5 +--- .../src/python/graph/node_state/node_state.rs | 10 ++++--- .../types/macros/trait_impl/layerops.rs | 2 +- .../python/types/macros/trait_impl/timeops.rs | 26 ++++++++++--------- 5 files changed, 31 insertions(+), 38 deletions(-) diff --git a/raphtory/src/python/graph/edge.rs b/raphtory/src/python/graph/edge.rs index 8c656f854f..da2ff1ea43 100644 --- a/raphtory/src/python/graph/edge.rs +++ b/raphtory/src/python/graph/edge.rs @@ -153,16 +153,6 @@ impl_edgeviewops!(PyEdge, edge, EdgeView, "Edge"); /// An edge is a directed connection between two nodes. #[pymethods] impl PyEdge { - /// Rich Comparison for Node objects - // pub fn __richcmp__(&self, other: Borrowed, op: CompareOp) -> Borrowed { - // let py = other.py(); - // match op { - // CompareOp::Eq => (self.edge.id() == other.id()).into_py(py), - // CompareOp::Ne => (self.edge.id() != other.id()).into_py(py), - // _ => py.NotImplemented(), - // } - // } - fn __eq__(&self, other: Bound) -> bool { self.edge == other.get().edge } @@ -229,7 +219,7 @@ impl PyEdge { /// Returns a list of timestamps of when an edge is added or change to an edge is made. /// /// Returns: - /// List[Datetime] + /// List[datetime] /// pub fn history_date_time(&self) -> Option>> { self.edge.history_date_time() @@ -246,35 +236,35 @@ impl PyEdge { /// Returns a list of timestamps of when an edge is deleted /// /// Returns: - /// List[Datetime] + /// List[datetime] pub fn deletions_data_time(&self) -> Option>> { self.edge.deletions_date_time() } /// Check if the edge is currently valid (i.e., not deleted) /// Returns: - /// bool + /// bool: pub fn is_valid(&self) -> bool { self.edge.is_valid() } /// Check if the edge is currently active (i.e., has at least one update within this period) /// Returns: - /// bool + /// bool: pub fn is_active(&self) -> bool { self.edge.is_active() } /// Check if the edge is currently deleted /// Returns: - /// bool + /// bool: pub fn is_deleted(&self) -> bool { self.edge.is_deleted() } /// Check if the edge is on the same node /// Returns: - /// bool + /// bool: pub fn is_self_loop(&self) -> bool { self.edge.is_self_loop() } @@ -300,7 +290,7 @@ impl PyEdge { /// Gets of earliest datetime of an edge. /// /// Returns: - /// Datetime: the earliest datetime of an edge + /// datetime: the earliest datetime of an edge #[getter] pub fn earliest_date_time(&self) -> Option> { self.edge.earliest_date_time() @@ -318,7 +308,7 @@ impl PyEdge { /// Gets of latest datetime of an edge. /// /// Returns: - /// Datetime: the latest datetime of an edge + /// datetime: the latest datetime of an edge #[getter] pub fn latest_date_time(&self) -> Option> { self.edge.latest_date_time() diff --git a/raphtory/src/python/graph/node.rs b/raphtory/src/python/graph/node.rs index f1c2932fa4..ea526a235a 100644 --- a/raphtory/src/python/graph/node.rs +++ b/raphtory/src/python/graph/node.rs @@ -184,11 +184,8 @@ impl PyNode { /// Returns the latest datetime that the node exists. /// - /// Arguments: - /// None - /// /// Returns: - /// Datetime: The latest datetime that the node exists as a Datetime. + /// datetime: The latest datetime that the node exists as a Datetime. #[getter] pub fn latest_date_time(&self) -> Option> { self.node.latest_date_time() diff --git a/raphtory/src/python/graph/node_state/node_state.rs b/raphtory/src/python/graph/node_state/node_state.rs index f812e08a5a..99684ddf94 100644 --- a/raphtory/src/python/graph/node_state/node_state.rs +++ b/raphtory/src/python/graph/node_state/node_state.rs @@ -80,6 +80,8 @@ macro_rules! impl_node_state_ops { }) } + /// Iterate over items + /// /// Returns: #[doc = concat!(" Iterator[Tuple[Node, ", $py_value, "]]: Iterator over items")] fn items(&self) -> PyBorrowingIterator { @@ -88,6 +90,8 @@ macro_rules! impl_node_state_ops { .map(|(n, v)| (n.cloned(), ($to_owned)(v)))) } + /// Iterate over values + /// /// Returns: #[doc = concat!(" Iterator[",$py_value, "]: Iterator over values")] fn values(&self) -> PyBorrowingIterator { @@ -201,7 +205,7 @@ macro_rules! impl_node_state_ord_ops { /// Return the median value /// /// Returns: - #[doc = concat!(" Optional[", $py_value, "]")] + #[doc = concat!(" Optional[", $py_value, "]:")] fn median(&self) -> Option<$value> { self.inner.median().map($to_owned) } @@ -282,7 +286,7 @@ macro_rules! impl_lazy_node_state { /// Compute all values and return the result as a node view /// /// Returns: - #[doc = concat!(" ", $computed)] + #[doc = concat!(" ", $computed, ": the computed `NodeState`")] fn compute( &self, ) -> NodeState<'static, <$op as NodeOp>::Output, DynamicGraph, DynamicGraph> { @@ -291,7 +295,7 @@ macro_rules! impl_lazy_node_state { /// Compute all values and return the result as a list /// - /// Returns + /// Returns: #[doc = concat!(" list[", $py_value, "]", ": all values as a list")] fn collect(&self) -> Vec<<$op as NodeOp>::Output> { self.inner.collect() diff --git a/raphtory/src/python/types/macros/trait_impl/layerops.rs b/raphtory/src/python/types/macros/trait_impl/layerops.rs index 42a6097e4e..95433dc1e5 100644 --- a/raphtory/src/python/types/macros/trait_impl/layerops.rs +++ b/raphtory/src/python/types/macros/trait_impl/layerops.rs @@ -66,7 +66,7 @@ macro_rules! impl_layerops { /// name (str): the name of the layer to check /// /// Returns: - /// bool + /// bool: fn has_layer( &self, name: &str, diff --git a/raphtory/src/python/types/macros/trait_impl/timeops.rs b/raphtory/src/python/types/macros/trait_impl/timeops.rs index 54b897855f..f97ee54781 100644 --- a/raphtory/src/python/types/macros/trait_impl/timeops.rs +++ b/raphtory/src/python/types/macros/trait_impl/timeops.rs @@ -22,7 +22,7 @@ macro_rules! impl_timeops { #[doc = concat!(r" Gets the earliest datetime that this ", $name, r" is valid")] /// /// Returns: - #[doc = concat!(r" Optional[Datetime]: The earliest datetime that this ", $name, r" is valid or None if the ", $name, r" is valid for all times.")] + #[doc = concat!(r" Optional[datetime]: The earliest datetime that this ", $name, r" is valid or None if the ", $name, r" is valid for all times.")] #[getter] pub fn start_date_time(&self) -> Option> { self.$field.start_date_time() @@ -40,7 +40,7 @@ macro_rules! impl_timeops { #[doc = concat!(r" Gets the latest datetime that this ", $name, r" is valid")] /// /// Returns: - #[doc = concat!(r" Optional[Datetime]: The latest datetime that this ", $name, r" is valid or None if the ", $name, r" is valid for all times.")] + #[doc = concat!(r" Optional[datetime]: The latest datetime that this ", $name, r" is valid or None if the ", $name, r" is valid for all times.")] #[getter] pub fn end_date_time(&self) -> Option> { self.$field.end_date_time() @@ -49,7 +49,7 @@ macro_rules! impl_timeops { #[doc = concat!(r" Get the window size (difference between start and end) for this ", $name)] /// /// Returns: - /// Optional[int] + /// Optional[int]: #[getter] pub fn window_size(&self) -> Option { self.$field.window_size() @@ -95,7 +95,7 @@ macro_rules! impl_timeops { /// end (TimeInput | None): The end time of the window (unbounded if `None`). /// /// Returns: - #[doc = concat!("r ", $name)] + #[doc = concat!(" ", $name, ":")] pub fn window( &self, start: $crate::python::utils::PyTime, @@ -111,7 +111,7 @@ macro_rules! impl_timeops { /// time (TimeInput): The time of the window. /// /// Returns: - #[doc = concat!(r" ", $name)] + #[doc = concat!(r" ", $name, ":")] pub fn at(&self, time: $crate::python::utils::PyTime) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.at(time) } @@ -119,7 +119,7 @@ macro_rules! impl_timeops { #[doc = concat!(r" Create a view of the ", $name, r" including all events at the latest time.")] /// /// Returns: - #[doc = concat!(r" ", $name)] + #[doc = concat!(r" ", $name, ":")] pub fn latest(&self) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.latest() } @@ -132,7 +132,7 @@ macro_rules! impl_timeops { /// time (TimeInput): The time of the window. /// /// Returns: - #[doc = concat!(r" ", $name)] + #[doc = concat!(r" ", $name, ":")] pub fn snapshot_at(&self, time: $crate::python::utils::PyTime) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.snapshot_at(time) } @@ -142,7 +142,7 @@ macro_rules! impl_timeops { /// This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s /// /// Returns: - #[doc = concat!(r" ", $name)] + #[doc = concat!(r" ", $name, ":")] pub fn snapshot_latest(&self) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.snapshot_latest() } @@ -153,7 +153,7 @@ macro_rules! impl_timeops { /// end (TimeInput): The end time of the window. /// /// Returns: - #[doc = concat!(r" ", $name)] + #[doc = concat!(r" ", $name, ":")] pub fn before(&self, end: $crate::python::utils::PyTime) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.before(end) } @@ -164,7 +164,7 @@ macro_rules! impl_timeops { /// start (TimeInput): The start time of the window. /// /// Returns: - #[doc = concat!(r" ", $name)] + #[doc = concat!(r" ", $name, ":")] pub fn after(&self, start: $crate::python::utils::PyTime) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.after(start) } @@ -175,7 +175,7 @@ macro_rules! impl_timeops { /// start (TimeInput): the new start time of the window /// /// Returns: - #[doc = concat!(r" ", $name)] + #[doc = concat!(r" ", $name, ":")] pub fn shrink_start(&self, start: $crate::python::utils::PyTime) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.shrink_start(start) } @@ -185,7 +185,7 @@ macro_rules! impl_timeops { /// Arguments: /// end (TimeInput): the new end time of the window /// Returns: - #[doc = concat!(r" ", $name)] + #[doc = concat!(r" ", $name, ":")] fn shrink_end(&self, end: $crate::python::utils::PyTime) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.shrink_end(end) } @@ -196,6 +196,8 @@ macro_rules! impl_timeops { /// start (TimeInput): the new start time for the window /// end (TimeInput): the new end time for the window /// + /// Returns: + #[doc = concat!(r" ", $name, ":")] fn shrink_window(&self, start: $crate::python::utils::PyTime, end: $crate::python::utils::PyTime) -> <$base_type as TimeOps<'static>>::WindowedViewType { self.$field.shrink_window(start, end) } From 49c3962a97f341192faeb5320768267b20e04127 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 10 Jan 2025 14:39:53 +0100 Subject: [PATCH 22/29] add tests and fix more docs --- python/python/raphtory/__init__.pyi | 363 ++++---- .../python/raphtory/node_state/__init__.pyi | 791 +++++++++++------- python/tests/test_graphdb/test_node_state.py | 30 + raphtory/src/db/api/state/group_by.rs | 76 +- raphtory/src/lib.rs | 4 +- raphtory/src/python/graph/node.rs | 2 +- .../src/python/graph/node_state/group_by.rs | 54 +- raphtory/src/python/graph/node_state/mod.rs | 32 +- .../src/python/graph/node_state/node_state.rs | 31 - 9 files changed, 827 insertions(+), 556 deletions(-) diff --git a/python/python/raphtory/__init__.pyi b/python/python/raphtory/__init__.pyi index 03fab964ec..479515babb 100644 --- a/python/python/raphtory/__init__.pyi +++ b/python/python/raphtory/__init__.pyi @@ -41,7 +41,7 @@ class GraphView(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> GraphView: """ Create a view of the GraphView including all events after `start` (exclusive). @@ -49,10 +49,10 @@ class GraphView(object): start (TimeInput): The start time of the window. Returns: - GraphView + GraphView: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> GraphView: """ Create a view of the GraphView including all events at `time`. @@ -60,10 +60,10 @@ class GraphView(object): time (TimeInput): The time of the window. Returns: - GraphView + GraphView: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> GraphView: """ Create a view of the GraphView including all events before `end` (exclusive). @@ -71,7 +71,7 @@ class GraphView(object): end (TimeInput): The end time of the window. Returns: - GraphView + GraphView: """ def cache_view(self) -> GraphView: @@ -125,7 +125,7 @@ class GraphView(object): """ @property - def earliest_time(self): + def earliest_time(self) -> Optional[int]: """ Timestamp of earliest activity in the graph @@ -146,7 +146,7 @@ class GraphView(object): """ @property - def edges(self): + def edges(self) -> Edges: """ Gets all edges in the graph @@ -155,7 +155,7 @@ class GraphView(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this GraphView is valid. @@ -164,12 +164,12 @@ class GraphView(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this GraphView is valid Returns: - Optional[Datetime]: The latest datetime that this GraphView is valid or None if the GraphView is valid for all times. + Optional[datetime]: The latest datetime that this GraphView is valid or None if the GraphView is valid for all times. """ def exclude_layer(self, name: str) -> GraphView: @@ -306,7 +306,7 @@ class GraphView(object): bool: true if the graph contains the specified edge, false otherwise """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if GraphView has the layer `"name"` @@ -314,7 +314,7 @@ class GraphView(object): name (str): the name of the layer to check Returns: - bool + bool: """ def has_node(self, id: InputNode) -> bool: @@ -338,12 +338,12 @@ class GraphView(object): GraphIndex - Returns a GraphIndex """ - def latest(self): + def latest(self) -> GraphView: """ Create a view of the GraphView including all events at the latest time. Returns: - GraphView + GraphView: """ @property @@ -356,7 +356,7 @@ class GraphView(object): """ @property - def latest_time(self): + def latest_time(self) -> Optional[int]: """ Timestamp of latest activity in the graph @@ -408,7 +408,7 @@ class GraphView(object): """ @property - def nodes(self): + def nodes(self) -> Nodes: """ Gets the nodes in the graph @@ -417,7 +417,7 @@ class GraphView(object): """ @property - def properties(self): + def properties(self) -> Properties: """ Get all graph properties @@ -441,17 +441,17 @@ class GraphView(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> GraphView: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - GraphView + GraphView: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> GraphView: """ Set the start of the window to the larger of `start` and `self.start()` @@ -459,10 +459,10 @@ class GraphView(object): start (TimeInput): the new start time of the window Returns: - GraphView + GraphView: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> GraphView: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -470,9 +470,11 @@ class GraphView(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + GraphView: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> GraphView: """ Create a view of the GraphView including all events that have not been explicitly deleted at `time`. @@ -482,21 +484,21 @@ class GraphView(object): time (TimeInput): The time of the window. Returns: - GraphView + GraphView: """ - def snapshot_latest(self): + def snapshot_latest(self) -> GraphView: """ Create a view of the GraphView including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - GraphView + GraphView: """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this GraphView @@ -505,12 +507,12 @@ class GraphView(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this GraphView is valid Returns: - Optional[Datetime]: The earliest datetime that this GraphView is valid or None if the GraphView is valid for all times. + Optional[datetime]: The earliest datetime that this GraphView is valid or None if the GraphView is valid for all times. """ def subgraph(self, nodes: list[InputNode]) -> GraphView: @@ -646,7 +648,7 @@ class GraphView(object): VectorisedGraph: A VectorisedGraph with all the documents/embeddings computed and with an initial empty selection """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window(self, start: TimeInput | None, end: TimeInput | None) -> GraphView: """ Create a view of the GraphView including all events between `start` (inclusive) and `end` (exclusive) @@ -655,16 +657,16 @@ class GraphView(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r GraphView + GraphView: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this GraphView Returns: - Optional[int] + Optional[int]: """ class Graph(GraphView): @@ -2074,7 +2076,7 @@ class Node(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> Node: """ Create a view of the Node including all events after `start` (exclusive). @@ -2082,10 +2084,10 @@ class Node(object): start (TimeInput): The start time of the window. Returns: - Node + Node: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> Node: """ Create a view of the Node including all events at `time`. @@ -2093,10 +2095,10 @@ class Node(object): time (TimeInput): The time of the window. Returns: - Node + Node: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> Node: """ Create a view of the Node including all events before `end` (exclusive). @@ -2104,7 +2106,7 @@ class Node(object): end (TimeInput): The end time of the window. Returns: - Node + Node: """ def default_layer(self) -> Node: @@ -2132,7 +2134,7 @@ class Node(object): """ @property - def earliest_time(self): + def earliest_time(self) -> int: """ Returns the earliest time that the node exists. @@ -2151,7 +2153,7 @@ class Node(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this Node is valid. @@ -2160,12 +2162,12 @@ class Node(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this Node is valid Returns: - Optional[Datetime]: The latest datetime that this Node is valid or None if the Node is valid for all times. + Optional[datetime]: The latest datetime that this Node is valid or None if the Node is valid for all times. """ def exclude_layer(self, name: str) -> Node: @@ -2261,7 +2263,7 @@ class Node(object): Node: The filtered view """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if Node has the layer `"name"` @@ -2269,7 +2271,7 @@ class Node(object): name (str): the name of the layer to check Returns: - bool + bool: """ def history(self) -> List[int]: @@ -2290,7 +2292,7 @@ class Node(object): """ @property - def id(self): + def id(self) -> str | int: """ Returns the id of the node. This is a unique identifier for the node. @@ -2328,28 +2330,25 @@ class Node(object): """ def is_active(self): ... - def latest(self): + def latest(self) -> Node: """ Create a view of the Node including all events at the latest time. Returns: - Node + Node: """ @property - def latest_date_time(self): + def latest_date_time(self) -> datetime: """ Returns the latest datetime that the node exists. - Arguments: - None - Returns: - Datetime: The latest datetime that the node exists as a Datetime. + datetime: The latest datetime that the node exists as a Datetime. """ @property - def latest_time(self): + def latest_time(self) -> int: """ Returns the latest time that the node exists. @@ -2382,7 +2381,7 @@ class Node(object): """ @property - def name(self): + def name(self) -> str: """ Returns the name of the node. @@ -2433,7 +2432,7 @@ class Node(object): """ @property - def properties(self): + def properties(self) -> Properties: """ The properties of the node @@ -2456,17 +2455,17 @@ class Node(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> Node: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - Node + Node: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> Node: """ Set the start of the window to the larger of `start` and `self.start()` @@ -2474,10 +2473,10 @@ class Node(object): start (TimeInput): the new start time of the window Returns: - Node + Node: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> Node: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -2485,9 +2484,11 @@ class Node(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + Node: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> Node: """ Create a view of the Node including all events that have not been explicitly deleted at `time`. @@ -2497,21 +2498,21 @@ class Node(object): time (TimeInput): The time of the window. Returns: - Node + Node: """ - def snapshot_latest(self): + def snapshot_latest(self) -> Node: """ Create a view of the Node including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Node + Node: """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this Node @@ -2520,12 +2521,12 @@ class Node(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this Node is valid Returns: - Optional[Datetime]: The earliest datetime that this Node is valid or None if the Node is valid for all times. + Optional[datetime]: The earliest datetime that this Node is valid or None if the Node is valid for all times. """ def valid_layers(self, names: list[str]) -> Node: @@ -2540,7 +2541,7 @@ class Node(object): Node: The layered view """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window(self, start: TimeInput | None, end: TimeInput | None) -> Node: """ Create a view of the Node including all events between `start` (inclusive) and `end` (exclusive) @@ -2549,16 +2550,16 @@ class Node(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r Node + Node: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this Node Returns: - Optional[int] + Optional[int]: """ class Nodes(object): @@ -2597,7 +2598,7 @@ class Nodes(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> Nodes: """ Create a view of the Nodes including all events after `start` (exclusive). @@ -2605,10 +2606,10 @@ class Nodes(object): start (TimeInput): The start time of the window. Returns: - Nodes + Nodes: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> Nodes: """ Create a view of the Nodes including all events at `time`. @@ -2616,10 +2617,10 @@ class Nodes(object): time (TimeInput): The time of the window. Returns: - Nodes + Nodes: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> Nodes: """ Create a view of the Nodes including all events before `end` (exclusive). @@ -2627,7 +2628,7 @@ class Nodes(object): end (TimeInput): The end time of the window. Returns: - Nodes + Nodes: """ def collect(self) -> list[Node]: @@ -2677,7 +2678,7 @@ class Nodes(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this Nodes is valid. @@ -2686,12 +2687,12 @@ class Nodes(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this Nodes is valid Returns: - Optional[Datetime]: The latest datetime that this Nodes is valid or None if the Nodes is valid for all times. + Optional[datetime]: The latest datetime that this Nodes is valid or None if the Nodes is valid for all times. """ def exclude_layer(self, name: str) -> Nodes: @@ -2787,7 +2788,7 @@ class Nodes(object): Nodes: The filtered view """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if Nodes has the layer `"name"` @@ -2795,7 +2796,7 @@ class Nodes(object): name (str): the name of the layer to check Returns: - bool + bool: """ def history(self): @@ -2848,12 +2849,12 @@ class Nodes(object): An iterator over the neighbours of this node that point into this node. """ - def latest(self): + def latest(self) -> Nodes: """ Create a view of the Nodes including all events at the latest time. Returns: - Nodes + Nodes: """ @property @@ -2963,17 +2964,17 @@ class Nodes(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> Nodes: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - Nodes + Nodes: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> Nodes: """ Set the start of the window to the larger of `start` and `self.start()` @@ -2981,10 +2982,10 @@ class Nodes(object): start (TimeInput): the new start time of the window Returns: - Nodes + Nodes: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> Nodes: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -2992,9 +2993,11 @@ class Nodes(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + Nodes: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> Nodes: """ Create a view of the Nodes including all events that have not been explicitly deleted at `time`. @@ -3004,21 +3007,21 @@ class Nodes(object): time (TimeInput): The time of the window. Returns: - Nodes + Nodes: """ - def snapshot_latest(self): + def snapshot_latest(self) -> Nodes: """ Create a view of the Nodes including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Nodes + Nodes: """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this Nodes @@ -3027,12 +3030,12 @@ class Nodes(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this Nodes is valid Returns: - Optional[Datetime]: The earliest datetime that this Nodes is valid or None if the Nodes is valid for all times. + Optional[datetime]: The earliest datetime that this Nodes is valid or None if the Nodes is valid for all times. """ def to_df( @@ -3067,7 +3070,7 @@ class Nodes(object): Nodes: The layered view """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window(self, start: TimeInput | None, end: TimeInput | None) -> Nodes: """ Create a view of the Nodes including all events between `start` (inclusive) and `end` (exclusive) @@ -3076,16 +3079,16 @@ class Nodes(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r Nodes + Nodes: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this Nodes Returns: - Optional[int] + Optional[int]: """ class MutableNode(Node): @@ -3179,7 +3182,7 @@ class Edge(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> Edge: """ Create a view of the Edge including all events after `start` (exclusive). @@ -3187,10 +3190,10 @@ class Edge(object): start (TimeInput): The start time of the window. Returns: - Edge + Edge: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> Edge: """ Create a view of the Edge including all events at `time`. @@ -3198,10 +3201,10 @@ class Edge(object): time (TimeInput): The time of the window. Returns: - Edge + Edge: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> Edge: """ Create a view of the Edge including all events before `end` (exclusive). @@ -3209,7 +3212,7 @@ class Edge(object): end (TimeInput): The end time of the window. Returns: - Edge + Edge: """ @property @@ -3241,7 +3244,7 @@ class Edge(object): Returns a list of timestamps of when an edge is deleted Returns: - List[Datetime] + List[datetime] """ @property @@ -3249,16 +3252,16 @@ class Edge(object): """Returns the destination node of the edge.""" @property - def earliest_date_time(self): + def earliest_date_time(self) -> datetime: """ Gets of earliest datetime of an edge. Returns: - Datetime: the earliest datetime of an edge + datetime: the earliest datetime of an edge """ @property - def earliest_time(self): + def earliest_time(self) -> int: """ Gets the earliest time of an edge. @@ -3267,7 +3270,7 @@ class Edge(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this Edge is valid. @@ -3276,12 +3279,12 @@ class Edge(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this Edge is valid Returns: - Optional[Datetime]: The latest datetime that this Edge is valid or None if the Edge is valid for all times. + Optional[datetime]: The latest datetime that this Edge is valid or None if the Edge is valid for all times. """ def exclude_layer(self, name: str) -> Edge: @@ -3347,7 +3350,7 @@ class Edge(object): def explode_layers(self): """Explode layers returns an edge object for each layer within the original edge. These new edge object contains only updates from respective layers.""" - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if Edge has the layer `"name"` @@ -3355,7 +3358,7 @@ class Edge(object): name (str): the name of the layer to check Returns: - bool + bool: """ def history(self) -> List[int]: @@ -3381,7 +3384,7 @@ class Edge(object): Returns a list of timestamps of when an edge is added or change to an edge is made. Returns: - List[Datetime] + List[datetime] """ @@ -3389,53 +3392,53 @@ class Edge(object): def id(self): """The id of the edge.""" - def is_active(self): + def is_active(self) -> bool: """ Check if the edge is currently active (i.e., has at least one update within this period) Returns: - bool + bool: """ - def is_deleted(self): + def is_deleted(self) -> bool: """ Check if the edge is currently deleted Returns: - bool + bool: """ - def is_self_loop(self): + def is_self_loop(self) -> bool: """ Check if the edge is on the same node Returns: - bool + bool: """ - def is_valid(self): + def is_valid(self) -> bool: """ Check if the edge is currently valid (i.e., not deleted) Returns: - bool + bool: """ - def latest(self): + def latest(self) -> Edge: """ Create a view of the Edge including all events at the latest time. Returns: - Edge + Edge: """ @property - def latest_date_time(self): + def latest_date_time(self) -> datetime: """ Gets of latest datetime of an edge. Returns: - Datetime: the latest datetime of an edge + datetime: the latest datetime of an edge """ @property - def latest_time(self): + def latest_time(self) -> int: """ Gets the latest time of an edge. @@ -3456,7 +3459,7 @@ class Edge(object): """ @property - def layer_name(self): + def layer_name(self) -> str: """ Gets the name of the layer this edge belongs to - assuming it only belongs to one layer @@ -3513,17 +3516,17 @@ class Edge(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> Edge: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - Edge + Edge: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> Edge: """ Set the start of the window to the larger of `start` and `self.start()` @@ -3531,10 +3534,10 @@ class Edge(object): start (TimeInput): the new start time of the window Returns: - Edge + Edge: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> Edge: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -3542,9 +3545,11 @@ class Edge(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + Edge: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> Edge: """ Create a view of the Edge including all events that have not been explicitly deleted at `time`. @@ -3554,17 +3559,17 @@ class Edge(object): time (TimeInput): The time of the window. Returns: - Edge + Edge: """ - def snapshot_latest(self): + def snapshot_latest(self) -> Edge: """ Create a view of the Edge including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Edge + Edge: """ @property @@ -3572,7 +3577,7 @@ class Edge(object): """Returns the source node of the edge.""" @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this Edge @@ -3581,16 +3586,16 @@ class Edge(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this Edge is valid Returns: - Optional[Datetime]: The earliest datetime that this Edge is valid or None if the Edge is valid for all times. + Optional[datetime]: The earliest datetime that this Edge is valid or None if the Edge is valid for all times. """ @property - def time(self): + def time(self) -> int: """ Gets the time of an exploded edge. @@ -3610,7 +3615,7 @@ class Edge(object): Edge: The layered view """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window(self, start: TimeInput | None, end: TimeInput | None) -> Edge: """ Create a view of the Edge including all events between `start` (inclusive) and `end` (exclusive) @@ -3619,16 +3624,16 @@ class Edge(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r Edge + Edge: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this Edge Returns: - Optional[int] + Optional[int]: """ class Edges(object): @@ -3646,7 +3651,7 @@ class Edges(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> Edges: """ Create a view of the Edges including all events after `start` (exclusive). @@ -3654,10 +3659,10 @@ class Edges(object): start (TimeInput): The start time of the window. Returns: - Edges + Edges: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> Edges: """ Create a view of the Edges including all events at `time`. @@ -3665,10 +3670,10 @@ class Edges(object): time (TimeInput): The time of the window. Returns: - Edges + Edges: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> Edges: """ Create a view of the Edges including all events before `end` (exclusive). @@ -3676,7 +3681,7 @@ class Edges(object): end (TimeInput): The end time of the window. Returns: - Edges + Edges: """ def collect(self) -> list[Edge]: @@ -3745,7 +3750,7 @@ class Edges(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this Edges is valid. @@ -3754,12 +3759,12 @@ class Edges(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this Edges is valid Returns: - Optional[Datetime]: The latest datetime that this Edges is valid or None if the Edges is valid for all times. + Optional[datetime]: The latest datetime that this Edges is valid or None if the Edges is valid for all times. """ def exclude_layer(self, name: str) -> Edges: @@ -3825,7 +3830,7 @@ class Edges(object): def explode_layers(self): """Explode layers returns an edge object for each layer within the original edge. These new edge object contains only updates from respective layers.""" - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if Edges has the layer `"name"` @@ -3833,7 +3838,7 @@ class Edges(object): name (str): the name of the layer to check Returns: - bool + bool: """ def history(self): @@ -3869,12 +3874,12 @@ class Edges(object): def is_valid(self): """Check if the edges are valid (i.e. not deleted)""" - def latest(self): + def latest(self) -> Edges: """ Create a view of the Edges including all events at the latest time. Returns: - Edges + Edges: """ @property @@ -3960,17 +3965,17 @@ class Edges(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> Edges: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - Edges + Edges: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> Edges: """ Set the start of the window to the larger of `start` and `self.start()` @@ -3978,10 +3983,10 @@ class Edges(object): start (TimeInput): the new start time of the window Returns: - Edges + Edges: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> Edges: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -3989,9 +3994,11 @@ class Edges(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + Edges: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> Edges: """ Create a view of the Edges including all events that have not been explicitly deleted at `time`. @@ -4001,17 +4008,17 @@ class Edges(object): time (TimeInput): The time of the window. Returns: - Edges + Edges: """ - def snapshot_latest(self): + def snapshot_latest(self) -> Edges: """ Create a view of the Edges including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - Edges + Edges: """ @property @@ -4019,7 +4026,7 @@ class Edges(object): """Returns the source node of the edge.""" @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this Edges @@ -4028,12 +4035,12 @@ class Edges(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this Edges is valid Returns: - Optional[Datetime]: The earliest datetime that this Edges is valid or None if the Edges is valid for all times. + Optional[datetime]: The earliest datetime that this Edges is valid or None if the Edges is valid for all times. """ @property @@ -4082,7 +4089,7 @@ class Edges(object): Edges: The layered view """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window(self, start: TimeInput | None, end: TimeInput | None) -> Edges: """ Create a view of the Edges including all events between `start` (inclusive) and `end` (exclusive) @@ -4091,16 +4098,16 @@ class Edges(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r Edges + Edges: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this Edges Returns: - Optional[int] + Optional[int]: """ class MutableEdge(Edge): diff --git a/python/python/raphtory/node_state/__init__.pyi b/python/python/raphtory/node_state/__init__.pyi index 2e2a7ebc95..378e9dc4c9 100644 --- a/python/python/raphtory/node_state/__init__.pyi +++ b/python/python/raphtory/node_state/__init__.pyi @@ -17,6 +17,49 @@ from raphtory.typing import * from datetime import datetime from pandas import DataFrame +class NodeGroups(object): + def __bool__(self): + """True if self else False""" + + def __getitem__(self, key): + """Return self[key].""" + + def __iter__(self): + """Implement iter(self).""" + + def __len__(self): + """Return len(self).""" + + def group(self, index: int) -> Tuple[Any, Nodes]: + """ + Get group nodes and value + + Arguments: + index (int): the group index + + Returns: + Tuple[Any, Nodes]: Nodes and corresponding value + """ + + def group_subgraph(self, index: int) -> Tuple[Any, GraphView]: + """ + Get group as subgraph + + Arguments: + index (int): the group index + + Returns: + Tuple[Any, GraphView]: The group as a subgraph and corresponding value + """ + + def iter_subgraphs(self) -> Iterator[Tuple[Any, GraphView]]: + """ + Iterate over group subgraphs + + Returns: + Iterator[Tuple[Any, GraphView]]: Iterator over subgraphs with corresponding value + """ + class DegreeView(object): """A lazy view over node values""" @@ -50,7 +93,7 @@ class DegreeView(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> DegreeView: """ Create a view of the DegreeView including all events after `start` (exclusive). @@ -58,10 +101,10 @@ class DegreeView(object): start (TimeInput): The start time of the window. Returns: - DegreeView + DegreeView: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> DegreeView: """ Create a view of the DegreeView including all events at `time`. @@ -69,10 +112,10 @@ class DegreeView(object): time (TimeInput): The time of the window. Returns: - DegreeView + DegreeView: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> DegreeView: """ Create a view of the DegreeView including all events before `end` (exclusive). @@ -80,7 +123,7 @@ class DegreeView(object): end (TimeInput): The end time of the window. Returns: - DegreeView + DegreeView: """ def bottom_k(self, k: int) -> NodeStateUsize: @@ -94,20 +137,20 @@ class DegreeView(object): NodeStateUsize: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[int]: """ Compute all values and return the result as a list - Returns + Returns: list[int]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateUsize: """ Compute all values and return the result as a node view Returns: - NodeStateUsize + NodeStateUsize: the computed `NodeState` """ def default_layer(self) -> DegreeView: @@ -118,7 +161,7 @@ class DegreeView(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this DegreeView is valid. @@ -127,12 +170,12 @@ class DegreeView(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this DegreeView is valid Returns: - Optional[Datetime]: The latest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. + Optional[datetime]: The latest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. """ def exclude_layer(self, name: str) -> DegreeView: @@ -200,7 +243,7 @@ class DegreeView(object): NodeGroups: The grouped nodes """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if DegreeView has the layer `"name"` @@ -208,21 +251,23 @@ class DegreeView(object): name (str): the name of the layer to check Returns: - bool + bool: """ - def items(self): + def items(self) -> Iterator[Tuple[Node, int]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, int]]: Iterator over items """ - def latest(self): + def latest(self) -> DegreeView: """ Create a view of the DegreeView including all events at the latest time. Returns: - DegreeView + DegreeView: """ def layer(self, name: str) -> DegreeView: @@ -273,12 +318,12 @@ class DegreeView(object): float: mean value """ - def median(self): + def median(self) -> Optional[int]: """ Return the median value Returns: - Optional[int] + Optional[int]: """ def median_item(self) -> Optional[Tuple[Node, int]]: @@ -328,17 +373,17 @@ class DegreeView(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> DegreeView: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - DegreeView + DegreeView: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> DegreeView: """ Set the start of the window to the larger of `start` and `self.start()` @@ -346,10 +391,10 @@ class DegreeView(object): start (TimeInput): the new start time of the window Returns: - DegreeView + DegreeView: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> DegreeView: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -357,9 +402,11 @@ class DegreeView(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + DegreeView: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> DegreeView: """ Create a view of the DegreeView including all events that have not been explicitly deleted at `time`. @@ -369,17 +416,17 @@ class DegreeView(object): time (TimeInput): The time of the window. Returns: - DegreeView + DegreeView: """ - def snapshot_latest(self): + def snapshot_latest(self) -> DegreeView: """ Create a view of the DegreeView including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - DegreeView + DegreeView: """ def sorted(self, reverse: bool = False) -> NodeStateUsize: @@ -402,7 +449,7 @@ class DegreeView(object): """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this DegreeView @@ -411,12 +458,12 @@ class DegreeView(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this DegreeView is valid Returns: - Optional[Datetime]: The earliest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. + Optional[datetime]: The earliest datetime that this DegreeView is valid or None if the DegreeView is valid for all times. """ def sum(self) -> int: @@ -450,13 +497,15 @@ class DegreeView(object): DegreeView: The layered view """ - def values(self): + def values(self) -> Iterator[int]: """ + Iterate over values + Returns: Iterator[int]: Iterator over values """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window(self, start: TimeInput | None, end: TimeInput | None) -> DegreeView: """ Create a view of the DegreeView including all events between `start` (inclusive) and `end` (exclusive) @@ -465,16 +514,16 @@ class DegreeView(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r DegreeView + DegreeView: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this DegreeView Returns: - Optional[int] + Optional[int]: """ class NodeStateUsize(object): @@ -527,8 +576,10 @@ class NodeStateUsize(object): NodeGroups: The grouped nodes """ - def items(self): + def items(self) -> Iterator[Tuple[Node, int]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, int]]: Iterator over items """ @@ -557,12 +608,12 @@ class NodeStateUsize(object): float: mean value """ - def median(self): + def median(self) -> Optional[int]: """ Return the median value Returns: - Optional[int] + Optional[int]: """ def median_item(self) -> Optional[Tuple[Node, int]]: @@ -635,8 +686,10 @@ class NodeStateUsize(object): NodeStateUsize: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[int]: """ + Iterate over values + Returns: Iterator[int]: Iterator over values """ @@ -683,8 +736,10 @@ class NodeStateU64(object): NodeStateU64: The k smallest values as a node state """ - def items(self): + def items(self) -> Iterator[Tuple[Node, int]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, int]]: Iterator over items """ @@ -713,12 +768,12 @@ class NodeStateU64(object): float: mean value """ - def median(self): + def median(self) -> Optional[int]: """ Return the median value Returns: - Optional[int] + Optional[int]: """ def median_item(self) -> Optional[Tuple[Node, int]]: @@ -791,8 +846,10 @@ class NodeStateU64(object): NodeStateU64: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[int]: """ + Iterate over values + Returns: Iterator[int]: Iterator over values """ @@ -847,8 +904,10 @@ class NodeStateOptionI64(object): NodeGroups: The grouped nodes """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[int]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[int]]]: Iterator over items """ @@ -869,12 +928,12 @@ class NodeStateOptionI64(object): Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[int]]: """ Return the median value Returns: - Optional[Optional[int]] + Optional[Optional[int]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[int]]]: @@ -939,8 +998,10 @@ class NodeStateOptionI64(object): NodeStateOptionI64: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[Optional[int]]: """ + Iterate over values + Returns: Iterator[Optional[int]]: Iterator over values """ @@ -989,24 +1050,26 @@ class IdView(object): NodeStateGID: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[GID]: """ Compute all values and return the result as a list - Returns + Returns: list[GID]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateGID: """ Compute all values and return the result as a node view Returns: - NodeStateGID + NodeStateGID: the computed `NodeState` """ - def items(self): + def items(self) -> Iterator[Tuple[Node, GID]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, GID]]: Iterator over items """ @@ -1027,12 +1090,12 @@ class IdView(object): Optional[Tuple[Node, GID]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[GID]: """ Return the median value Returns: - Optional[GID] + Optional[GID]: """ def median_item(self) -> Optional[Tuple[Node, GID]]: @@ -1097,8 +1160,10 @@ class IdView(object): NodeStateGID: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[GID]: """ + Iterate over values + Returns: Iterator[GID]: Iterator over values """ @@ -1145,8 +1210,10 @@ class NodeStateGID(object): NodeStateGID: The k smallest values as a node state """ - def items(self): + def items(self) -> Iterator[Tuple[Node, GID]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, GID]]: Iterator over items """ @@ -1167,12 +1234,12 @@ class NodeStateGID(object): Optional[Tuple[Node, GID]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[GID]: """ Return the median value Returns: - Optional[GID] + Optional[GID]: """ def median_item(self) -> Optional[Tuple[Node, GID]]: @@ -1237,8 +1304,10 @@ class NodeStateGID(object): NodeStateGID: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[GID]: """ + Iterate over values + Returns: Iterator[GID]: Iterator over values """ @@ -1276,7 +1345,7 @@ class EarliestTimeView(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> EarliestTimeView: """ Create a view of the EarliestTimeView including all events after `start` (exclusive). @@ -1284,10 +1353,10 @@ class EarliestTimeView(object): start (TimeInput): The start time of the window. Returns: - EarliestTimeView + EarliestTimeView: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> EarliestTimeView: """ Create a view of the EarliestTimeView including all events at `time`. @@ -1295,10 +1364,10 @@ class EarliestTimeView(object): time (TimeInput): The time of the window. Returns: - EarliestTimeView + EarliestTimeView: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> EarliestTimeView: """ Create a view of the EarliestTimeView including all events before `end` (exclusive). @@ -1306,7 +1375,7 @@ class EarliestTimeView(object): end (TimeInput): The end time of the window. Returns: - EarliestTimeView + EarliestTimeView: """ def bottom_k(self, k: int) -> NodeStateOptionI64: @@ -1320,20 +1389,20 @@ class EarliestTimeView(object): NodeStateOptionI64: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[Optional[int]]: """ Compute all values and return the result as a list - Returns + Returns: list[Optional[int]]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateOptionI64: """ Compute all values and return the result as a node view Returns: - NodeStateOptionI64 + NodeStateOptionI64: the computed `NodeState` """ def default_layer(self) -> EarliestTimeView: @@ -1344,7 +1413,7 @@ class EarliestTimeView(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this EarliestTimeView is valid. @@ -1353,12 +1422,12 @@ class EarliestTimeView(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this EarliestTimeView is valid Returns: - Optional[Datetime]: The latest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + Optional[datetime]: The latest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ def exclude_layer(self, name: str) -> EarliestTimeView: @@ -1426,7 +1495,7 @@ class EarliestTimeView(object): NodeGroups: The grouped nodes """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if EarliestTimeView has the layer `"name"` @@ -1434,21 +1503,23 @@ class EarliestTimeView(object): name (str): the name of the layer to check Returns: - bool + bool: """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[int]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[int]]]: Iterator over items """ - def latest(self): + def latest(self) -> EarliestTimeView: """ Create a view of the EarliestTimeView including all events at the latest time. Returns: - EarliestTimeView + EarliestTimeView: """ def layer(self, name: str) -> EarliestTimeView: @@ -1491,12 +1562,12 @@ class EarliestTimeView(object): Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[int]]: """ Return the median value Returns: - Optional[Optional[int]] + Optional[Optional[int]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[int]]]: @@ -1546,17 +1617,17 @@ class EarliestTimeView(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> EarliestTimeView: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - EarliestTimeView + EarliestTimeView: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> EarliestTimeView: """ Set the start of the window to the larger of `start` and `self.start()` @@ -1564,10 +1635,10 @@ class EarliestTimeView(object): start (TimeInput): the new start time of the window Returns: - EarliestTimeView + EarliestTimeView: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> EarliestTimeView: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -1575,9 +1646,11 @@ class EarliestTimeView(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + EarliestTimeView: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> EarliestTimeView: """ Create a view of the EarliestTimeView including all events that have not been explicitly deleted at `time`. @@ -1587,17 +1660,17 @@ class EarliestTimeView(object): time (TimeInput): The time of the window. Returns: - EarliestTimeView + EarliestTimeView: """ - def snapshot_latest(self): + def snapshot_latest(self) -> EarliestTimeView: """ Create a view of the EarliestTimeView including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - EarliestTimeView + EarliestTimeView: """ def sorted(self, reverse: bool = False) -> NodeStateOptionI64: @@ -1620,7 +1693,7 @@ class EarliestTimeView(object): """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this EarliestTimeView @@ -1629,12 +1702,12 @@ class EarliestTimeView(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this EarliestTimeView is valid Returns: - Optional[Datetime]: The earliest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. + Optional[datetime]: The earliest datetime that this EarliestTimeView is valid or None if the EarliestTimeView is valid for all times. """ def top_k(self, k: int) -> NodeStateOptionI64: @@ -1660,13 +1733,17 @@ class EarliestTimeView(object): EarliestTimeView: The layered view """ - def values(self): + def values(self) -> Iterator[Optional[int]]: """ + Iterate over values + Returns: Iterator[Optional[int]]: Iterator over values """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window( + self, start: TimeInput | None, end: TimeInput | None + ) -> EarliestTimeView: """ Create a view of the EarliestTimeView including all events between `start` (inclusive) and `end` (exclusive) @@ -1675,16 +1752,16 @@ class EarliestTimeView(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r EarliestTimeView + EarliestTimeView: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this EarliestTimeView Returns: - Optional[int] + Optional[int]: """ class LatestTimeView(object): @@ -1720,7 +1797,7 @@ class LatestTimeView(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> LatestTimeView: """ Create a view of the LatestTimeView including all events after `start` (exclusive). @@ -1728,10 +1805,10 @@ class LatestTimeView(object): start (TimeInput): The start time of the window. Returns: - LatestTimeView + LatestTimeView: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> LatestTimeView: """ Create a view of the LatestTimeView including all events at `time`. @@ -1739,10 +1816,10 @@ class LatestTimeView(object): time (TimeInput): The time of the window. Returns: - LatestTimeView + LatestTimeView: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> LatestTimeView: """ Create a view of the LatestTimeView including all events before `end` (exclusive). @@ -1750,7 +1827,7 @@ class LatestTimeView(object): end (TimeInput): The end time of the window. Returns: - LatestTimeView + LatestTimeView: """ def bottom_k(self, k: int) -> NodeStateOptionI64: @@ -1764,20 +1841,20 @@ class LatestTimeView(object): NodeStateOptionI64: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[Optional[int]]: """ Compute all values and return the result as a list - Returns + Returns: list[Optional[int]]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateOptionI64: """ Compute all values and return the result as a node view Returns: - NodeStateOptionI64 + NodeStateOptionI64: the computed `NodeState` """ def default_layer(self) -> LatestTimeView: @@ -1788,7 +1865,7 @@ class LatestTimeView(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this LatestTimeView is valid. @@ -1797,12 +1874,12 @@ class LatestTimeView(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this LatestTimeView is valid Returns: - Optional[Datetime]: The latest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + Optional[datetime]: The latest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. """ def exclude_layer(self, name: str) -> LatestTimeView: @@ -1870,7 +1947,7 @@ class LatestTimeView(object): NodeGroups: The grouped nodes """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if LatestTimeView has the layer `"name"` @@ -1878,21 +1955,23 @@ class LatestTimeView(object): name (str): the name of the layer to check Returns: - bool + bool: """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[int]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[int]]]: Iterator over items """ - def latest(self): + def latest(self) -> LatestTimeView: """ Create a view of the LatestTimeView including all events at the latest time. Returns: - LatestTimeView + LatestTimeView: """ def layer(self, name: str) -> LatestTimeView: @@ -1935,12 +2014,12 @@ class LatestTimeView(object): Optional[Tuple[Node, Optional[int]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[int]]: """ Return the median value Returns: - Optional[Optional[int]] + Optional[Optional[int]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[int]]]: @@ -1990,17 +2069,17 @@ class LatestTimeView(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> LatestTimeView: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - LatestTimeView + LatestTimeView: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> LatestTimeView: """ Set the start of the window to the larger of `start` and `self.start()` @@ -2008,10 +2087,10 @@ class LatestTimeView(object): start (TimeInput): the new start time of the window Returns: - LatestTimeView + LatestTimeView: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> LatestTimeView: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -2019,9 +2098,11 @@ class LatestTimeView(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + LatestTimeView: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> LatestTimeView: """ Create a view of the LatestTimeView including all events that have not been explicitly deleted at `time`. @@ -2031,17 +2112,17 @@ class LatestTimeView(object): time (TimeInput): The time of the window. Returns: - LatestTimeView + LatestTimeView: """ - def snapshot_latest(self): + def snapshot_latest(self) -> LatestTimeView: """ Create a view of the LatestTimeView including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - LatestTimeView + LatestTimeView: """ def sorted(self, reverse: bool = False) -> NodeStateOptionI64: @@ -2064,7 +2145,7 @@ class LatestTimeView(object): """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this LatestTimeView @@ -2073,12 +2154,12 @@ class LatestTimeView(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this LatestTimeView is valid Returns: - Optional[Datetime]: The earliest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. + Optional[datetime]: The earliest datetime that this LatestTimeView is valid or None if the LatestTimeView is valid for all times. """ def top_k(self, k: int) -> NodeStateOptionI64: @@ -2104,13 +2185,15 @@ class LatestTimeView(object): LatestTimeView: The layered view """ - def values(self): + def values(self) -> Iterator[Optional[int]]: """ + Iterate over values + Returns: Iterator[Optional[int]]: Iterator over values """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window(self, start: TimeInput | None, end: TimeInput | None) -> LatestTimeView: """ Create a view of the LatestTimeView including all events between `start` (inclusive) and `end` (exclusive) @@ -2119,16 +2202,16 @@ class LatestTimeView(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r LatestTimeView + LatestTimeView: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this LatestTimeView Returns: - Optional[int] + Optional[int]: """ class NameView(object): @@ -2175,20 +2258,20 @@ class NameView(object): NodeStateString: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[str]: """ Compute all values and return the result as a list - Returns + Returns: list[str]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateString: """ Compute all values and return the result as a node view Returns: - NodeStateString + NodeStateString: the computed `NodeState` """ def groups(self) -> NodeGroups: @@ -2199,8 +2282,10 @@ class NameView(object): NodeGroups: The grouped nodes """ - def items(self): + def items(self) -> Iterator[Tuple[Node, str]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, str]]: Iterator over items """ @@ -2221,12 +2306,12 @@ class NameView(object): Optional[Tuple[Node, str]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[str]: """ Return the median value Returns: - Optional[str] + Optional[str]: """ def median_item(self) -> Optional[Tuple[Node, str]]: @@ -2291,8 +2376,10 @@ class NameView(object): NodeStateString: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[str]: """ + Iterate over values + Returns: Iterator[str]: Iterator over values """ @@ -2347,8 +2434,10 @@ class NodeStateString(object): NodeGroups: The grouped nodes """ - def items(self): + def items(self) -> Iterator[Tuple[Node, str]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, str]]: Iterator over items """ @@ -2369,12 +2458,12 @@ class NodeStateString(object): Optional[Tuple[Node, str]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[str]: """ Return the median value Returns: - Optional[str] + Optional[str]: """ def median_item(self) -> Optional[Tuple[Node, str]]: @@ -2439,8 +2528,10 @@ class NodeStateString(object): NodeStateString: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[str]: """ + Iterate over values + Returns: Iterator[str]: Iterator over values """ @@ -2478,7 +2569,7 @@ class EarliestDateTimeView(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> EarliestDateTimeView: """ Create a view of the EarliestDateTimeView including all events after `start` (exclusive). @@ -2486,10 +2577,10 @@ class EarliestDateTimeView(object): start (TimeInput): The start time of the window. Returns: - EarliestDateTimeView + EarliestDateTimeView: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> EarliestDateTimeView: """ Create a view of the EarliestDateTimeView including all events at `time`. @@ -2497,10 +2588,10 @@ class EarliestDateTimeView(object): time (TimeInput): The time of the window. Returns: - EarliestDateTimeView + EarliestDateTimeView: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> EarliestDateTimeView: """ Create a view of the EarliestDateTimeView including all events before `end` (exclusive). @@ -2508,7 +2599,7 @@ class EarliestDateTimeView(object): end (TimeInput): The end time of the window. Returns: - EarliestDateTimeView + EarliestDateTimeView: """ def bottom_k(self, k: int) -> NodeStateOptionDateTime: @@ -2522,20 +2613,20 @@ class EarliestDateTimeView(object): NodeStateOptionDateTime: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[Optional[datetime]]: """ Compute all values and return the result as a list - Returns + Returns: list[Optional[datetime]]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateOptionDateTime: """ Compute all values and return the result as a node view Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: the computed `NodeState` """ def default_layer(self) -> EarliestDateTimeView: @@ -2546,7 +2637,7 @@ class EarliestDateTimeView(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this EarliestDateTimeView is valid. @@ -2555,12 +2646,12 @@ class EarliestDateTimeView(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this EarliestDateTimeView is valid Returns: - Optional[Datetime]: The latest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[datetime]: The latest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ def exclude_layer(self, name: str) -> EarliestDateTimeView: @@ -2628,7 +2719,7 @@ class EarliestDateTimeView(object): NodeGroups: The grouped nodes """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if EarliestDateTimeView has the layer `"name"` @@ -2636,21 +2727,23 @@ class EarliestDateTimeView(object): name (str): the name of the layer to check Returns: - bool + bool: """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[datetime]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[datetime]]]: Iterator over items """ - def latest(self): + def latest(self) -> EarliestDateTimeView: """ Create a view of the EarliestDateTimeView including all events at the latest time. Returns: - EarliestDateTimeView + EarliestDateTimeView: """ def layer(self, name: str) -> EarliestDateTimeView: @@ -2693,12 +2786,12 @@ class EarliestDateTimeView(object): Optional[Tuple[Node, Optional[datetime]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[datetime]]: """ Return the median value Returns: - Optional[Optional[datetime]] + Optional[Optional[datetime]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: @@ -2748,17 +2841,17 @@ class EarliestDateTimeView(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> EarliestDateTimeView: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - EarliestDateTimeView + EarliestDateTimeView: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> EarliestDateTimeView: """ Set the start of the window to the larger of `start` and `self.start()` @@ -2766,10 +2859,10 @@ class EarliestDateTimeView(object): start (TimeInput): the new start time of the window Returns: - EarliestDateTimeView + EarliestDateTimeView: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> EarliestDateTimeView: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -2777,9 +2870,11 @@ class EarliestDateTimeView(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + EarliestDateTimeView: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> EarliestDateTimeView: """ Create a view of the EarliestDateTimeView including all events that have not been explicitly deleted at `time`. @@ -2789,17 +2884,17 @@ class EarliestDateTimeView(object): time (TimeInput): The time of the window. Returns: - EarliestDateTimeView + EarliestDateTimeView: """ - def snapshot_latest(self): + def snapshot_latest(self) -> EarliestDateTimeView: """ Create a view of the EarliestDateTimeView including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - EarliestDateTimeView + EarliestDateTimeView: """ def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: @@ -2822,7 +2917,7 @@ class EarliestDateTimeView(object): """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this EarliestDateTimeView @@ -2831,12 +2926,12 @@ class EarliestDateTimeView(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this EarliestDateTimeView is valid Returns: - Optional[Datetime]: The earliest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. + Optional[datetime]: The earliest datetime that this EarliestDateTimeView is valid or None if the EarliestDateTimeView is valid for all times. """ def top_k(self, k: int) -> NodeStateOptionDateTime: @@ -2862,13 +2957,17 @@ class EarliestDateTimeView(object): EarliestDateTimeView: The layered view """ - def values(self): + def values(self) -> Iterator[Optional[datetime]]: """ + Iterate over values + Returns: Iterator[Optional[datetime]]: Iterator over values """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window( + self, start: TimeInput | None, end: TimeInput | None + ) -> EarliestDateTimeView: """ Create a view of the EarliestDateTimeView including all events between `start` (inclusive) and `end` (exclusive) @@ -2877,16 +2976,16 @@ class EarliestDateTimeView(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r EarliestDateTimeView + EarliestDateTimeView: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this EarliestDateTimeView Returns: - Optional[int] + Optional[int]: """ class LatestDateTimeView(object): @@ -2922,7 +3021,7 @@ class LatestDateTimeView(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> LatestDateTimeView: """ Create a view of the LatestDateTimeView including all events after `start` (exclusive). @@ -2930,10 +3029,10 @@ class LatestDateTimeView(object): start (TimeInput): The start time of the window. Returns: - LatestDateTimeView + LatestDateTimeView: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> LatestDateTimeView: """ Create a view of the LatestDateTimeView including all events at `time`. @@ -2941,10 +3040,10 @@ class LatestDateTimeView(object): time (TimeInput): The time of the window. Returns: - LatestDateTimeView + LatestDateTimeView: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> LatestDateTimeView: """ Create a view of the LatestDateTimeView including all events before `end` (exclusive). @@ -2952,7 +3051,7 @@ class LatestDateTimeView(object): end (TimeInput): The end time of the window. Returns: - LatestDateTimeView + LatestDateTimeView: """ def bottom_k(self, k: int) -> NodeStateOptionDateTime: @@ -2966,20 +3065,20 @@ class LatestDateTimeView(object): NodeStateOptionDateTime: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[Optional[datetime]]: """ Compute all values and return the result as a list - Returns + Returns: list[Optional[datetime]]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateOptionDateTime: """ Compute all values and return the result as a node view Returns: - NodeStateOptionDateTime + NodeStateOptionDateTime: the computed `NodeState` """ def default_layer(self) -> LatestDateTimeView: @@ -2990,7 +3089,7 @@ class LatestDateTimeView(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this LatestDateTimeView is valid. @@ -2999,12 +3098,12 @@ class LatestDateTimeView(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this LatestDateTimeView is valid Returns: - Optional[Datetime]: The latest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + Optional[datetime]: The latest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ def exclude_layer(self, name: str) -> LatestDateTimeView: @@ -3072,7 +3171,7 @@ class LatestDateTimeView(object): NodeGroups: The grouped nodes """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if LatestDateTimeView has the layer `"name"` @@ -3080,21 +3179,23 @@ class LatestDateTimeView(object): name (str): the name of the layer to check Returns: - bool + bool: """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[datetime]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[datetime]]]: Iterator over items """ - def latest(self): + def latest(self) -> LatestDateTimeView: """ Create a view of the LatestDateTimeView including all events at the latest time. Returns: - LatestDateTimeView + LatestDateTimeView: """ def layer(self, name: str) -> LatestDateTimeView: @@ -3137,12 +3238,12 @@ class LatestDateTimeView(object): Optional[Tuple[Node, Optional[datetime]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[datetime]]: """ Return the median value Returns: - Optional[Optional[datetime]] + Optional[Optional[datetime]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: @@ -3192,17 +3293,17 @@ class LatestDateTimeView(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> LatestDateTimeView: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - LatestDateTimeView + LatestDateTimeView: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> LatestDateTimeView: """ Set the start of the window to the larger of `start` and `self.start()` @@ -3210,10 +3311,10 @@ class LatestDateTimeView(object): start (TimeInput): the new start time of the window Returns: - LatestDateTimeView + LatestDateTimeView: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> LatestDateTimeView: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -3221,9 +3322,11 @@ class LatestDateTimeView(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + LatestDateTimeView: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> LatestDateTimeView: """ Create a view of the LatestDateTimeView including all events that have not been explicitly deleted at `time`. @@ -3233,17 +3336,17 @@ class LatestDateTimeView(object): time (TimeInput): The time of the window. Returns: - LatestDateTimeView + LatestDateTimeView: """ - def snapshot_latest(self): + def snapshot_latest(self) -> LatestDateTimeView: """ Create a view of the LatestDateTimeView including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - LatestDateTimeView + LatestDateTimeView: """ def sorted(self, reverse: bool = False) -> NodeStateOptionDateTime: @@ -3266,7 +3369,7 @@ class LatestDateTimeView(object): """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this LatestDateTimeView @@ -3275,12 +3378,12 @@ class LatestDateTimeView(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this LatestDateTimeView is valid Returns: - Optional[Datetime]: The earliest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. + Optional[datetime]: The earliest datetime that this LatestDateTimeView is valid or None if the LatestDateTimeView is valid for all times. """ def top_k(self, k: int) -> NodeStateOptionDateTime: @@ -3306,13 +3409,17 @@ class LatestDateTimeView(object): LatestDateTimeView: The layered view """ - def values(self): + def values(self) -> Iterator[Optional[datetime]]: """ + Iterate over values + Returns: Iterator[Optional[datetime]]: Iterator over values """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window( + self, start: TimeInput | None, end: TimeInput | None + ) -> LatestDateTimeView: """ Create a view of the LatestDateTimeView including all events between `start` (inclusive) and `end` (exclusive) @@ -3321,16 +3428,16 @@ class LatestDateTimeView(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r LatestDateTimeView + LatestDateTimeView: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this LatestDateTimeView Returns: - Optional[int] + Optional[int]: """ class NodeStateOptionDateTime(object): @@ -3383,8 +3490,10 @@ class NodeStateOptionDateTime(object): NodeGroups: The grouped nodes """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[datetime]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[datetime]]]: Iterator over items """ @@ -3405,12 +3514,12 @@ class NodeStateOptionDateTime(object): Optional[Tuple[Node, Optional[datetime]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[datetime]]: """ Return the median value Returns: - Optional[Optional[datetime]] + Optional[Optional[datetime]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[datetime]]]: @@ -3475,8 +3584,10 @@ class NodeStateOptionDateTime(object): NodeStateOptionDateTime: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[Optional[datetime]]: """ + Iterate over values + Returns: Iterator[Optional[datetime]]: Iterator over values """ @@ -3514,7 +3625,7 @@ class HistoryView(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> HistoryView: """ Create a view of the HistoryView including all events after `start` (exclusive). @@ -3522,10 +3633,10 @@ class HistoryView(object): start (TimeInput): The start time of the window. Returns: - HistoryView + HistoryView: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> HistoryView: """ Create a view of the HistoryView including all events at `time`. @@ -3533,10 +3644,10 @@ class HistoryView(object): time (TimeInput): The time of the window. Returns: - HistoryView + HistoryView: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> HistoryView: """ Create a view of the HistoryView including all events before `end` (exclusive). @@ -3544,7 +3655,7 @@ class HistoryView(object): end (TimeInput): The end time of the window. Returns: - HistoryView + HistoryView: """ def bottom_k(self, k: int) -> NodeStateListI64: @@ -3558,20 +3669,20 @@ class HistoryView(object): NodeStateListI64: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[list[int]]: """ Compute all values and return the result as a list - Returns + Returns: list[list[int]]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateListI64: """ Compute all values and return the result as a node view Returns: - NodeStateListI64 + NodeStateListI64: the computed `NodeState` """ def default_layer(self) -> HistoryView: @@ -3582,7 +3693,7 @@ class HistoryView(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this HistoryView is valid. @@ -3591,12 +3702,12 @@ class HistoryView(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this HistoryView is valid Returns: - Optional[Datetime]: The latest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. + Optional[datetime]: The latest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. """ def exclude_layer(self, name: str) -> HistoryView: @@ -3656,7 +3767,7 @@ class HistoryView(object): WindowSet: A `WindowSet` object. """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if HistoryView has the layer `"name"` @@ -3664,21 +3775,23 @@ class HistoryView(object): name (str): the name of the layer to check Returns: - bool + bool: """ - def items(self): + def items(self) -> Iterator[Tuple[Node, list[int]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, list[int]]]: Iterator over items """ - def latest(self): + def latest(self) -> HistoryView: """ Create a view of the HistoryView including all events at the latest time. Returns: - HistoryView + HistoryView: """ def layer(self, name: str) -> HistoryView: @@ -3721,12 +3834,12 @@ class HistoryView(object): Optional[Tuple[Node, list[int]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[list[int]]: """ Return the median value Returns: - Optional[list[int]] + Optional[list[int]]: """ def median_item(self) -> Optional[Tuple[Node, list[int]]]: @@ -3776,17 +3889,17 @@ class HistoryView(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> HistoryView: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - HistoryView + HistoryView: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> HistoryView: """ Set the start of the window to the larger of `start` and `self.start()` @@ -3794,10 +3907,10 @@ class HistoryView(object): start (TimeInput): the new start time of the window Returns: - HistoryView + HistoryView: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> HistoryView: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -3805,9 +3918,11 @@ class HistoryView(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + HistoryView: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> HistoryView: """ Create a view of the HistoryView including all events that have not been explicitly deleted at `time`. @@ -3817,17 +3932,17 @@ class HistoryView(object): time (TimeInput): The time of the window. Returns: - HistoryView + HistoryView: """ - def snapshot_latest(self): + def snapshot_latest(self) -> HistoryView: """ Create a view of the HistoryView including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - HistoryView + HistoryView: """ def sorted(self, reverse: bool = False) -> NodeStateListI64: @@ -3850,7 +3965,7 @@ class HistoryView(object): """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this HistoryView @@ -3859,12 +3974,12 @@ class HistoryView(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this HistoryView is valid Returns: - Optional[Datetime]: The earliest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. + Optional[datetime]: The earliest datetime that this HistoryView is valid or None if the HistoryView is valid for all times. """ def top_k(self, k: int) -> NodeStateListI64: @@ -3890,13 +4005,15 @@ class HistoryView(object): HistoryView: The layered view """ - def values(self): + def values(self) -> Iterator[list[int]]: """ + Iterate over values + Returns: Iterator[list[int]]: Iterator over values """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window(self, start: TimeInput | None, end: TimeInput | None) -> HistoryView: """ Create a view of the HistoryView including all events between `start` (inclusive) and `end` (exclusive) @@ -3905,16 +4022,16 @@ class HistoryView(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r HistoryView + HistoryView: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this HistoryView Returns: - Optional[int] + Optional[int]: """ class NodeStateListI64(object): @@ -3959,8 +4076,10 @@ class NodeStateListI64(object): NodeStateListI64: The k smallest values as a node state """ - def items(self): + def items(self) -> Iterator[Tuple[Node, list[int]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, list[int]]]: Iterator over items """ @@ -3981,12 +4100,12 @@ class NodeStateListI64(object): Optional[Tuple[Node, list[int]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[list[int]]: """ Return the median value Returns: - Optional[list[int]] + Optional[list[int]]: """ def median_item(self) -> Optional[Tuple[Node, list[int]]]: @@ -4051,8 +4170,10 @@ class NodeStateListI64(object): NodeStateListI64: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[list[int]]: """ + Iterate over values + Returns: Iterator[list[int]]: Iterator over values """ @@ -4090,7 +4211,7 @@ class HistoryDateTimeView(object): def __repr__(self): """Return repr(self).""" - def after(self, start: TimeInput): + def after(self, start: TimeInput) -> HistoryDateTimeView: """ Create a view of the HistoryDateTimeView including all events after `start` (exclusive). @@ -4098,10 +4219,10 @@ class HistoryDateTimeView(object): start (TimeInput): The start time of the window. Returns: - HistoryDateTimeView + HistoryDateTimeView: """ - def at(self, time: TimeInput): + def at(self, time: TimeInput) -> HistoryDateTimeView: """ Create a view of the HistoryDateTimeView including all events at `time`. @@ -4109,10 +4230,10 @@ class HistoryDateTimeView(object): time (TimeInput): The time of the window. Returns: - HistoryDateTimeView + HistoryDateTimeView: """ - def before(self, end: TimeInput): + def before(self, end: TimeInput) -> HistoryDateTimeView: """ Create a view of the HistoryDateTimeView including all events before `end` (exclusive). @@ -4120,7 +4241,7 @@ class HistoryDateTimeView(object): end (TimeInput): The end time of the window. Returns: - HistoryDateTimeView + HistoryDateTimeView: """ def bottom_k(self, k: int) -> NodeStateOptionListDateTime: @@ -4134,20 +4255,20 @@ class HistoryDateTimeView(object): NodeStateOptionListDateTime: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[Optional[list[datetime]]]: """ Compute all values and return the result as a list - Returns + Returns: list[Optional[list[datetime]]]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateOptionListDateTime: """ Compute all values and return the result as a node view Returns: - NodeStateOptionListDateTime + NodeStateOptionListDateTime: the computed `NodeState` """ def default_layer(self) -> HistoryDateTimeView: @@ -4158,7 +4279,7 @@ class HistoryDateTimeView(object): """ @property - def end(self): + def end(self) -> Optional[int]: """ Gets the latest time that this HistoryDateTimeView is valid. @@ -4167,12 +4288,12 @@ class HistoryDateTimeView(object): """ @property - def end_date_time(self): + def end_date_time(self) -> Optional[datetime]: """ Gets the latest datetime that this HistoryDateTimeView is valid Returns: - Optional[Datetime]: The latest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + Optional[datetime]: The latest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ def exclude_layer(self, name: str) -> HistoryDateTimeView: @@ -4232,7 +4353,7 @@ class HistoryDateTimeView(object): WindowSet: A `WindowSet` object. """ - def has_layer(self, name: str): + def has_layer(self, name: str) -> bool: """ Check if HistoryDateTimeView has the layer `"name"` @@ -4240,21 +4361,23 @@ class HistoryDateTimeView(object): name (str): the name of the layer to check Returns: - bool + bool: """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[list[datetime]]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[list[datetime]]]]: Iterator over items """ - def latest(self): + def latest(self) -> HistoryDateTimeView: """ Create a view of the HistoryDateTimeView including all events at the latest time. Returns: - HistoryDateTimeView + HistoryDateTimeView: """ def layer(self, name: str) -> HistoryDateTimeView: @@ -4297,12 +4420,12 @@ class HistoryDateTimeView(object): Optional[Tuple[Node, Optional[list[datetime]]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[list[datetime]]]: """ Return the median value Returns: - Optional[Optional[list[datetime]]] + Optional[Optional[list[datetime]]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[list[datetime]]]]: @@ -4352,17 +4475,17 @@ class HistoryDateTimeView(object): WindowSet: A `WindowSet` object. """ - def shrink_end(self, end: TimeInput): + def shrink_end(self, end: TimeInput) -> HistoryDateTimeView: """ Set the end of the window to the smaller of `end` and `self.end()` Arguments: end (TimeInput): the new end time of the window Returns: - HistoryDateTimeView + HistoryDateTimeView: """ - def shrink_start(self, start: TimeInput): + def shrink_start(self, start: TimeInput) -> HistoryDateTimeView: """ Set the start of the window to the larger of `start` and `self.start()` @@ -4370,10 +4493,10 @@ class HistoryDateTimeView(object): start (TimeInput): the new start time of the window Returns: - HistoryDateTimeView + HistoryDateTimeView: """ - def shrink_window(self, start: TimeInput, end: TimeInput): + def shrink_window(self, start: TimeInput, end: TimeInput) -> HistoryDateTimeView: """ Shrink both the start and end of the window (same as calling `shrink_start` followed by `shrink_end` but more efficient) @@ -4381,9 +4504,11 @@ class HistoryDateTimeView(object): start (TimeInput): the new start time for the window end (TimeInput): the new end time for the window + Returns: + HistoryDateTimeView: """ - def snapshot_at(self, time: TimeInput): + def snapshot_at(self, time: TimeInput) -> HistoryDateTimeView: """ Create a view of the HistoryDateTimeView including all events that have not been explicitly deleted at `time`. @@ -4393,17 +4518,17 @@ class HistoryDateTimeView(object): time (TimeInput): The time of the window. Returns: - HistoryDateTimeView + HistoryDateTimeView: """ - def snapshot_latest(self): + def snapshot_latest(self) -> HistoryDateTimeView: """ Create a view of the HistoryDateTimeView including all events that have not been explicitly deleted at the latest time. This is equivalent to a no-op for `EventGraph`s and `latest()` for `PersitentGraph`s Returns: - HistoryDateTimeView + HistoryDateTimeView: """ def sorted(self, reverse: bool = False) -> NodeStateOptionListDateTime: @@ -4426,7 +4551,7 @@ class HistoryDateTimeView(object): """ @property - def start(self): + def start(self) -> Optional[int]: """ Gets the start time for rolling and expanding windows for this HistoryDateTimeView @@ -4435,12 +4560,12 @@ class HistoryDateTimeView(object): """ @property - def start_date_time(self): + def start_date_time(self) -> Optional[datetime]: """ Gets the earliest datetime that this HistoryDateTimeView is valid Returns: - Optional[Datetime]: The earliest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. + Optional[datetime]: The earliest datetime that this HistoryDateTimeView is valid or None if the HistoryDateTimeView is valid for all times. """ def top_k(self, k: int) -> NodeStateOptionListDateTime: @@ -4466,13 +4591,17 @@ class HistoryDateTimeView(object): HistoryDateTimeView: The layered view """ - def values(self): + def values(self) -> Iterator[Optional[list[datetime]]]: """ + Iterate over values + Returns: Iterator[Optional[list[datetime]]]: Iterator over values """ - def window(self, start: TimeInput | None, end: TimeInput | None): + def window( + self, start: TimeInput | None, end: TimeInput | None + ) -> HistoryDateTimeView: """ Create a view of the HistoryDateTimeView including all events between `start` (inclusive) and `end` (exclusive) @@ -4481,16 +4610,16 @@ class HistoryDateTimeView(object): end (TimeInput | None): The end time of the window (unbounded if `None`). Returns: - r HistoryDateTimeView + HistoryDateTimeView: """ @property - def window_size(self): + def window_size(self) -> Optional[int]: """ Get the window size (difference between start and end) for this HistoryDateTimeView Returns: - Optional[int] + Optional[int]: """ class NodeStateOptionListDateTime(object): @@ -4535,8 +4664,10 @@ class NodeStateOptionListDateTime(object): NodeStateOptionListDateTime: The k smallest values as a node state """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[list[datetime]]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[list[datetime]]]]: Iterator over items """ @@ -4557,12 +4688,12 @@ class NodeStateOptionListDateTime(object): Optional[Tuple[Node, Optional[list[datetime]]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[list[datetime]]]: """ Return the median value Returns: - Optional[Optional[list[datetime]]] + Optional[Optional[list[datetime]]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[list[datetime]]]]: @@ -4627,8 +4758,10 @@ class NodeStateOptionListDateTime(object): NodeStateOptionListDateTime: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[Optional[list[datetime]]]: """ + Iterate over values + Returns: Iterator[Optional[list[datetime]]]: Iterator over values """ @@ -4677,20 +4810,20 @@ class NodeTypeView(object): NodeStateOptionStr: The k smallest values as a node state """ - def collect(self): + def collect(self) -> list[Optional[str]]: """ Compute all values and return the result as a list - Returns + Returns: list[Optional[str]]: all values as a list """ - def compute(self): + def compute(self) -> NodeStateOptionStr: """ Compute all values and return the result as a node view Returns: - NodeStateOptionStr + NodeStateOptionStr: the computed `NodeState` """ def groups(self) -> NodeGroups: @@ -4701,8 +4834,10 @@ class NodeTypeView(object): NodeGroups: The grouped nodes """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[str]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[str]]]: Iterator over items """ @@ -4723,12 +4858,12 @@ class NodeTypeView(object): Optional[Tuple[Node, Optional[str]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[str]]: """ Return the median value Returns: - Optional[Optional[str]] + Optional[Optional[str]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[str]]]: @@ -4793,8 +4928,10 @@ class NodeTypeView(object): NodeStateOptionStr: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[Optional[str]]: """ + Iterate over values + Returns: Iterator[Optional[str]]: Iterator over values """ @@ -4849,8 +4986,10 @@ class NodeStateOptionStr(object): NodeGroups: The grouped nodes """ - def items(self): + def items(self) -> Iterator[Tuple[Node, Optional[str]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, Optional[str]]]: Iterator over items """ @@ -4871,12 +5010,12 @@ class NodeStateOptionStr(object): Optional[Tuple[Node, Optional[str]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[Optional[str]]: """ Return the median value Returns: - Optional[Optional[str]] + Optional[Optional[str]]: """ def median_item(self) -> Optional[Tuple[Node, Optional[str]]]: @@ -4941,8 +5080,10 @@ class NodeStateOptionStr(object): NodeStateOptionStr: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[Optional[str]]: """ + Iterate over values + Returns: Iterator[Optional[str]]: Iterator over values """ @@ -4989,8 +5130,10 @@ class NodeStateListDateTime(object): NodeStateListDateTime: The k smallest values as a node state """ - def items(self): + def items(self) -> Iterator[Tuple[Node, list[datetime]]]: """ + Iterate over items + Returns: Iterator[Tuple[Node, list[datetime]]]: Iterator over items """ @@ -5011,12 +5154,12 @@ class NodeStateListDateTime(object): Optional[Tuple[Node, list[datetime]]]: The Node and maximum value or `None` if empty """ - def median(self): + def median(self) -> Optional[list[datetime]]: """ Return the median value Returns: - Optional[list[datetime]] + Optional[list[datetime]]: """ def median_item(self) -> Optional[Tuple[Node, list[datetime]]]: @@ -5081,8 +5224,10 @@ class NodeStateListDateTime(object): NodeStateListDateTime: The k largest values as a node state """ - def values(self): + def values(self) -> Iterator[list[datetime]]: """ + Iterate over values + Returns: Iterator[list[datetime]]: Iterator over values """ diff --git a/python/tests/test_graphdb/test_node_state.py b/python/tests/test_graphdb/test_node_state.py index a8015ff770..62914c77ca 100644 --- a/python/tests/test_graphdb/test_node_state.py +++ b/python/tests/test_graphdb/test_node_state.py @@ -24,3 +24,33 @@ def test_degree_layer(): assert degs == [3, 0, 0, 0] assert degs.layers(["1"]) == [1, 0, 0, 0] assert degs.layers(["2"]) == [2, 0, 0, 0] + + +def test_group_by(): + g = Graph() + g.add_edge(0, 1, 2) + g.add_edge(0, 2, 3) + g.add_edge(0, 4, 5) + + groups_from_lazy = g.nodes.out_degree().groups() + groups_from_eager = g.nodes.out_degree().compute().groups() + + expected = { + 0: [3, 5], + 1: [1, 2, 4], + } + + assert {v: nodes.id for v, nodes in groups_from_lazy} == expected + + assert {v: nodes.id for v, nodes in groups_from_eager} == expected + + assert { + v: graph.nodes.id for v, graph in groups_from_lazy.iter_subgraphs() + } == expected + + assert len(groups_from_lazy) == len(expected) + + for i, (v, nodes) in enumerate(groups_from_lazy): + (v2, nodes2) = groups_from_eager[i] + assert v == v2 + assert nodes.id == nodes2.id diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index 3ace5fa51f..2883a6121b 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -122,4 +122,78 @@ where } #[cfg(test)] -mod tests {} +mod tests { + use crate::{prelude::*, test_storage}; + use std::collections::HashMap; + + #[test] + fn test() { + let g = Graph::new(); + g.add_edge(0, 1, 2, NO_PROPS, None).unwrap(); + g.add_edge(0, 2, 3, NO_PROPS, None).unwrap(); + g.add_edge(0, 4, 5, NO_PROPS, None).unwrap(); + + test_storage!(&g, |g| { + let groups_from_lazy = g.nodes().out_degree().groups(); + let groups_from_eager = g.nodes().out_degree().compute().groups(); + + let expected = HashMap::from([ + (0, vec![GID::U64(3), GID::U64(5)]), + (1, vec![GID::U64(1), GID::U64(2), GID::U64(4)]), + ]); + + assert_eq!( + groups_from_lazy + .iter() + .map(|(v, nodes)| (*v, nodes.id().collect_vec())) + .collect::>(), + expected + ); + + assert_eq!( + groups_from_lazy + .clone() + .into_iter_groups() + .map(|(v, nodes)| (v, nodes.id().collect_vec())) + .collect::>(), + expected + ); + + assert_eq!( + groups_from_lazy + .iter_subgraphs() + .map(|(v, graph)| (*v, graph.nodes().id().collect_vec())) + .collect::>(), + expected + ); + + assert_eq!( + groups_from_lazy + .clone() + .into_iter_subgraphs() + .map(|(v, graph)| (v, graph.nodes().id().collect_vec())) + .collect::>(), + expected + ); + + assert_eq!( + groups_from_eager + .iter() + .map(|(v, nodes)| (*v, nodes.id().collect_vec())) + .collect::>(), + expected + ); + + assert_eq!(groups_from_lazy.len(), expected.len()); + + for (i, (v, nodes)) in groups_from_eager.iter().enumerate() { + let (v2, nodes2) = groups_from_eager.group(i).unwrap(); + assert_eq!(v, v2); + assert!(nodes.iter().eq(nodes2.iter())); + let (v3, graph) = groups_from_eager.group_subgraph(i).unwrap(); + assert_eq!(v, v3); + assert!(nodes.iter().eq(graph.nodes().iter())); + } + }); + } +} diff --git a/raphtory/src/lib.rs b/raphtory/src/lib.rs index 701d50c016..5d62ff4d2a 100644 --- a/raphtory/src/lib.rs +++ b/raphtory/src/lib.rs @@ -117,7 +117,9 @@ pub mod prelude { db::{ api::{ mutation::{AdditionOps, DeletionOps, ImportOps, PropertyAdditionOps}, - state::{AsOrderedNodeStateOps, NodeStateOps, OrderedNodeStateOps}, + state::{ + AsOrderedNodeStateOps, NodeStateGroupBy, NodeStateOps, OrderedNodeStateOps, + }, view::{ EdgePropertyFilterOps, EdgeViewOps, ExplodedEdgePropertyFilterOps, GraphViewOps, Layer, LayerOps, NodePropertyFilterOps, NodeViewOps, ResetFilter, diff --git a/raphtory/src/python/graph/node.rs b/raphtory/src/python/graph/node.rs index ea526a235a..8953067707 100644 --- a/raphtory/src/python/graph/node.rs +++ b/raphtory/src/python/graph/node.rs @@ -97,7 +97,7 @@ impl AsNodeRef for PyNode { /// It can also be used to navigate the graph. #[pymethods] impl PyNode { - /// checks if a node is equal to another by their id (ids are unqiue) + /// checks if a node is equal to another by their id (ids are unique) /// /// Arguments: /// other: The other node to compare to. diff --git a/raphtory/src/python/graph/node_state/group_by.rs b/raphtory/src/python/graph/node_state/group_by.rs index f4f100e6df..2c455c5f90 100644 --- a/raphtory/src/python/graph/node_state/group_by.rs +++ b/raphtory/src/python/graph/node_state/group_by.rs @@ -17,13 +17,13 @@ trait PyNodeGroupOps: Send + Sync + 'static { &self, index: usize, py: Python<'py>, - ) -> PyResult, Bound<'py, PyAny>)>>; + ) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyAny>)>; fn group_subgraph<'py>( &self, index: usize, py: Python<'py>, - ) -> PyResult, DynamicGraph)>>; + ) -> PyResult<(Bound<'py, PyAny>, DynamicGraph)>; fn len(&self) -> usize; @@ -47,27 +47,25 @@ impl< &self, index: usize, py: Python<'py>, - ) -> PyResult, Bound<'py, PyAny>)>> { - let res = match self.group(index) { - Some((v, nodes)) => Some(( + ) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyAny>)> { + match self.group(index) { + Some((v, nodes)) => Ok(( v.clone().into_bound_py_any(py)?, nodes.into_bound_py_any(py)?, )), - None => None, - }; - Ok(res) + None => Err(PyIndexError::new_err("Index for group out of bounds")), + } } fn group_subgraph<'py>( &self, index: usize, py: Python<'py>, - ) -> PyResult, DynamicGraph)>> { - let res = match self.group_subgraph(index) { - None => None, - Some((v, graph)) => Some((v.clone().into_bound_py_any(py)?, graph.into_dynamic())), - }; - Ok(res) + ) -> PyResult<(Bound<'py, PyAny>, DynamicGraph)> { + match self.group_subgraph(index) { + None => Err(PyIndexError::new_err("Index for group out of bounds")), + Some((v, graph)) => Ok((v.clone().into_bound_py_any(py)?, graph.into_dynamic())), + } } fn len(&self) -> usize { @@ -79,7 +77,7 @@ impl< } } -#[pyclass(name = "NodeGroups", module = "node_state", frozen)] +#[pyclass(name = "NodeGroups", module = "raphtory.node_state", frozen)] pub struct PyNodeGroups { inner: Box, } @@ -103,27 +101,43 @@ impl PyNodeGroups { index: usize, py: Python<'py>, ) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyAny>)> { - self.inner - .group(index, py)? - .ok_or_else(|| PyIndexError::new_err("group not found")) + self.inner.group(index, py) } + /// Get group nodes and value + /// + /// Arguments: + /// index (int): the group index + /// + /// Returns: + /// Tuple[Any, Nodes]: Nodes and corresponding value fn group<'py>( &self, index: usize, py: Python<'py>, - ) -> PyResult, Bound<'py, PyAny>)>> { + ) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyAny>)> { self.inner.group(index, py) } + /// Get group as subgraph + /// + /// Arguments: + /// index (int): the group index + /// + /// Returns: + /// Tuple[Any, GraphView]: The group as a subgraph and corresponding value fn group_subgraph<'py>( &self, index: usize, py: Python<'py>, - ) -> PyResult, DynamicGraph)>> { + ) -> PyResult<(Bound<'py, PyAny>, DynamicGraph)> { self.inner.group_subgraph(index, py) } + /// Iterate over group subgraphs + /// + /// Returns: + /// Iterator[Tuple[Any, GraphView]]: Iterator over subgraphs with corresponding value fn iter_subgraphs(&self) -> PyGenericIterator { self.inner.iter_subgraphs() } diff --git a/raphtory/src/python/graph/node_state/mod.rs b/raphtory/src/python/graph/node_state/mod.rs index 7842e1b8ed..ba25b570b8 100644 --- a/raphtory/src/python/graph/node_state/mod.rs +++ b/raphtory/src/python/graph/node_state/mod.rs @@ -1,4 +1,34 @@ mod group_by; mod node_state; - +use crate::{add_classes, python::graph::node_state::group_by::PyNodeGroups}; pub use node_state::*; +use pyo3::prelude::*; + +pub fn base_node_state_module(py: Python<'_>) -> PyResult> { + let m = PyModule::new(py, "node_state")?; + add_classes!( + &m, + PyNodeGroups, + DegreeView, + NodeStateUsize, + NodeStateU64, + NodeStateOptionI64, + IdView, + NodeStateGID, + EarliestTimeView, + LatestTimeView, + NameView, + NodeStateString, + EarliestDateTimeView, + LatestDateTimeView, + NodeStateOptionDateTime, + HistoryView, + NodeStateListI64, + HistoryDateTimeView, + NodeStateOptionListDateTime, + NodeTypeView, + NodeStateOptionStr, + NodeStateListDateTime, + ); + Ok(m) +} diff --git a/raphtory/src/python/graph/node_state/node_state.rs b/raphtory/src/python/graph/node_state/node_state.rs index 99684ddf94..9c1054ae82 100644 --- a/raphtory/src/python/graph/node_state/node_state.rs +++ b/raphtory/src/python/graph/node_state/node_state.rs @@ -1,5 +1,4 @@ use crate::{ - add_classes, core::entities::nodes::node_ref::{AsNodeRef, NodeRef}, db::{ api::{ @@ -17,7 +16,6 @@ use crate::{ prelude::*, py_borrowing_iter, python::{ - graph::node_state::group_by::PyNodeGroups, types::{repr::Repr, wrappers::iterators::PyBorrowingIterator}, utils::PyNodeRef, }, @@ -542,32 +540,3 @@ impl_node_state_ord!( "NodeStateListDateTime", "list[datetime]" ); - -pub fn base_node_state_module(py: Python<'_>) -> PyResult> { - let m = PyModule::new(py, "node_state")?; - add_classes!( - &m, - DegreeView, - NodeStateUsize, - NodeStateU64, - NodeStateOptionI64, - IdView, - NodeStateGID, - EarliestTimeView, - LatestTimeView, - NameView, - NodeStateString, - EarliestDateTimeView, - LatestDateTimeView, - NodeStateOptionDateTime, - HistoryView, - NodeStateListI64, - HistoryDateTimeView, - NodeStateOptionListDateTime, - NodeTypeView, - NodeStateOptionStr, - NodeStateListDateTime, - PyNodeGroups - ); - Ok(m) -} From 73460b6b1c353f44e13a703bec5231ff2bec2a81 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Fri, 10 Jan 2025 16:06:20 +0100 Subject: [PATCH 23/29] fix the python test --- python/tests/test_graphdb/test_node_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tests/test_graphdb/test_node_state.py b/python/tests/test_graphdb/test_node_state.py index 62914c77ca..43d03f48be 100644 --- a/python/tests/test_graphdb/test_node_state.py +++ b/python/tests/test_graphdb/test_node_state.py @@ -51,6 +51,6 @@ def test_group_by(): assert len(groups_from_lazy) == len(expected) for i, (v, nodes) in enumerate(groups_from_lazy): - (v2, nodes2) = groups_from_eager[i] + (v2, nodes2) = groups_from_lazy[i] assert v == v2 assert nodes.id == nodes2.id From d5bced2c8a68445b7104ec2950277eb4212a60fa Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Mon, 13 Jan 2025 15:03:17 +0100 Subject: [PATCH 24/29] make groub_by parallel --- Cargo.lock | 1 + Cargo.toml | 2 +- raphtory/src/db/api/state/group_by.rs | 17 ++++++++++------- raphtory/src/db/api/state/node_state_ops.rs | 4 ++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d55918fb1c..d1d606598f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1447,6 +1447,7 @@ dependencies = [ "lock_api", "once_cell", "parking_lot_core", + "rayon", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index fbf5f84a69..7bd6d2221f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,7 @@ rand_distr = "0.4.3" rustc-hash = "2.0.0" twox-hash = "2.1.0" lock_api = { version = "0.4.11", features = ["arc_lock", "serde"] } -dashmap = { version = "6.0.1", features = ["serde"] } +dashmap = { version = "6.0.1", features = ["serde", "rayon"] } enum_dispatch = "0.3.12" glam = "0.29.0" quad-rand = "0.2.1" diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index 2883a6121b..a872743a6d 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -5,8 +5,10 @@ use crate::{ }, prelude::{GraphViewOps, NodeStateOps}, }; +use dashmap::DashMap; use raphtory_api::core::entities::VID; -use std::{collections::HashMap, hash::Hash, sync::Arc}; +use rayon::prelude::*; +use std::{hash::Hash, sync::Arc}; #[derive(Clone, Debug)] pub struct NodeGroups { @@ -14,14 +16,15 @@ pub struct NodeGroups { graph: G, } -impl<'graph, V: Hash + Eq, G: GraphViewOps<'graph>> NodeGroups { - pub(crate) fn new(values: impl Iterator, graph: G) -> Self { - let mut groups: HashMap> = HashMap::new(); - for (node, v) in values { +impl<'graph, V: Hash + Eq + Send + Sync + Clone, G: GraphViewOps<'graph>> NodeGroups { + pub(crate) fn new(values: impl ParallelIterator, graph: G) -> Self { + let groups: DashMap, ahash::RandomState> = DashMap::default(); + values.for_each(|(node, v)| { groups.entry(v).or_insert_with(Vec::new).push(node); - } + }); + let groups = groups - .into_iter() + .into_par_iter() .map(|(k, v)| (k, Index::new(v))) .collect(); Self { groups, graph } diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index 7ba019671a..1e293b3c1d 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -208,12 +208,12 @@ pub trait NodeStateOps<'graph>: values.into_iter().nth(median_index) } - fn group_by V + Sync>( + fn group_by V + Sync>( &self, group_fn: F, ) -> NodeGroups { NodeGroups::new( - self.iter() + self.par_iter() .map(|(node, v)| (node.node, group_fn(v.borrow()))), self.graph().clone(), ) From 6f6bdfcde3c61c235db82275cd224bea23b41ab6 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Tue, 14 Jan 2025 10:45:56 +0100 Subject: [PATCH 25/29] rename iter methods in NodeStateOps to be more explicit and add values method to the non-lazy NodeState to get a reference to the underlying values --- raphtory/src/algorithms/metrics/degree.rs | 2 +- raphtory/src/db/api/state/lazy_node_state.rs | 16 +++++++------- raphtory/src/db/api/state/node_state.rs | 22 ++++++++++++++----- raphtory/src/db/api/state/node_state_ops.rs | 10 ++++----- raphtory/src/db/api/view/graph.rs | 6 ++--- raphtory/src/db/api/view/internal/mod.rs | 2 +- raphtory/src/db/graph/graph.rs | 12 +++++----- raphtory/src/db/graph/views/window_graph.rs | 15 ++++++++----- raphtory/src/disk_graph/graph_impl/interop.rs | 2 +- raphtory/src/disk_graph/graph_impl/mod.rs | 8 +++---- .../src/graphgen/preferential_attachment.rs | 4 ++-- raphtory/src/graphgen/random_attachment.rs | 2 +- raphtory/src/io/json_loader.rs | 2 +- raphtory/src/python/graph/node.rs | 2 +- .../src/python/graph/node_state/node_state.rs | 8 +++---- 15 files changed, 65 insertions(+), 48 deletions(-) diff --git a/raphtory/src/algorithms/metrics/degree.rs b/raphtory/src/algorithms/metrics/degree.rs index 7fa913716b..9ec7a64a79 100644 --- a/raphtory/src/algorithms/metrics/degree.rs +++ b/raphtory/src/algorithms/metrics/degree.rs @@ -81,7 +81,7 @@ pub fn average_degree<'graph, G: GraphViewOps<'graph>>(graph: &'graph G) -> f64 let (deg_sum, count) = graph .nodes() .degree() - .par_values() + .par_iter_values() .fold_with((0usize, 0usize), |(deg_sum, count), deg| { (deg_sum + deg, count + 1) }) diff --git a/raphtory/src/db/api/state/lazy_node_state.rs b/raphtory/src/db/api/state/lazy_node_state.rs index 90af73a3b3..fab4e21ce2 100644 --- a/raphtory/src/db/api/state/lazy_node_state.rs +++ b/raphtory/src/db/api/state/lazy_node_state.rs @@ -30,7 +30,7 @@ where Op::Output: Debug, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_list().entries(self.values()).finish() + f.debug_list().entries(self.iter_values()).finish() } } @@ -71,7 +71,7 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra self.nodes .clone() .into_iter() - .zip(self.into_values()) + .zip(self.into_iter_values()) .into_dyn_boxed() } } @@ -84,7 +84,7 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra } pub fn collect>(&self) -> C { - self.par_values().collect() + self.par_iter_values().collect() } pub fn collect_vec(&self) -> Vec { @@ -135,7 +135,7 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra &self.nodes.base_graph } - fn values<'a>(&'a self) -> impl Iterator> + 'a + fn iter_values<'a>(&'a self) -> impl Iterator> + 'a where 'graph: 'a, { @@ -145,7 +145,7 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra .map(move |vid| self.op.apply(&storage, vid)) } - fn par_values<'a>(&'a self) -> impl ParallelIterator> + 'a + fn par_iter_values<'a>(&'a self) -> impl ParallelIterator> + 'a where 'graph: 'a, { @@ -155,14 +155,14 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra .map(move |vid| self.op.apply(&storage, vid)) } - fn into_values(self) -> impl Iterator + Send + Sync + 'graph { + fn into_iter_values(self) -> impl Iterator + Send + Sync + 'graph { let storage = self.graph().core_graph().lock(); self.nodes .iter_refs() .map(move |vid| self.op.apply(&storage, vid)) } - fn into_par_values(self) -> impl ParallelIterator + 'graph { + fn into_par_iter_values(self) -> impl ParallelIterator + 'graph { let storage = self.graph().core_graph().lock(); self.nodes .par_iter_refs() @@ -280,7 +280,7 @@ mod test { op: arc_deg.clone(), }; - let dyn_deg: Vec<_> = node_state_dyn.values().collect(); + let dyn_deg: Vec<_> = node_state_dyn.iter_values().collect(); assert_eq!(dyn_deg, [1, 1]); assert_eq!(arc_deg.apply(g.core_graph(), VID(0)), 1); diff --git a/raphtory/src/db/api/state/node_state.rs b/raphtory/src/db/api/state/node_state.rs index e04eef867e..4b2357770f 100644 --- a/raphtory/src/db/api/state/node_state.rs +++ b/raphtory/src/db/api/state/node_state.rs @@ -93,6 +93,14 @@ pub struct NodeState<'graph, V, G, GH = G> { _marker: PhantomData<&'graph ()>, } +impl<'graph, RHS: Send + Sync, V: PartialEq + Send + Sync, G, GH> PartialEq> + for NodeState<'graph, V, G, GH> +{ + fn eq(&self, other: &Vec) -> bool { + self.values.par_iter().eq(other) + } +} + impl<'graph, V, G: IntoDynamic, GH: IntoDynamic> NodeState<'graph, V, G, GH> { pub fn into_dyn(self) -> NodeState<'graph, V, DynamicGraph> { NodeState::new( @@ -161,6 +169,10 @@ impl<'graph, V, G: GraphViewOps<'graph>, GH: GraphViewOps<'graph>> NodeState<'gr pub fn into_inner(self) -> (Arc<[V]>, Option>) { (self.values, self.keys) } + + pub fn values(&self) -> &Arc<[V]> { + &self.values + } } impl< @@ -177,7 +189,7 @@ impl< self.nodes() .clone() .into_iter() - .zip(self.into_values()) + .zip(self.into_iter_values()) .into_dyn_boxed() } } @@ -205,25 +217,25 @@ impl< &self.base_graph } - fn values<'a>(&'a self) -> impl Iterator> + 'a + fn iter_values<'a>(&'a self) -> impl Iterator> + 'a where 'graph: 'a, { self.values.iter() } - fn par_values<'a>(&'a self) -> impl ParallelIterator> + 'a + fn par_iter_values<'a>(&'a self) -> impl ParallelIterator> + 'a where 'graph: 'a, { self.values.par_iter() } - fn into_values(self) -> impl Iterator + 'graph { + fn into_iter_values(self) -> impl Iterator + 'graph { (0..self.values.len()).map(move |i| self.values[i].clone()) } - fn into_par_values(self) -> impl ParallelIterator + 'graph { + fn into_par_iter_values(self) -> impl ParallelIterator + 'graph { (0..self.values.len()) .into_par_iter() .map(move |i| self.values[i].clone()) diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index 1e293b3c1d..3e57aede75 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -29,16 +29,16 @@ pub trait NodeStateOps<'graph>: fn base_graph(&self) -> &Self::BaseGraph; - fn values<'a>(&'a self) -> impl Iterator> + 'a + fn iter_values<'a>(&'a self) -> impl Iterator> + 'a where 'graph: 'a; - fn par_values<'a>(&'a self) -> impl ParallelIterator> + 'a + fn par_iter_values<'a>(&'a self) -> impl ParallelIterator> + 'a where 'graph: 'a; - fn into_values(self) -> impl Iterator + Send + Sync + 'graph; + fn into_iter_values(self) -> impl Iterator + Send + Sync + 'graph; - fn into_par_values(self) -> impl ParallelIterator + 'graph; + fn into_par_iter_values(self) -> impl ParallelIterator + 'graph; fn iter<'a>( &'a self, @@ -224,7 +224,7 @@ pub trait NodeStateOps<'graph>: 'graph: 'a, S: Send + Sum> + Sum, { - self.par_values().sum() + self.par_iter_values().sum() } fn mean<'a>(&'a self) -> f64 diff --git a/raphtory/src/db/api/view/graph.rs b/raphtory/src/db/api/view/graph.rs index 55b338ae69..d10e075264 100644 --- a/raphtory/src/db/api/view/graph.rs +++ b/raphtory/src/db/api/view/graph.rs @@ -1158,7 +1158,7 @@ mod test_materialize { assert_graph_equal(&g, &gm); assert_eq!( - gm.nodes().name().values().collect::>(), + gm.nodes().name().iter_values().collect::>(), vec!["1", "2"] ); @@ -1227,7 +1227,7 @@ mod test_materialize { nodes_subgraph .nodes() .name() - .values() + .iter_values() .collect::>(), vec!["4", "5"] ); @@ -1249,7 +1249,7 @@ mod test_materialize { exclude_nodes_subgraph .nodes() .name() - .values() + .iter_values() .collect::>(), vec!["1", "2", "3"] ); diff --git a/raphtory/src/db/api/view/internal/mod.rs b/raphtory/src/db/api/view/internal/mod.rs index 670871ed0d..776fdb4a95 100644 --- a/raphtory/src/db/api/view/internal/mod.rs +++ b/raphtory/src/db/api/view/internal/mod.rs @@ -197,7 +197,7 @@ mod test { boxed .nodes() .id() - .values() + .iter_values() .filter_map(|v| v.as_u64()) .collect_vec(), vec![1] diff --git a/raphtory/src/db/graph/graph.rs b/raphtory/src/db/graph/graph.rs index 77bf9bd496..5dbc3cf0cd 100644 --- a/raphtory/src/db/graph/graph.rs +++ b/raphtory/src/db/graph/graph.rs @@ -49,7 +49,7 @@ pub fn graph_equal<'graph1, 'graph2, G1: GraphViewOps<'graph1>, G2: GraphViewOps g2: &G2, ) -> bool { if g1.count_nodes() == g2.count_nodes() && g1.count_edges() == g2.count_edges() { - g1.nodes().id().par_values().all(|v| g2.has_node(v)) && // all nodes exist in other + g1.nodes().id().par_iter_values().all(|v| g2.has_node(v)) && // all nodes exist in other g1.count_temporal_edges() == g2.count_temporal_edges() && // same number of exploded edges g1.edges().explode().iter().all(|e| { // all exploded edges exist in other g2 @@ -2907,7 +2907,7 @@ mod db_tests { } g.nodes() .name() - .into_values() + .into_iter_values() .map(|name| g.node(name)) .all(|v| v.is_some()) } @@ -2921,7 +2921,7 @@ mod db_tests { assert!(g .nodes() .name() - .into_values() + .into_iter_values() .map(|name| g.node(name)) .all(|v| v.is_some())) } @@ -3201,7 +3201,7 @@ mod db_tests { g.nodes() .type_filter(&vec!["wallet"]) .name() - .into_values() + .into_iter_values() .collect_vec(), vec!["1", "4"] ); @@ -3372,7 +3372,7 @@ mod db_tests { g.nodes() .type_filter(&vec!["a"]) .name() - .into_values() + .into_iter_values() .collect_vec(), vec!["1", "4"] ); @@ -3380,7 +3380,7 @@ mod db_tests { g.nodes() .type_filter(&vec!["a", "c"]) .name() - .into_values() + .into_iter_values() .collect_vec(), vec!["1", "4", "5"] ); diff --git a/raphtory/src/db/graph/views/window_graph.rs b/raphtory/src/db/graph/views/window_graph.rs index a865e8cb15..eda93c3dff 100644 --- a/raphtory/src/db/graph/views/window_graph.rs +++ b/raphtory/src/db/graph/views/window_graph.rs @@ -1076,7 +1076,7 @@ mod views_test { let mut e = wg .nodes() .id() - .values() + .iter_values() .filter_map(|id| id.to_u64()) .collect::>(); e.sort(); @@ -1098,7 +1098,7 @@ mod views_test { let mut e = wg .nodes() .id() - .values() + .iter_values() .filter_map(|id| id.to_u64()) .collect::>(); e.sort(); @@ -1160,7 +1160,7 @@ mod views_test { let actual = wg .nodes() .id() - .values() + .iter_values() .filter_map(|id| id.to_u64()) .collect::>(); @@ -1274,14 +1274,19 @@ mod views_test { graph .nodes() .earliest_time() - .values() + .iter_values() .flatten() .collect_vec(), [0, 0, 0, 4,] ); assert_eq!( - graph.nodes().latest_time().values().flatten().collect_vec(), + graph + .nodes() + .latest_time() + .iter_values() + .flatten() + .collect_vec(), [3, 7, 3, 7] ); diff --git a/raphtory/src/disk_graph/graph_impl/interop.rs b/raphtory/src/disk_graph/graph_impl/interop.rs index a790617d39..655097ccf6 100644 --- a/raphtory/src/disk_graph/graph_impl/interop.rs +++ b/raphtory/src/disk_graph/graph_impl/interop.rs @@ -30,7 +30,7 @@ impl GraphLike for Graph { } fn node_names(&self) -> impl Iterator { - self.nodes().name().into_values() + self.nodes().name().into_iter_values() } fn node_type_ids(&self) -> Option> { diff --git a/raphtory/src/disk_graph/graph_impl/mod.rs b/raphtory/src/disk_graph/graph_impl/mod.rs index d5af191401..937450b26a 100644 --- a/raphtory/src/disk_graph/graph_impl/mod.rs +++ b/raphtory/src/disk_graph/graph_impl/mod.rs @@ -179,18 +179,18 @@ mod test { // let expected = 1; // assert_eq!(actual, expected); - let out_v_deg = w_g.nodes().out_degree().values().collect::>(); + let out_v_deg = w_g.nodes().out_degree().iter_values().collect::>(); assert_eq!(out_v_deg, vec![1, 0]); let w_g = g.window(-2, 0); - let out_v_deg = w_g.nodes().out_degree().values().collect::>(); + let out_v_deg = w_g.nodes().out_degree().iter_values().collect::>(); assert_eq!(out_v_deg, vec![2, 0]); let w_g = g.window(-2, 4); - let out_v_deg = w_g.nodes().out_degree().values().collect::>(); + let out_v_deg = w_g.nodes().out_degree().iter_values().collect::>(); assert_eq!(out_v_deg, vec![4, 0, 0, 0]); - let in_v_deg = w_g.nodes().in_degree().values().collect::>(); + let in_v_deg = w_g.nodes().in_degree().iter_values().collect::>(); assert_eq!(in_v_deg, vec![1, 1, 1, 1]); } diff --git a/raphtory/src/graphgen/preferential_attachment.rs b/raphtory/src/graphgen/preferential_attachment.rs index e93b4122f0..534704cc6f 100644 --- a/raphtory/src/graphgen/preferential_attachment.rs +++ b/raphtory/src/graphgen/preferential_attachment.rs @@ -65,8 +65,8 @@ pub fn ba_preferential_attachment( } let mut latest_time = graph.latest_time().unwrap_or(0); let view = graph; - let mut ids = graph.nodes().id().values().collect::>(); - let mut degrees: Vec = view.nodes().degree().values().collect(); + let mut ids = graph.nodes().id().iter_values().collect::>(); + let mut degrees: Vec = view.nodes().degree().iter_values().collect(); let mut edge_count: usize = degrees.iter().sum(); let mut max_id = next_id(view, ids.iter().max().cloned()); diff --git a/raphtory/src/graphgen/random_attachment.rs b/raphtory/src/graphgen/random_attachment.rs index 9822d9f634..e821e27054 100644 --- a/raphtory/src/graphgen/random_attachment.rs +++ b/raphtory/src/graphgen/random_attachment.rs @@ -61,7 +61,7 @@ pub fn random_attachment( rng = StdRng::from_entropy(); } let mut latest_time = graph.latest_time().unwrap_or(0); - let mut ids = graph.nodes().id().values().collect::>(); + let mut ids = graph.nodes().id().iter_values().collect::>(); let mut max_id = next_id(graph, ids.iter().max().cloned()); while ids.len() < edges_per_step { diff --git a/raphtory/src/io/json_loader.rs b/raphtory/src/io/json_loader.rs index 9c472f418e..0b18c0d160 100644 --- a/raphtory/src/io/json_loader.rs +++ b/raphtory/src/io/json_loader.rs @@ -315,7 +315,7 @@ mod tests { .expect("Unable to add node to graph"); assert_eq!(g.count_nodes(), 3); assert_eq!(g.count_edges(), 0); - let mut names = g.nodes().name().values().collect::>(); + let mut names = g.nodes().name().iter_values().collect::>(); names.sort(); assert_eq!(names, vec!["test", "testbz", "testgz"]); } diff --git a/raphtory/src/python/graph/node.rs b/raphtory/src/python/graph/node.rs index 8953067707..786d4ec0fb 100644 --- a/raphtory/src/python/graph/node.rs +++ b/raphtory/src/python/graph/node.rs @@ -614,7 +614,7 @@ impl PyNodes { #[getter] fn properties(&self) -> PyPropsList { let nodes = self.nodes.clone(); - (move || nodes.properties().into_values()).into() + (move || nodes.properties().into_iter_values()).into() } /// Returns the number of edges of the nodes diff --git a/raphtory/src/python/graph/node_state/node_state.rs b/raphtory/src/python/graph/node_state/node_state.rs index 9c1054ae82..92d420301f 100644 --- a/raphtory/src/python/graph/node_state/node_state.rs +++ b/raphtory/src/python/graph/node_state/node_state.rs @@ -33,7 +33,7 @@ macro_rules! impl_node_state_ops { ($name:ident, $value:ty, $inner_t:ty, $to_owned:expr, $computed:literal, $py_value:literal) => { impl $name { pub fn iter(&self) -> impl Iterator + '_ { - self.inner.values().map($to_owned) + self.inner.iter_values().map($to_owned) } } @@ -53,7 +53,7 @@ macro_rules! impl_node_state_ops { fn __iter__(&self) -> PyBorrowingIterator { py_borrowing_iter!(self.inner.clone(), $inner_t, |inner| inner - .values() + .iter_values() .map($to_owned)) } @@ -225,9 +225,9 @@ macro_rules! impl_node_state_ord_ops { ) -> Result, std::convert::Infallible> { let res = if let Ok(other) = other.downcast::() { let other = Bound::borrow(other); - self.inner.values().eq(other.inner.values()) + self.inner.iter_values().eq(other.inner.iter_values()) } else if let Ok(other) = other.extract::>() { - self.inner.values().map($to_owned).eq(other.into_iter()) + self.inner.iter_values().map($to_owned).eq(other.into_iter()) } else if let Ok(other) = other.extract::>() { (self.inner.len() == other.len() && other.into_iter().all(|(node, value)| { From 290c7c7769ee52c0de1ecb2dcc2a9b84e8c9471c Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Tue, 14 Jan 2025 10:46:06 +0100 Subject: [PATCH 26/29] tidy --- python/tests/graphql/test_edge_sorting.py | 165 ++++++++++++---------- raphtory-graphql/src/model/graph/edge.rs | 1 - 2 files changed, 90 insertions(+), 76 deletions(-) diff --git a/python/tests/graphql/test_edge_sorting.py b/python/tests/graphql/test_edge_sorting.py index 8025a17b29..03ef7c87a4 100644 --- a/python/tests/graphql/test_edge_sorting.py +++ b/python/tests/graphql/test_edge_sorting.py @@ -104,6 +104,7 @@ def run_graphql_error_test(query, expected_error_message, graph): error_message == expected_error_message ), f"Expected '{expected_error_message}', but got '{error_message}'" + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_nothing(graph): query = """ @@ -129,11 +130,11 @@ def test_graph_edge_sort_by_nothing(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, ] } } @@ -141,6 +142,7 @@ def test_graph_edge_sort_by_nothing(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_src(graph): query = """ @@ -166,11 +168,11 @@ def test_graph_edge_sort_by_src(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, ] } } @@ -178,6 +180,7 @@ def test_graph_edge_sort_by_src(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_dst(graph): query = """ @@ -203,11 +206,11 @@ def test_graph_edge_sort_by_dst(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, ] } } @@ -215,6 +218,7 @@ def test_graph_edge_sort_by_dst(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_earliest_time(graph): query = """ @@ -240,11 +244,11 @@ def test_graph_edge_sort_by_earliest_time(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, ] } } @@ -252,6 +256,7 @@ def test_graph_edge_sort_by_earliest_time(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_earliest_time_reversed(graph): query = """ @@ -277,12 +282,12 @@ def test_graph_edge_sort_by_earliest_time_reversed(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "b" }, "dst": { "id": "c" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, + {"src": {"id": "b"}, "dst": {"id": "c"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, # C->D and A->B have the same time so will maintain their relative order - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, ] } } @@ -290,6 +295,7 @@ def test_graph_edge_sort_by_earliest_time_reversed(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph]) def test_graph_edge_sort_by_latest_time(graph): query = """ @@ -315,11 +321,11 @@ def test_graph_edge_sort_by_latest_time(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, ] } } @@ -327,6 +333,7 @@ def test_graph_edge_sort_by_latest_time(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [PersistentGraph]) def test_graph_edge_sort_by_latest_time_persistent_graph(graph): query = """ @@ -353,11 +360,11 @@ def test_graph_edge_sort_by_latest_time_persistent_graph(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, ] } } @@ -365,6 +372,7 @@ def test_graph_edge_sort_by_latest_time_persistent_graph(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_eprop1(graph): query = """ @@ -390,11 +398,11 @@ def test_graph_edge_sort_by_eprop1(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, ] } } @@ -402,6 +410,7 @@ def test_graph_edge_sort_by_eprop1(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_eprop2(graph): query = """ @@ -427,11 +436,11 @@ def test_graph_edge_sort_by_eprop2(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "b" }, "dst": { "id": "c" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, + {"src": {"id": "b"}, "dst": {"id": "c"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, ] } } @@ -439,6 +448,7 @@ def test_graph_edge_sort_by_eprop2(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_eprop3(graph): query = """ @@ -464,11 +474,11 @@ def test_graph_edge_sort_by_eprop3(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "b" }, "dst": { "id": "c" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, + {"src": {"id": "b"}, "dst": {"id": "c"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, ] } } @@ -476,6 +486,7 @@ def test_graph_edge_sort_by_eprop3(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_eprop4(graph): query = """ @@ -501,11 +512,11 @@ def test_graph_edge_sort_by_eprop4(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "b" }, "dst": { "id": "c" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, + {"src": {"id": "b"}, "dst": {"id": "c"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, ] } } @@ -513,6 +524,7 @@ def test_graph_edge_sort_by_eprop4(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_eprop5(graph): query = """ @@ -538,11 +550,11 @@ def test_graph_edge_sort_by_eprop5(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, ] } } @@ -550,6 +562,7 @@ def test_graph_edge_sort_by_eprop5(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_nonexistent_prop(graph): query = """ @@ -575,11 +588,11 @@ def test_graph_edge_sort_by_nonexistent_prop(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, ] } } @@ -587,6 +600,7 @@ def test_graph_edge_sort_by_nonexistent_prop(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_combined(graph): query = """ @@ -612,11 +626,11 @@ def test_graph_edge_sort_by_combined(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, ] } } @@ -624,6 +638,7 @@ def test_graph_edge_sort_by_combined(graph): } run_graphql_test(query, expected_output, graph()) + @pytest.mark.parametrize("graph", [Graph, PersistentGraph]) def test_graph_edge_sort_by_combined_2(graph): query = """ @@ -649,11 +664,11 @@ def test_graph_edge_sort_by_combined_2(graph): "edges": { "sorted": { "list": [ - {"src": { "id": "a" }, "dst": { "id": "b" } }, - {"src": { "id": "b" }, "dst": { "id": "c" } }, - {"src": { "id": "c" }, "dst": { "id": "d" } }, - {"src": { "id": "b" }, "dst": { "id": "d" } }, - {"src": { "id": "a" }, "dst": { "id": "d" } }, + {"src": {"id": "a"}, "dst": {"id": "b"}}, + {"src": {"id": "b"}, "dst": {"id": "c"}}, + {"src": {"id": "c"}, "dst": {"id": "d"}}, + {"src": {"id": "b"}, "dst": {"id": "d"}}, + {"src": {"id": "a"}, "dst": {"id": "d"}}, ] } } diff --git a/raphtory-graphql/src/model/graph/edge.rs b/raphtory-graphql/src/model/graph/edge.rs index ded23dc43c..2f66a1c30c 100644 --- a/raphtory-graphql/src/model/graph/edge.rs +++ b/raphtory-graphql/src/model/graph/edge.rs @@ -1,6 +1,5 @@ use crate::model::graph::{edges::GqlEdges, node::Node, property::GqlProperties}; use dynamic_graphql::{ResolvedObject, ResolvedObjectFields}; -use itertools::Itertools; use raphtory::{ core::utils::errors::GraphError, db::{ From 736d2c205d1ebf034074f38110adb261fa12ad24 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Tue, 14 Jan 2025 10:46:30 +0100 Subject: [PATCH 27/29] add sorting to tests since that is no longer guaranteed --- python/tests/test_graphdb/test_node_state.py | 6 ++--- raphtory/src/db/api/state/group_by.rs | 24 ++++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/python/tests/test_graphdb/test_node_state.py b/python/tests/test_graphdb/test_node_state.py index 43d03f48be..00135d7f94 100644 --- a/python/tests/test_graphdb/test_node_state.py +++ b/python/tests/test_graphdb/test_node_state.py @@ -40,12 +40,12 @@ def test_group_by(): 1: [1, 2, 4], } - assert {v: nodes.id for v, nodes in groups_from_lazy} == expected + assert {v: nodes.id.sorted() for v, nodes in groups_from_lazy} == expected - assert {v: nodes.id for v, nodes in groups_from_eager} == expected + assert {v: nodes.id.sorted() for v, nodes in groups_from_eager} == expected assert { - v: graph.nodes.id for v, graph in groups_from_lazy.iter_subgraphs() + v: graph.nodes.id.sorted() for v, graph in groups_from_lazy.iter_subgraphs() } == expected assert len(groups_from_lazy) == len(expected) diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index a872743a6d..f654b318d3 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -127,7 +127,7 @@ where #[cfg(test)] mod tests { use crate::{prelude::*, test_storage}; - use std::collections::HashMap; + use std::{collections::HashMap, sync::Arc}; #[test] fn test() { @@ -140,15 +140,15 @@ mod tests { let groups_from_lazy = g.nodes().out_degree().groups(); let groups_from_eager = g.nodes().out_degree().compute().groups(); - let expected = HashMap::from([ - (0, vec![GID::U64(3), GID::U64(5)]), - (1, vec![GID::U64(1), GID::U64(2), GID::U64(4)]), + let expected: HashMap> = HashMap::from([ + (0, Arc::from_iter([GID::U64(3), GID::U64(5)])), + (1, Arc::from_iter([GID::U64(1), GID::U64(2), GID::U64(4)])), ]); assert_eq!( groups_from_lazy .iter() - .map(|(v, nodes)| (*v, nodes.id().collect_vec())) + .map(|(v, nodes)| (*v, nodes.id().sort_by_values(false).values().clone())) .collect::>(), expected ); @@ -157,7 +157,7 @@ mod tests { groups_from_lazy .clone() .into_iter_groups() - .map(|(v, nodes)| (v, nodes.id().collect_vec())) + .map(|(v, nodes)| (v, nodes.id().sort_by_values(false).values().clone())) .collect::>(), expected ); @@ -165,7 +165,10 @@ mod tests { assert_eq!( groups_from_lazy .iter_subgraphs() - .map(|(v, graph)| (*v, graph.nodes().id().collect_vec())) + .map(|(v, graph)| ( + *v, + graph.nodes().id().sort_by_values(false).values().clone() + )) .collect::>(), expected ); @@ -174,7 +177,10 @@ mod tests { groups_from_lazy .clone() .into_iter_subgraphs() - .map(|(v, graph)| (v, graph.nodes().id().collect_vec())) + .map(|(v, graph)| ( + v, + graph.nodes().id().sort_by_values(false).values().clone() + )) .collect::>(), expected ); @@ -182,7 +188,7 @@ mod tests { assert_eq!( groups_from_eager .iter() - .map(|(v, nodes)| (*v, nodes.id().collect_vec())) + .map(|(v, nodes)| (*v, nodes.id().sort_by_values(false).values().clone())) .collect::>(), expected ); From 760df60808a5ecc24082164f4a1b1ca38c498fe6 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Tue, 14 Jan 2025 11:29:50 +0100 Subject: [PATCH 28/29] remove temporary vecs when creating Index --- Cargo.lock | 1 + Cargo.toml | 2 +- .../algorithms/components/in_components.rs | 4 +- .../algorithms/components/out_components.rs | 4 +- raphtory/src/db/api/state/group_by.rs | 6 +- raphtory/src/db/api/state/lazy_node_state.rs | 3 +- raphtory/src/db/api/state/node_state.rs | 18 ++-- raphtory/src/db/api/state/node_state_ops.rs | 87 +++++++++---------- raphtory/src/db/graph/views/node_subgraph.rs | 4 +- raphtory/src/db/graph/views/window_graph.rs | 2 +- 10 files changed, 71 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1d606598f..d38ce8b3c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2906,6 +2906,7 @@ checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.2", + "rayon", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 7bd6d2221f..7efbdd47f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -149,4 +149,4 @@ arrow-buffer = { version = "53.2.0" } arrow-schema = { version = "53.2.0" } arrow-array = { version = "53.2.0" } moka = { version = "0.12.7", features = ["sync"] } -indexmap = "2.7.0" +indexmap = { version = "2.7.0", features = ["rayon"] } diff --git a/raphtory/src/algorithms/components/in_components.rs b/raphtory/src/algorithms/components/in_components.rs index d26e2c493d..6841b22ba0 100644 --- a/raphtory/src/algorithms/components/in_components.rs +++ b/raphtory/src/algorithms/components/in_components.rs @@ -19,6 +19,7 @@ use crate::{ }, prelude::GraphViewOps, }; +use indexmap::IndexSet; use itertools::Itertools; use std::collections::{hash_map::Entry, HashMap, HashSet, VecDeque}; @@ -130,7 +131,8 @@ pub fn in_component<'graph, G: GraphViewOps<'graph>>( } } - let (nodes, distances): (Vec<_>, Vec<_>) = in_components.into_iter().sorted().unzip(); + let (nodes, distances): (IndexSet<_, ahash::RandomState>, Vec<_>) = + in_components.into_iter().sorted().unzip(); NodeState::new( node.graph.clone(), node.graph.clone(), diff --git a/raphtory/src/algorithms/components/out_components.rs b/raphtory/src/algorithms/components/out_components.rs index 519d46a7c2..855e213a71 100644 --- a/raphtory/src/algorithms/components/out_components.rs +++ b/raphtory/src/algorithms/components/out_components.rs @@ -16,6 +16,7 @@ use crate::{ }, prelude::GraphViewOps, }; +use indexmap::IndexSet; use itertools::Itertools; use raphtory_api::core::entities::GID; use rayon::prelude::*; @@ -133,7 +134,8 @@ pub fn out_component<'graph, G: GraphViewOps<'graph>>( } } - let (nodes, distances): (Vec<_>, Vec<_>) = out_components.into_iter().sorted().unzip(); + let (nodes, distances): (IndexSet<_, ahash::RandomState>, Vec<_>) = + out_components.into_iter().sorted().unzip(); NodeState::new( node.graph.clone(), node.graph.clone(), diff --git a/raphtory/src/db/api/state/group_by.rs b/raphtory/src/db/api/state/group_by.rs index f654b318d3..c4f200e4fa 100644 --- a/raphtory/src/db/api/state/group_by.rs +++ b/raphtory/src/db/api/state/group_by.rs @@ -6,6 +6,7 @@ use crate::{ prelude::{GraphViewOps, NodeStateOps}, }; use dashmap::DashMap; +use indexmap::IndexSet; use raphtory_api::core::entities::VID; use rayon::prelude::*; use std::{hash::Hash, sync::Arc}; @@ -18,9 +19,10 @@ pub struct NodeGroups { impl<'graph, V: Hash + Eq + Send + Sync + Clone, G: GraphViewOps<'graph>> NodeGroups { pub(crate) fn new(values: impl ParallelIterator, graph: G) -> Self { - let groups: DashMap, ahash::RandomState> = DashMap::default(); + let groups: DashMap, ahash::RandomState> = + DashMap::default(); values.for_each(|(node, v)| { - groups.entry(v).or_insert_with(Vec::new).push(node); + groups.entry(v).or_default().insert(node); }); let groups = groups diff --git a/raphtory/src/db/api/state/lazy_node_state.rs b/raphtory/src/db/api/state/lazy_node_state.rs index fab4e21ce2..7d2d085d18 100644 --- a/raphtory/src/db/api/state/lazy_node_state.rs +++ b/raphtory/src/db/api/state/lazy_node_state.rs @@ -15,6 +15,7 @@ use crate::{ }, prelude::*, }; +use indexmap::IndexSet; use rayon::prelude::*; use std::fmt::{Debug, Formatter}; @@ -93,7 +94,7 @@ impl<'graph, Op: NodeOp + 'graph, G: GraphViewOps<'graph>, GH: GraphViewOps<'gra pub fn compute(&self) -> NodeState<'graph, Op::Output, G, GH> { if self.nodes.is_filtered() { - let (keys, values): (Vec<_>, Vec<_>) = self + let (keys, values): (IndexSet<_, ahash::RandomState>, Vec<_>) = self .par_iter() .map(|(node, value)| (node.node, value)) .unzip(); diff --git a/raphtory/src/db/api/state/node_state.rs b/raphtory/src/db/api/state/node_state.rs index 4b2357770f..398490bb07 100644 --- a/raphtory/src/db/api/state/node_state.rs +++ b/raphtory/src/db/api/state/node_state.rs @@ -13,11 +13,19 @@ use indexmap::IndexSet; use rayon::{iter::Either, prelude::*}; use std::{fmt::Debug, hash::Hash, marker::PhantomData, sync::Arc}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct Index { index: Arc>, } +impl + From + Send + Sync> FromIterator for Index { + fn from_iter>(iter: T) -> Self { + Self { + index: Arc::new(IndexSet::from_iter(iter)), + } + } +} + impl Index { pub fn for_graph<'graph>(graph: impl GraphViewOps<'graph>) -> Option { if graph.nodes_filtered() { @@ -27,7 +35,7 @@ impl Index { NodeList::List { nodes } => Some(nodes), } } else { - Some(Self::new(graph.nodes().iter().map(|node| node.node))) + Some(Self::from_iter(graph.nodes().iter().map(|node| node.node))) } } else { None @@ -36,10 +44,8 @@ impl Index { } impl + From + Send + Sync> Index { - pub fn new(keys: impl IntoIterator) -> Self { - Self { - index: Arc::new(IndexSet::from_iter(keys)), - } + pub fn new(keys: impl Into>>) -> Self { + Self { index: keys.into() } } #[inline] diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index 3e57aede75..10b6533902 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -1,16 +1,16 @@ use crate::{ core::entities::nodes::node_ref::AsNodeRef, db::{ - api::state::{group_by::NodeGroups, node_state::NodeState, node_state_ord_ops, Index}, + api::{ + state::{group_by::NodeGroups, node_state::NodeState, node_state_ord_ops, Index}, + }, graph::{node::NodeView, nodes::Nodes}, }, prelude::{GraphViewOps, NodeViewOps}, }; +use indexmap::IndexSet; use num_traits::AsPrimitive; -use rayon::{ - iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}, - prelude::ParallelSliceMut, -}; +use rayon::prelude::*; use std::{borrow::Borrow, hash::Hash, iter::Sum}; pub trait NodeStateOps<'graph>: @@ -73,6 +73,40 @@ pub trait NodeStateOps<'graph>: fn len(&self) -> usize; + fn sort_by< + F: Fn( + (NodeView<&Self::BaseGraph, &Self::Graph>, &Self::OwnedValue), + (NodeView<&Self::BaseGraph, &Self::Graph>, &Self::OwnedValue), + ) -> std::cmp::Ordering + + Sync, + >( + &self, + cmp: F, + ) -> NodeState<'graph, Self::OwnedValue, Self::BaseGraph, Self::Graph> { + let mut state: Vec<_> = self + .par_iter() + .map(|(n, v)| (n.node, v.borrow().clone())) + .collect(); + let graph = self.graph(); + let base_graph = self.base_graph(); + state.par_sort_by(|(n1, v1), (n2, v2)| { + cmp( + (NodeView::new_one_hop_filtered(base_graph, graph, *n1), v1), + (NodeView::new_one_hop_filtered(base_graph, graph, *n2), v2), + ) + }); + + let (keys, values): (IndexSet<_, ahash::RandomState>, Vec<_>) = + state.into_par_iter().unzip(); + + NodeState::new( + self.base_graph().clone(), + self.graph().clone(), + values.into(), + Some(Index::new(keys)), + ) + } + /// Sorts the by its values in ascending or descending order. /// /// Arguments: @@ -88,49 +122,12 @@ pub trait NodeStateOps<'graph>: &self, cmp: F, ) -> NodeState<'graph, Self::OwnedValue, Self::BaseGraph, Self::Graph> { - { - let mut state: Vec<_> = self - .par_iter() - .map(|(n, v)| (n.node, v.borrow().clone())) - .collect(); - state.par_sort_by(|(_, v1), (_, v2)| cmp(v1, v2)); - - let mut keys = Vec::with_capacity(state.len()); - let mut values = Vec::with_capacity(state.len()); - state - .into_par_iter() - .unzip_into_vecs(&mut keys, &mut values); - - NodeState::new( - self.base_graph().clone(), - self.graph().clone(), - values.into(), - Some(Index::new(keys)), - ) - } + self.sort_by(|(_, v1), (_, v2)| cmp(v1, v2)) } /// Sort the results by global node id fn sort_by_id(&self) -> NodeState<'graph, Self::OwnedValue, Self::BaseGraph, Self::Graph> { - let mut state: Vec<_> = self - .par_iter() - .map(|(n, v)| (n.id(), n.node, v.borrow().clone())) - .collect(); - state.par_sort_by(|(l_id, l_n, _), (r_id, r_n, _)| (l_id, l_n).cmp(&(r_id, r_n))); - - let mut keys = Vec::with_capacity(state.len()); - let mut values = Vec::with_capacity(state.len()); - state - .into_par_iter() - .map(|(_, n, v)| (n, v)) - .unzip_into_vecs(&mut keys, &mut values); - - NodeState::new( - self.base_graph().clone(), - self.graph().clone(), - values.into(), - Some(Index::new(keys)), - ) + self.sort_by(|(n1, _), (n2, _)| n1.id().cmp(&n2.id())) } /// Retrieves the top-k elements from the `AlgorithmResult` based on its values. @@ -157,7 +154,7 @@ pub trait NodeStateOps<'graph>: |(_, v1), (_, v2)| cmp(v1.borrow(), v2.borrow()), k, ); - let (keys, values): (Vec<_>, Vec<_>) = values + let (keys, values): (IndexSet<_, ahash::RandomState>, Vec<_>) = values .into_iter() .map(|(n, v)| (n.node, v.borrow().clone())) .unzip(); diff --git a/raphtory/src/db/graph/views/node_subgraph.rs b/raphtory/src/db/graph/views/node_subgraph.rs index ed2f88f3e6..04722f5c6c 100644 --- a/raphtory/src/db/graph/views/node_subgraph.rs +++ b/raphtory/src/db/graph/views/node_subgraph.rs @@ -55,9 +55,9 @@ impl<'graph, G: GraphViewOps<'graph>> NodeSubgraph { .into_iter() .flat_map(|v| graph.internalise_node(v.as_node_ref())); let nodes = if graph.nodes_filtered() { - Index::new(nodes.filter(|n| graph.has_node(*n))) + Index::from_iter(nodes.filter(|n| graph.has_node(*n))) } else { - Index::new(nodes) + Index::from_iter(nodes) }; Self { graph, nodes } } diff --git a/raphtory/src/db/graph/views/window_graph.rs b/raphtory/src/db/graph/views/window_graph.rs index eda93c3dff..f7f330d4d0 100644 --- a/raphtory/src/db/graph/views/window_graph.rs +++ b/raphtory/src/db/graph/views/window_graph.rs @@ -140,7 +140,7 @@ impl<'graph, G: GraphViewOps<'graph>> ListOps for WindowedGraph { fn node_list(&self) -> NodeList { if self.window_is_empty() { NodeList::List { - nodes: Index::new(vec![]), + nodes: Index::default(), } } else { self.graph.node_list() From 03f82622703c9aa81671acf24d0309775bfbee10 Mon Sep 17 00:00:00 2001 From: Lucas Jeub Date: Tue, 14 Jan 2025 11:36:07 +0100 Subject: [PATCH 29/29] fmt --- raphtory/src/db/api/state/node_state_ops.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/raphtory/src/db/api/state/node_state_ops.rs b/raphtory/src/db/api/state/node_state_ops.rs index 10b6533902..fdf4a2b4f3 100644 --- a/raphtory/src/db/api/state/node_state_ops.rs +++ b/raphtory/src/db/api/state/node_state_ops.rs @@ -1,9 +1,7 @@ use crate::{ core::entities::nodes::node_ref::AsNodeRef, db::{ - api::{ - state::{group_by::NodeGroups, node_state::NodeState, node_state_ord_ops, Index}, - }, + api::state::{group_by::NodeGroups, node_state::NodeState, node_state_ord_ops, Index}, graph::{node::NodeView, nodes::Nodes}, }, prelude::{GraphViewOps, NodeViewOps},