Skip to content

Commit

Permalink
fix property aggregation methods (#1578)
Browse files Browse the repository at this point in the history
* fix property aggregation methods

* clean up the implementations and try to fix lists of lengths one
  • Loading branch information
ljeub-pometry authored Apr 30, 2024
1 parent d84fac4 commit edd44e5
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 340 deletions.
36 changes: 18 additions & 18 deletions python/tests/test_iterables.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,20 @@ def test_empty_lists():
for src, dst, val, time in edges_str:
g.add_edge(time, src, dst, {"value_dec": val})
assert (
g.nodes.out_edges.properties.temporal.get("value_dec")
.values()
.median()
.median()
.median()
== 5
g.nodes.out_edges.properties.temporal.get("value_dec")
.values()
.median()
.median()
.median()
== 5
)
assert (
g.nodes.out_edges.properties.temporal.get("value_dec")
.values()
.mean()
.mean()
.mean()
== 1.3333333333333335
int(g.nodes.out_edges.properties.temporal.get("value_dec")
.values()
.mean()
.mean()
.mean() * 100)
== 616
)


Expand Down Expand Up @@ -157,13 +157,13 @@ def test_propiterable():
assert sorted(total) == [3, 5, 15, 32]

total = g.nodes.out_edges.properties.get("value_dec").median()
assert list(total) == [10, 5, 10, 2, None]
assert list(total) == [10, 5, 5, 1, None]

total = g.node("1").in_edges.properties.get("value_dec").sum()
assert total == 6

total = g.node("1").in_edges.properties.get("value_dec").median()
assert total == 5
assert total == 1


def test_pypropvalue_list_listlist():
Expand Down Expand Up @@ -197,7 +197,7 @@ def test_pypropvalue_list_listlist():

assert res.median() == 5
assert res_v.median() == 5
assert res_ll.median() == [5, 5, 10, 5, 5]
assert res_ll.median() == [5, 5, 10, 2, 5]

assert res.min() == 1
assert res_v.min() == 1
Expand All @@ -214,9 +214,9 @@ def test_pypropvalue_list_listlist():
assert res.mean() == res.average() == 18.5
assert res_v.mean() == res_v.average() == 26.2
assert (
res_ll.mean()
== res_ll.average()
== [26.2, 35.666666666666664, 11.666666666666666, 4.5, 5.0]
res_ll.mean()
== res_ll.average()
== [26.2, 35.666666666666664, 11.666666666666666, 4.5, 5.0]
)


Expand Down
82 changes: 81 additions & 1 deletion raphtory/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use std::{
ops::Deref,
sync::Arc,
};
use thiserror::Error;

Check warning on line 40 in raphtory/src/core/mod.rs

View workflow job for this annotation

GitHub Actions / Run benchmarks / Rust Benchmark (ubuntu-latest)

unused import: `thiserror::Error`

#[cfg(test)]
extern crate core;
Expand Down Expand Up @@ -172,6 +173,46 @@ pub enum PropType {
DTime,
}

impl PropType {
pub fn is_numeric(&self) -> bool {
matches!(
self,
PropType::U8
| PropType::U16
| PropType::U32
| PropType::U64
| PropType::I32
| PropType::I64
| PropType::F32
| PropType::F64
)
}

pub fn is_str(&self) -> bool {
matches!(self, PropType::Str)
}

pub fn is_bool(&self) -> bool {
matches!(self, PropType::Bool)
}

pub fn is_date(&self) -> bool {
matches!(self, PropType::DTime | PropType::NDTime)
}

pub fn has_add(&self) -> bool {
self.is_numeric() || self.is_str()
}

pub fn has_divide(&self) -> bool {
self.is_numeric()
}

pub fn has_cmp(&self) -> bool {
self.is_bool() || self.is_numeric() || self.is_str() || self.is_date()
}
}

/// Denotes the types of properties allowed to be stored in the graph.
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum Prop {
Expand Down Expand Up @@ -207,6 +248,7 @@ impl PartialOrd for Prop {
(Prop::F64(a), Prop::F64(b)) => a.partial_cmp(b),
(Prop::Bool(a), Prop::Bool(b)) => a.partial_cmp(b),
(Prop::NDTime(a), Prop::NDTime(b)) => a.partial_cmp(b),
(Prop::DTime(a), Prop::DTime(b)) => a.partial_cmp(b),
_ => None,
}
}
Expand Down Expand Up @@ -283,6 +325,22 @@ impl Prop {
}
}

pub fn min(self, other: Prop) -> Option<Prop> {
self.partial_cmp(&other).map(|ord| match ord {
Ordering::Less => self,
Ordering::Equal => self,
Ordering::Greater => other,
})
}

pub fn max(self, other: Prop) -> Option<Prop> {
self.partial_cmp(&other).map(|ord| match ord {
Ordering::Less => other,
Ordering::Equal => self,
Ordering::Greater => self,
})
}

pub fn divide(self, other: Prop) -> Option<Prop> {
match (self, other) {
(Prop::U8(a), Prop::U8(b)) if b != 0 => Some(Prop::U8(a / b)),
Expand All @@ -296,6 +354,20 @@ impl Prop {
_ => None,
}
}

pub fn as_f64(&self) -> Option<f64> {
match self {
Prop::U8(v) => Some(*v as f64),
Prop::U16(v) => Some(*v as f64),
Prop::I32(v) => Some(*v as f64),
Prop::I64(v) => Some(*v as f64),
Prop::U32(v) => Some(*v as f64),
Prop::U64(v) => Some(*v as f64),
Prop::F32(v) => Some(*v as f64),
Prop::F64(v) => Some(*v as f64),
_ => None,
}
}
}

pub trait PropUnwrap: Sized {
Expand Down Expand Up @@ -786,7 +858,7 @@ mod serde_value_into_prop {

#[cfg(test)]
mod test_arc_str {
use crate::core::{ArcStr, OptionAsStr};
use crate::core::{ArcStr, OptionAsStr, Prop};
use std::sync::Arc;

#[test]
Expand Down Expand Up @@ -814,4 +886,12 @@ mod test_arc_str {
assert_eq!(opt_str_2, Some("test"));
assert_eq!(opt_str3, Some("test"));
}

#[test]
fn test_prop_min_max() {
let v1 = Prop::I64(4);
let v2 = Prop::I64(2);
assert_eq!(v1.clone().max(v2.clone()), Some(Prop::I64(4)));
assert_eq!((v1.min(v2)), Some(Prop::I64(2)));
}
}
Loading

0 comments on commit edd44e5

Please sign in to comment.