Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ edition = "2024"

[dependencies]
csv = "1.4.0"
egg = "0.10.0"
libc = "0.2"
oxrdf = "0.3.3"
oxttl = "0.2.3"
spargebra = "0.4.6"
thiserror = "1.0"
rand = "0.8"
expect-test = "1.5.1"

[features]
regenerate-bindings = ["bindgen"]
Expand Down
5 changes: 5 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ fn regenerate_bindings() {
.allowlist_function("GrB_Vector_extractTuples_BOOL")
.allowlist_function("GrB_vxm")
.allowlist_item("LAGRAPH_MSG_LEN")
.allowlist_item("RPQMatrixOp")
.allowlist_type("RPQMatrixPlan")
.allowlist_type("LAGraph_Graph")
.allowlist_type("LAGraph_Kind")
.allowlist_function("LAGraph_CheckGraph")
Expand All @@ -83,6 +85,9 @@ fn regenerate_bindings() {
.allowlist_function("LAGraph_Delete")
.allowlist_function("LAGraph_Cached_AT")
.allowlist_function("LAGraph_MMRead")
.allowlist_function("LAGraph_RPQMatrix")
.allowlist_function("LAGraph_DestroyRpqMatrixPlan")
.allowlist_function("LAGraph_RPQMatrix_reduce")
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
})
Expand Down
56 changes: 51 additions & 5 deletions src/graph/inmemory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use std::{collections::HashMap, io::Read};

use crate::formats::mm::{load_mm_file, parse_index_map};
use crate::formats::{Csv, MatrixMarket};
use crate::graph::ReduceType;
use crate::{
graph::GraphSource,
lagraph_sys::{GrB_Index, GrB_Matrix, GrB_Matrix_free, LAGraph_Kind},
};

use super::{
Backend, Edge, GraphBuilder, GraphDecomposition, GraphError, LagraphGraph, ensure_grb_init,
ensure_grb_init, Backend, Edge, GraphBuilder, GraphDecomposition, GraphError, LagraphGraph,
};

/// Marker type for the in-memory GraphBLAS-backed backend.
Expand Down Expand Up @@ -141,8 +142,20 @@ impl GraphBuilder for InMemoryBuilder {

let mut graphs: HashMap<String, Arc<LagraphGraph>> =
HashMap::with_capacity(self.label_buffers.len() + self.prebuilt.len());
let mut catalog: HashMap<String, GraphMetadata> =
HashMap::with_capacity(self.label_buffers.len() + self.prebuilt.len());

for (label, lg) in self.prebuilt {
let rreduce = lg.reduces_nvals(ReduceType::ReduceByRows)? as usize;
let creduce = lg.reduces_nvals(ReduceType::ReduceByCols)? as usize;
catalog.insert(
label.clone(),
GraphMetadata {
// num_vertices: nrows,
row_projections: rreduce,
column_projections: creduce,
},
);
graphs.insert(label, Arc::new(lg));
}

Expand All @@ -159,22 +172,43 @@ impl GraphBuilder for InMemoryBuilder {
LAGraph_Kind::LAGraph_ADJACENCY_DIRECTED,
)?;

let rreduce = lg.reduces_nvals(ReduceType::ReduceByRows)? as usize;
let creduce = lg.reduces_nvals(ReduceType::ReduceByCols)? as usize;
catalog.insert(
label.clone(),
GraphMetadata {
// num_vertices: nrows,
row_projections: rreduce,
column_projections: creduce,
},
);

graphs.insert(label.clone(), Arc::new(lg));
}

Ok(InMemoryGraph {
node_to_id: self.node_to_id,
id_to_node: self.id_to_node,
graphs,
catalog,
})
}
}

/// Metadata about a labeled graph in the decomposition.
#[derive(Debug, Clone, Default)]
pub struct GraphMetadata {
// pub num_vertices: usize,
pub row_projections: usize,
pub column_projections: usize,
}

