diff --git a/clam-core b/clam-core new file mode 160000 index 0000000000..5e10a79ded --- /dev/null +++ b/clam-core @@ -0,0 +1 @@ +Subproject commit 5e10a79ded1a39830426b3c2def7de25598203b3 diff --git a/optd b/optd new file mode 160000 index 0000000000..4099009d3b --- /dev/null +++ b/optd @@ -0,0 +1 @@ +Subproject commit 4099009d3bf67d7591b006afc0908077c980fde2 diff --git a/python/Cargo.toml b/python/Cargo.toml index a88d5f460d..b1bcf17fc3 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -26,6 +26,7 @@ raphtory = { workspace = true, features = [ raphtory-graphql = { workspace = true, features = [ "python", ] } +clam-core = { workspace = true, features = ["python"] } [features] extension-module = ["pyo3/extension-module"] diff --git a/python/python/raphtory/__init__.py b/python/python/raphtory/__init__.py index 95e7905eaf..3e1a47ff84 100644 --- a/python/python/raphtory/__init__.py +++ b/python/python/raphtory/__init__.py @@ -7,6 +7,7 @@ _sys.modules["raphtory.graph_loader"] = graph_loader _sys.modules["raphtory.vectors"] = vectors _sys.modules["raphtory.graphql"] = graphql +_sys.modules["raphtory.gql"] = gql _sys.modules["raphtory.filter"] = filter _sys.modules["raphtory.iterables"] = iterables diff --git a/python/src/lib.rs b/python/src/lib.rs index 7e77ec8709..b1707254b5 100644 --- a/python/src/lib.rs +++ b/python/src/lib.rs @@ -8,6 +8,7 @@ use raphtory::python::{ }, }; use raphtory_graphql::python::pymodule::base_graphql_module; +use clam_core::python::py_gql::base_gql_module; /// Raphtory graph analytics library #[pymodule] @@ -15,6 +16,7 @@ fn _raphtory(py: Python<'_>, m: &Bound) -> PyResult<()> { let _ = add_raphtory_classes(m); let graphql_module = base_graphql_module(py)?; + let gql_module = base_gql_module(py)?; let algorithm_module = base_algorithm_module(py)?; let graph_loader_module = base_graph_loader_module(py)?; let graph_gen_module = base_graph_gen_module(py)?; @@ -23,6 +25,7 @@ fn _raphtory(py: Python<'_>, m: &Bound) -> PyResult<()> { let filter_module = base_filter_module(py)?; let iterables = base_iterables_module(py)?; m.add_submodule(&graphql_module)?; + m.add_submodule(&gql_module)?; m.add_submodule(&algorithm_module)?; m.add_submodule(&graph_loader_module)?; m.add_submodule(&graph_gen_module)?; diff --git a/raphtory-itertools/Cargo.toml b/raphtory-itertools/Cargo.toml new file mode 100644 index 0000000000..0098255b68 --- /dev/null +++ b/raphtory-itertools/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "raphtory-itertools" +version.workspace = true +documentation.workspace = true +repository.workspace = true +license.workspace = true +readme.workspace = true +homepage.workspace = true +keywords.workspace = true +authors.workspace = true +rust-version.workspace = true +edition.workspace = true diff --git a/raphtory-itertools/src/lib.rs b/raphtory-itertools/src/lib.rs new file mode 100644 index 0000000000..06b76e7508 --- /dev/null +++ b/raphtory-itertools/src/lib.rs @@ -0,0 +1,3 @@ +mod take; + +pub use take::{ReTake, TakeExt}; diff --git a/raphtory-itertools/src/take.rs b/raphtory-itertools/src/take.rs new file mode 100644 index 0000000000..b50589bf27 --- /dev/null +++ b/raphtory-itertools/src/take.rs @@ -0,0 +1,136 @@ +use std::{cmp, iter::FusedIterator}; + +/// An iterator that only iterates over the first `n` iterations of `iter`. +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +pub struct ReTake { + iter: I, + n: usize, +} + +pub trait TakeExt: Sized { + fn take_updatable(self, n: usize) -> ReTake; +} + +impl TakeExt for I { + fn take_updatable(self, n: usize) -> ReTake { + ReTake { iter: self, n } + } +} + +impl ReTake { + /// Take the first n elements of the iterator by updating the current take + pub fn take_inplace(&mut self, n: usize) { + self.n = self.n.min(n); + } + + /// Advance the iterator by n elements + pub fn advance_by(&mut self, n: usize) { + if let Some(to_skip) = n.min(self.n).checked_sub(1) { + self.iter.nth(to_skip); + } + self.n = self.n.saturating_sub(n); + } +} + +impl Iterator for ReTake +where + I: Iterator, +{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + if self.n != 0 { + self.n -= 1; + self.iter.next() + } else { + None + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + if self.n > n { + self.n -= n + 1; + self.iter.nth(n) + } else { + if self.n > 0 { + self.iter.nth(self.n - 1); + self.n = 0; + } + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.n == 0 { + return (0, Some(0)); + } + + let (lower, upper) = self.iter.size_hint(); + + let lower = cmp::min(lower, self.n); + + let upper = match upper { + Some(x) if x < self.n => Some(x), + _ => Some(self.n), + }; + + (lower, upper) + } +} + +impl DoubleEndedIterator for ReTake +where + I: DoubleEndedIterator + ExactSizeIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + if self.n == 0 { + None + } else { + let n = self.n; + self.n -= 1; + self.iter.nth_back(self.iter.len().saturating_sub(n)) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.iter.len(); + if self.n > n { + let m = len.saturating_sub(self.n) + n; + self.n -= n + 1; + self.iter.nth_back(m) + } else { + if len > 0 { + self.iter.nth_back(len - 1); + } + None + } + } + + #[inline] + fn rfold(mut self, init: Acc, fold: Fold) -> Acc + where + Self: Sized, + Fold: FnMut(Acc, Self::Item) -> Acc, + { + if self.n == 0 { + init + } else { + let len = self.iter.len(); + if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { + init + } else { + self.iter.rfold(init, fold) + } + } + } +} + +impl ExactSizeIterator for ReTake where I: ExactSizeIterator {} + +impl FusedIterator for ReTake where I: FusedIterator {} diff --git a/ui-tests b/ui-tests index ae682bd989..928e576b13 160000 --- a/ui-tests +++ b/ui-tests @@ -1 +1 @@ -Subproject commit ae682bd989d90bc73db4220b9df23191be1e406c +Subproject commit 928e576b134086cf04c714d253282b8f472ea4f0