Skip to content
This repository has been archived by the owner on Apr 26, 2023. It is now read-only.

Commit

Permalink
Tidy up the python APIs (#106)
Browse files Browse the repository at this point in the history
* Exposed more functions on the graph_window

* Corrected src and dst on windowed edges python

* Added latest just for demos

* brought Time APIs inline

* Fixed tests

* Final changes

* Fixed python test
  • Loading branch information
miratepuffin authored Mar 19, 2023
1 parent a4f6dd6 commit 11ac128
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 157 deletions.
2 changes: 1 addition & 1 deletion docbrown/db/src/graph_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl Iterator for GraphWindowSet {

#[derive(Debug, Clone)]
pub struct WindowedGraph {
pub(crate) graph: Graph,
pub graph: Graph,
pub t_start: i64, // inclusive
pub t_end: i64, // exclusive
}
Expand Down
1 change: 1 addition & 0 deletions examples/rust/src/bin/lotr/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use docbrown_db::{csv_loader::csv::CsvLoader, graph::Graph};
use serde::Deserialize;
use std::path::PathBuf;
use std::{env, path::Path, time::Instant};
use docbrown_db::view_api::{GraphViewOps, VertexViewOps};

#[derive(Deserialize, std::fmt::Debug)]
pub struct Lotr {
Expand Down
186 changes: 119 additions & 67 deletions raphtory/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use pyo3::types::{PyInt, PyIterator, PyString};
use std::collections::HashMap;
use std::iter;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::Arc;

use crate::graph_window::{GraphWindowSet, WindowedGraph};
use crate::wrappers::{PerspectiveSet, Prop};
use crate::graph_window::{GraphWindowSet, WindowedEdge, WindowedGraph, WindowedVertex};
use crate::wrappers::{PerspectiveSet, Prop, VertexIdsIterator, WindowedEdgeIterator, WindowedVertices};
use crate::Perspective;

#[pyclass]
Expand All @@ -36,18 +37,78 @@ impl Graph {
}
}

pub fn earliest_time(&self) -> Option<i64> {
self.graph.earliest_time()
//****** Graph Updates ******//

pub fn add_vertex(&self, timestamp: i64, id: &PyAny, properties:Option<HashMap<String, Prop>>) {
let props = match properties {
None => {vec![]}
Some(p) => {
p.into_iter()
.map(|f| (f.0.clone(), f.1.into()))
.collect::<Vec<(String, dbc::Prop)>>()
}
};
if let Ok(vv) = id.extract::<String>() {
self.graph.add_vertex(
timestamp,
vv,
&props
)
} else {
if let Ok(vvv) = id.extract::<u64>() {
self.graph.add_vertex(
timestamp,
vvv,
&props
)
} else { println!("Input must be a string or integer.") }
}
}

pub fn latest_time(&self) -> Option<i64> {
self.graph.latest_time()

pub fn add_edge(&self, timestamp: i64, src: &PyAny, dst: &PyAny, properties: Option<HashMap<String, Prop>>) {
let props = match properties {
None => {vec![]}
Some(p) => {
p.into_iter()
.map(|f| (f.0.clone(), f.1.into()))
.collect::<Vec<(String, dbc::Prop)>>()
}
};
if let (Ok(src), Ok(dst)) = (src.extract::<String>(), dst.extract::<String>()) {
self.graph.add_edge(
timestamp,
src,
dst,
&props,
)
} else if let (Ok(src), Ok(dst)) = (src.extract::<u64>(), dst.extract::<u64>()) {
self.graph.add_edge(
timestamp,
src,
dst,
&props
)
} else {
println!("Types of src and dst must be the same (either Int or str)")
}
}

//****** Perspective APIS ******//

pub fn window(&self, t_start: i64, t_end: i64) -> WindowedGraph {
WindowedGraph::new(self, t_start, t_end)
}

pub fn at(&self, end: i64) -> WindowedGraph { self.graph.at(end).into() }

pub fn latest(&self) -> WindowedGraph {
match self.latest_time(){
None => self.at(0),
Some(time) => self.at(time)
}
}

fn through(&self, perspectives: &PyAny) -> PyResult<GraphWindowSet> {
struct PyPerspectiveIterator {
pub iter: Py<PyIterator>,
Expand Down Expand Up @@ -75,6 +136,8 @@ impl Graph {
Ok(result.into())
}

//****** Saving And Loading ******//

#[staticmethod]
pub fn load_from_file(path: String) -> PyResult<Self> {
let file_path: PathBuf = [env!("CARGO_MANIFEST_DIR"), &path].iter().collect();
Expand All @@ -98,26 +161,20 @@ impl Graph {
}
}

pub fn len(&self) -> usize {
self.graph.num_vertices()
}
//****** Metrics APIs ******//

pub fn edges_len(&self) -> usize {
self.graph.num_edges()
pub fn earliest_time(&self) -> Option<i64> {
self.graph.earliest_time()
}

pub fn number_of_edges(&self) -> usize {
self.graph.num_edges()
pub fn latest_time(&self) -> Option<i64> {
self.graph.latest_time()
}

pub fn num_edges(&self) -> usize {
self.graph.num_edges()
}

pub fn number_of_nodes(&self) -> usize {
self.graph.num_vertices()
}

pub fn num_vertices(&self) -> usize {
self.graph.num_vertices()
}
Expand All @@ -142,59 +199,54 @@ impl Graph {
self.graph
.has_edge(src, dst)
} else {
//FIXME This probably should just throw an error not fully panic
panic!("Types of src and dst must be the same (either Int or str)")
}
}

pub fn add_vertex(&self, t: i64, v: &PyAny, props: HashMap<String, Prop>) {
if let Ok(vv) = v.extract::<String>() {
self.graph.add_vertex(
t,
vv,
&props
.into_iter()
.map(|(key, value)| (key, value.into()))
.collect::<Vec<(String, dbc::Prop)>>(),
)
} else {
if let Ok(vvv) = v.extract::<u64>() {
self.graph.add_vertex(
t,
vvv,
&props
.into_iter()
.map(|(key, value)| (key, value.into()))
.collect::<Vec<(String, dbc::Prop)>>(),
)
} else { panic!("Input must be a string or integer.") }
}
}

pub fn at(&self, end: i64) -> WindowedGraph { self.graph.at(end).into() }
//****** Getter APIs ******//
//TODO Implement LatestVertex/Edge
//FIXME These are just placeholders for now and do not work because of the pyRef
// pub fn vertex(&self, v: u64) -> Option<WindowedVertex> {
// match self.latest_time(){
// None => None,
// Some(time) =>self.vertex(v)
// }
// }
//
// pub fn vertex_ids(&self) -> VertexIdsIterator {
// match self.latest_time(){
// None => { self.at(0).vertex_ids()
// },
// Some(time) => self.at(time).vertex_ids()
// }
// }
//slf: PyRef<'_, Self>
// pub fn vertices(&self) -> WindowedVertices {
// match self.latest_time(){
// None => {
// self.at(0).vertices()
// },
// Some(time) => self.at(time).vertices()
// }
// }
//
// pub fn edge(&self, src: u64, dst: u64) -> Option<WindowedEdge> {
// match self.latest_time(){
// None => {
// None
// },
// Some(time) => self.at(time).edge(src,dst)
// }
// }
//
// pub fn edges(&self) -> WindowedEdgeIterator {
// match self.latest_time(){
// None => {
// self.at(0).edges()
// },
// Some(time) => self.at(time).edges()
// }
// }

pub fn add_edge(&self, t: i64, src: &PyAny, dst: &PyAny, props: HashMap<String, Prop>) {
if let (Ok(src), Ok(dst)) = (src.extract::<String>(), dst.extract::<String>()) {
self.graph.add_edge(
t,
src,
dst,
&props
.into_iter()
.map(|f| (f.0.clone(), f.1.into()))
.collect::<Vec<(String, dbc::Prop)>>(),
)
} else if let (Ok(src), Ok(dst)) = (src.extract::<u64>(), dst.extract::<u64>()) {
self.graph.add_edge(
t,
src,
dst,
&props
.into_iter()
.map(|f| (f.0.clone(), f.1.into()))
.collect::<Vec<(String, dbc::Prop)>>(),
)
} else {
panic!("Types of src and dst must be the same (either Int or str)")
}
}
}
57 changes: 36 additions & 21 deletions raphtory/src/graph_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ impl WindowedGraph {
}
}

pub fn earliest_time(&self) -> i64 {
self.graph_w.t_start
}
//****** Metrics APIs ******//

pub fn latest_time(&self) -> i64 {
self.graph_w.t_end
}
pub fn earliest_time(&self) -> Option<i64> { self.graph_w.earliest_time() }

pub fn latest_time(&self) -> Option<i64> { self.graph_w.latest_time() }

pub fn num_edges(&self) -> usize {self.graph_w.num_edges()}

pub fn num_vertices(&self) -> usize {self.graph_w.num_vertices()}

pub fn has_vertex(&self, v: &PyAny) -> bool {
if let Ok(v) = v.extract::<String>() {
Expand Down Expand Up @@ -92,10 +94,13 @@ impl WindowedGraph {
)
}
else {
//FIXME This probably should just throw an error not fully panic
panic!("Types of src and dst must be the same (either Int or str)")
}
}

//****** Getter APIs ******//

pub fn vertex(slf: PyRef<'_, Self>, v: u64) -> Option<WindowedVertex> {
let v = slf.graph_w.vertex(v)?;
let g: Py<Self> = slf.into();
Expand All @@ -116,6 +121,12 @@ impl WindowedGraph {
pub fn edge(&self, src: u64, dst: u64) -> Option<WindowedEdge> {
self.graph_w.edge(src, dst).map(|we| we.into())
}

pub fn edges(&self) -> WindowedEdgeIterator {
WindowedEdgeIterator {
iter: Box::new(self.graph_w.edges().map(|te| te.into())),
}
}
}

#[pyclass]
Expand All @@ -126,6 +137,15 @@ pub struct WindowedVertex {
pub(crate) vertex_w: graph_window::WindowedVertex,
}

//TODO need to implement but would need to change a lot of things
//Have to rely on internal from for the moment
// impl From<graph_window::WindowedVertex> for WindowedVertex {
// fn from(value: graph_window::WindowedVertex) ->WindowedVertex {
//
// }
// }


impl WindowedVertex {
fn from(&self, value: graph_window::WindowedVertex) -> WindowedVertex {
WindowedVertex {
Expand All @@ -149,6 +169,7 @@ impl WindowedVertex {

#[pymethods]
impl WindowedVertex {

pub fn prop(&self, name: String) -> Vec<(i64, Prop)> {
self.vertex_w
.prop(name)
Expand Down Expand Up @@ -251,27 +272,12 @@ impl WindowedVertex {

#[pyclass]
pub struct WindowedEdge {
pub edge_id: usize,
#[pyo3(get)]
pub src: u64,
#[pyo3(get)]
pub dst: u64,
#[pyo3(get)]
pub time: Option<i64>,
pub is_remote: bool,
pub(crate) edge_w: graph_window::WindowedEdge,
}

impl From<graph_window::WindowedEdge> for WindowedEdge {
fn from(value: graph_window::WindowedEdge) -> WindowedEdge {
let value_ref: EdgeRef = value.as_ref();
// FIXME: temporary hack, shouldn't really be copying all these values
WindowedEdge {
edge_id: value_ref.edge_id,
src: value_ref.src_g_id,
dst: value_ref.dst_g_id,
time: value_ref.time,
is_remote: value_ref.is_remote,
edge_w: value,
}
}
Expand All @@ -286,4 +292,13 @@ impl WindowedEdge {
.map(|(t, p)| (t, p.into()))
.collect_vec()
}
fn src(&self) -> u64 {
//FIXME can't currently return the WindowedVertex as can't create a Py<WindowedGraph>
self.edge_w.src().id()
}

fn dst(&self) -> u64 {
//FIXME can't currently return the WindowedVertex as can't create a Py<WindowedGraph>
self.edge_w.dst().id()
}
}
Loading

0 comments on commit 11ac128

Please sign in to comment.