/// Immutable, read-only Boolean-decomposed graph backed by LAGraph graphs.
pub struct InMemoryGraph {
node_to_id: HashMap<String, usize>,
id_to_node: HashMap<usize, String>,
graphs: HashMap<String, Arc<LagraphGraph>>,
catalog: HashMap<String, GraphMetadata>,
}

impl GraphDecomposition for InMemoryGraph {
Expand All @@ -198,6 +232,20 @@ impl GraphDecomposition for InMemoryGraph {
fn num_nodes(&self) -> usize {
self.id_to_node.len()
}

fn get_meta(&self, label: &str) -> Option<&GraphMetadata> {
self.get_metadata(label)
}
}

impl InMemoryGraph {
pub fn get_metadata(&self, label: &str) -> Option<&GraphMetadata> {
self.catalog.get(label)
}

pub fn catalog(&self) -> &HashMap<String, GraphMetadata> {
&self.catalog
}
}

impl<R: Read> GraphSource<InMemoryBuilder> for Csv<R> {
Expand All @@ -216,10 +264,8 @@ impl GraphSource<InMemoryBuilder> for MatrixMarket {
fn apply_to(self, mut builder: InMemoryBuilder) -> Result<InMemoryBuilder, GraphError> {
let vertices_path = self.dir.join("vertices.txt");
let (vert_by_idx, vert_by_name) = parse_index_map(&vertices_path)?;
let vert_by_idx =
vert_by_idx.into_iter().map(|(i, n)| (i - 1, n)).collect();
let vert_by_name =
vert_by_name.into_iter().map(|(n, i)| (n, i - 1)).collect();
let vert_by_idx = vert_by_idx.into_iter().map(|(i, n)| (i - 1, n)).collect();
let vert_by_name = vert_by_name.into_iter().map(|(n, i)| (n, i - 1)).collect();

let (edge_by_idx, _) = parse_index_map(&self.dir.join("edges.txt"))?;

Expand Down
21 changes: 20 additions & 1 deletion src/graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

pub mod inmemory;

pub use inmemory::{InMemory, InMemoryBuilder, InMemoryGraph};
pub use inmemory::{GraphMetadata, InMemory, InMemoryBuilder, InMemoryGraph};

use std::marker::PhantomData;
use std::sync::{Arc, Once};
Expand All @@ -11,6 +11,10 @@ use crate::{grb_ok, la_ok, lagraph_sys::*};

use thiserror::Error;

pub enum ReduceType {
ReduceByRows,
ReduceByCols,
}
#[derive(Debug, Error)]
pub enum GraphError {
/// A GraphBLAS C call returned a non-SUCCESS info code.
Expand Down Expand Up @@ -112,6 +116,19 @@ impl LagraphGraph {
pub fn check_graph(&self) -> Result<(), GraphError> {
la_ok!(LAGraph_CheckGraph(self.inner))
}

pub fn reduces_nvals(&self, reduce_type: ReduceType) -> Result<GrB_Index, GraphError> {
let mut n: GrB_Index = 0;
let matrix = unsafe { &*self.inner }.A;
grb_ok!(LAGraph_RPQMatrix_reduce(&mut n, matrix, reduce_type as u8))?;
Ok(n)
}
pub fn nvals(&self) -> Result<GrB_Index, GraphError> {
let mut n: GrB_Index = 0;
let matrix = unsafe { &*self.inner }.A;
grb_ok!(GrB_Matrix_nvals(&mut n, matrix))?;
Ok(n)
}
}

impl Drop for LagraphGraph {
Expand All @@ -125,6 +142,7 @@ impl Drop for LagraphGraph {
unsafe impl Send for LagraphGraph {}
unsafe impl Sync for LagraphGraph {}

#[derive(Debug)]
pub struct GraphblasVector {
pub inner: GrB_Vector,
}
Expand Down Expand Up @@ -201,6 +219,7 @@ pub trait GraphDecomposition {
/// Translates a matrix index back to a string ID.
fn get_node_name(&self, mapped_id: usize) -> Option<String>;
fn num_nodes(&self) -> usize;
fn get_meta(&self, label: &str) -> Option<&GraphMetadata>;
}

/// Associates a backend marker type with a concrete [`GraphBuilder`] and
Expand Down
36 changes: 36 additions & 0 deletions src/lagraph_sys_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,39 @@ unsafe extern "C" {
msg: *mut ::std::os::raw::c_char,
) -> ::std::os::raw::c_int;
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum RPQMatrixOp {
RPQ_MATRIX_OP_LABEL = 0,
RPQ_MATRIX_OP_LOR = 1,
RPQ_MATRIX_OP_CONCAT = 2,
RPQ_MATRIX_OP_KLEENE = 3,
RPQ_MATRIX_OP_KLEENE_L = 4,
RPQ_MATRIX_OP_KLEENE_R = 5,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct RPQMatrixPlan {
pub op: RPQMatrixOp,
pub lhs: *mut RPQMatrixPlan,
pub rhs: *mut RPQMatrixPlan,
pub mat: GrB_Matrix,
pub res_mat: GrB_Matrix,
}
unsafe extern "C" {
pub fn LAGraph_RPQMatrix(
nnz: *mut GrB_Index,
plan: *mut RPQMatrixPlan,
msg: *mut ::std::os::raw::c_char,
) -> GrB_Info;
}
unsafe extern "C" {
pub fn LAGraph_DestroyRpqMatrixPlan(plan: *mut RPQMatrixPlan) -> GrB_Info;
}
unsafe extern "C" {
pub fn LAGraph_RPQMatrix_reduce(
res: *mut GrB_Index,
mat: GrB_Matrix,
reduce_type: u8,
) -> GrB_Info;
}
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
pub mod formats;
pub mod graph;
pub mod rpq;
pub mod sparql;
#[allow(unused_unsafe, dead_code)]
pub(crate) mod utils;
pub mod utils;

pub mod lagraph_sys;
54 changes: 54 additions & 0 deletions src/rpq/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! Regular Path Query (RPQ) evaluation over edge-labeled graphs.
//! ```rust,ignore
//! use pathrex::sparql::parse_rpq;
//! use pathrex::rpq::{RpqEvaluator, nfarpq::NfaRpqEvaluator};
//!
//! let triple = parse_rpq("SELECT ?x ?y WHERE { ?x <knows>/<likes>* ?y . }")?;
//! let result = NfaRpqEvaluator.evaluate(&triple.subject, &triple.path, &triple.object, &graph)?;
//! ```

pub mod rpqmatrix;

use crate::graph::GraphDecomposition;
use crate::graph::GraphblasVector;
use crate::sparql::ExtractError;
use spargebra::SparqlSyntaxError;
use spargebra::algebra::PropertyPathExpression;
use spargebra::term::TermPattern;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum RpqError {
#[error("SPARQL syntax error: {0}")]
Parse(#[from] SparqlSyntaxError),

#[error("query extraction error: {0}")]
Extract(#[from] ExtractError),

#[error("unsupported path expression: {0}")]
UnsupportedPath(String),

#[error("label not found in graph: '{0}'")]
LabelNotFound(String),

#[error("vertex not found in graph: '{0}'")]
VertexNotFound(String),

#[error("GraphBLAS/LAGraph error: {0}")]
GraphBlas(String),
}

#[derive(Debug)]
pub struct RpqResult {
pub reachable: GraphblasVector,
}

pub trait RpqEvaluator {
fn evaluate<G: GraphDecomposition>(
&self,
subject: &TermPattern,
path: &PropertyPathExpression,
object: &TermPattern,
graph: &G,
) -> Result<RpqResult, RpqError>;
}
Loading
Loading