Skip to content
Merged
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
13 changes: 13 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: crate-ci/typos@master
- run: rustup update stable && rustup default stable
- run: cargo fmt --check
- run: cargo clippy
- run: |
git clone --depth 1 https://github.com/DrTimothyAldenDavis/GraphBLAS.git
cd GraphBLAS
make compact
sudo make install
cd ..
- run: |
cd vendor/LAGraph
make
sudo make install
cd ../..
- run: cargo build --verbose
- run: cargo test --verbose
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "vendor/LAGraph"]
path = vendor/LAGraph
url = https://github.com/SparseLinearAlgebra/LAGraph.git
71 changes: 71 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ egg = "0.10.0"
nom = "7.1"
expect-test = "1.5.1"
libc = "0.2.0"
rand = "0.8"
2 changes: 2 additions & 0 deletions _typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[files]
extend-exclude = ["vendor/"]
7 changes: 7 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main() {
println!("cargo:rustc-link-lib=dylib=lagraphx");
println!("cargo:rustc-link-search=native=vendor/LAGraph/build/experimental");

println!("cargo:rustc-link-lib=dylib=lagraph");
println!("cargo:rustc-link-search=native=vendor/LAGraph/build/src");
}
140 changes: 140 additions & 0 deletions src/eval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use std::ptr::null_mut;

use crate::graph::Graph;
use crate::grb;
use crate::plan::Plan;

#[repr(C)]
#[derive(Clone)]
pub enum RpqMatrixOp {
Label,
Lor,
Concat,
Kleene,
KleeneL,
KleeneR,
}

#[repr(C)]
#[derive(Clone)]
pub struct RpqMatrixPlan {
pub op: RpqMatrixOp,
pub lhs: *mut RpqMatrixPlan,
pub rhs: *mut RpqMatrixPlan,
pub mat: grb::Matrix,
pub res_mat: grb::Matrix,
}

#[link(name = "lagraphx")]
extern "C" {
pub fn LAGraph_Init(msg: *mut libc::c_char) -> libc::c_int;
pub fn LAGraph_DestroyRpqMatrixPlan(plan: *mut RpqMatrixPlan);
pub fn LAGraph_RPQMatrix(
ans: *mut usize,
plan: *mut RpqMatrixPlan,
msg: *mut libc::c_char,
) -> libc::c_longlong;
pub fn LAGraph_RPQMatrix_label(
mat: *mut grb::Matrix,
x: usize,
i: usize,
j: usize,
) -> libc::c_longlong;
}

#[link(name = "lagraph")]
extern "C" {
pub fn LAGraph_MMRead(
mat: *mut grb::Matrix,
f: *mut libc::FILE,
msg: *mut libc::c_char,
) -> libc::c_int;
}

pub fn eval(graph: &Graph, expr: egg::RecExpr<Plan>) -> Result<usize, String> {
let mut plans: Vec<RpqMatrixPlan> = vec![
RpqMatrixPlan {
op: RpqMatrixOp::Label,
lhs: null_mut(),
rhs: null_mut(),
mat: grb::Matrix::null(),
res_mat: grb::Matrix::null()
};
expr.len()
];
expr.items().for_each(|(id, plan)| {
let eval_plan = match plan {
&Plan::Seq([lhs, rhs]) => RpqMatrixPlan {
op: RpqMatrixOp::Concat,
lhs: plans.get_mut::<usize>(lhs.into()).unwrap() as *mut RpqMatrixPlan,
rhs: plans.get_mut::<usize>(rhs.into()).unwrap() as *mut RpqMatrixPlan,
res_mat: grb::Matrix::null(),
mat: grb::Matrix::null(),
},
&Plan::Alt([lhs, rhs]) => RpqMatrixPlan {
op: RpqMatrixOp::Lor,
lhs: plans.get_mut::<usize>(lhs.into()).unwrap() as *mut RpqMatrixPlan,
rhs: plans.get_mut::<usize>(rhs.into()).unwrap() as *mut RpqMatrixPlan,
res_mat: grb::Matrix::null(),
mat: grb::Matrix::null(),
},
&Plan::Star([lhs]) => RpqMatrixPlan {
op: RpqMatrixOp::Kleene,
lhs: null_mut(),
rhs: plans.get_mut::<usize>(lhs.into()).unwrap() as *mut RpqMatrixPlan,
res_mat: grb::Matrix::null(),
mat: grb::Matrix::null(),
},
&Plan::LStar([lhs, rhs]) => RpqMatrixPlan {
op: RpqMatrixOp::KleeneL,
lhs: plans.get_mut::<usize>(lhs.into()).unwrap() as *mut RpqMatrixPlan,
rhs: plans.get_mut::<usize>(rhs.into()).unwrap() as *mut RpqMatrixPlan,
res_mat: grb::Matrix::null(),
mat: grb::Matrix::null(),
},
&Plan::RStar([lhs, rhs]) => RpqMatrixPlan {
op: RpqMatrixOp::KleeneR,
lhs: plans.get_mut::<usize>(lhs.into()).unwrap() as *mut RpqMatrixPlan,
rhs: plans.get_mut::<usize>(rhs.into()).unwrap() as *mut RpqMatrixPlan,
res_mat: grb::Matrix::null(),
mat: grb::Matrix::null(),
},
Plan::Label(meta) => {
let mut mat: grb::Matrix = grb::Matrix(std::ptr::null_mut());
let mat = graph
.mats
.get(&meta.name)
.or({
graph.verts.get(&meta.name).map(|vert_idx| {
Comment on lines +103 to +108
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable mat is shadowed immediately after declaration. The mutable mat on line 103 is never used before being shadowed on line 104, making its initialization pointless. Remove the declaration on line 103 or rename one of the variables.

Suggested change
let mut mat: grb::Matrix = grb::Matrix(std::ptr::null_mut());
let mat = graph
.mats
.get(&meta.name)
.or({
graph.verts.get(&meta.name).map(|vert_idx| {
let mat = graph
.mats
.get(&meta.name)
.or({
graph.verts.get(&meta.name).map(|vert_idx| {
let mut mat: grb::Matrix = grb::Matrix(std::ptr::null_mut());

Copilot uses AI. Check for mistakes.
unsafe {
LAGraph_RPQMatrix_label(
&mut mat as *mut grb::Matrix,
*vert_idx,
graph.verts.len(),
graph.verts.len(),
);
}
&mat
})
})
Comment on lines +107 to +119
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This closure references mat from the outer scope (line 103), but mat is shadowed on line 104. The reference &mat on line 117 would refer to the outer uninitialized matrix. This code would not compile as written, or has undefined behavior.

Copilot uses AI. Check for mistakes.
.unwrap()
.clone();
RpqMatrixPlan {
op: RpqMatrixOp::Label,
lhs: null_mut(),
rhs: null_mut(),
res_mat: grb::Matrix::null(),
mat,
}
}
};
plans[std::convert::Into::<usize>::into(id)] = eval_plan;
});
let plan = plans.iter_mut().last().unwrap();
let mut ans: usize = 0;
unsafe {
LAGraph_RPQMatrix(&mut ans, plan as *mut RpqMatrixPlan, null_mut());
LAGraph_DestroyRpqMatrixPlan(plan);
Comment on lines +136 to +137
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value from LAGraph_RPQMatrix is ignored. Check the return code and propagate errors appropriately, similar to how LAGraph_MMRead is checked in graph.rs.

Suggested change
LAGraph_RPQMatrix(&mut ans, plan as *mut RpqMatrixPlan, null_mut());
LAGraph_DestroyRpqMatrixPlan(plan);
let status = LAGraph_RPQMatrix(&mut ans, plan as *mut RpqMatrixPlan, null_mut());
LAGraph_DestroyRpqMatrixPlan(plan);
if status != 0 {
return Err(format!("LAGraph_RPQMatrix failed with error code {}", status));
}

Copilot uses AI. Check for mistakes.
}
Ok(ans)
}
Loading