Skip to content

feat(graph): add CSR graph algorithms (PageRank, community, path, similarity)#46

Merged
epicsagas merged 4 commits into
mainfrom
graph-algorithms
Jun 26, 2026
Merged

feat(graph): add CSR graph algorithms (PageRank, community, path, similarity)#46
epicsagas merged 4 commits into
mainfrom
graph-algorithms

Conversation

@epicsagas

Copy link
Copy Markdown
Owner

Summary

Closes the Neo4j/GDS algorithm gap flagged in #45 (Axis C — algorithmic depth). Adds a pure-Rust, zero-dependency graph algorithm module (src/graph/algo/) behind the existing graph feature — no Cargo.toml change, no petgraph.

Algorithms

Module Algorithms GDS counterpart
algo/csr.rs CsrGraph — directed weighted CSR snapshot, dangling-node detection foundation
algo/pagerank.rs weighted PageRank (power iteration + dangling redistribution) Centrality
algo/community.rs connected components (union-find) + label propagation Community detection
algo/path.rs Dijkstra weighted shortest path (distance = -ln(weight)) Pathfinding
algo/similarity.rs Jaccard, common neighbors, Adamic-Adar, link prediction Similarity

recall integration + drift removal

smart_recall's graph boost (W_GRAPH = 0.10) now ranks the top-100 candidates by true PageRank over their induced subgraph, replacing the former neighbor-weight-sum (an approximate degree centrality). The SQLite (recall.rs) and PostgreSQL (pg.rs) recall paths share the same pagerank_default free function, permanently removing the cross-backend boost-logic drift (pg.rs had duplicated the boost SQL).

New store::edges_among serves the induced-subgraph query.

Verification

  • 570 tests pass (cargo test --all-features); +87 new algorithm/regression tests
  • cargo clippy --all-features -- -D warnings — clean
  • cargo fmt --all -- --check — clean
  • RUSTDOCFLAGS=\"-D warnings\" cargo doc --all-features — clean
  • eval graph PASS (12 scenarios incl. 2 PageRank, avg_recall 1.0)
  • Hand-computed unit tests: diamond PageRank (sink dominates, B/C symmetric), jaccard 1/3, adamic-adar 1/ln(2), two-hop-beats-direct Dijkstra

Benchmarks (2026-06-26 baseline)

Full numbers + interpretation in docs/benchmarks/graph.md. Highlights (criterion median):

Algorithm 100 nodes 1000 nodes
PageRank 435 ns 4.87 µs
Connected components 956 ns 9.50 µs
Dijkstra 3.17 µs 41.0 µs
CSR build (DB load incl.) 75.0 µs 727 µs

PageRank at ~5 µs / 1000 nodes justifies recomputing it on every smart_recall call — no result cache needed.

Scope

Addresses #45 Axis C (algorithmic depth) and contributes to Axis A (benchmark baselines). The remaining axes (scale ceiling, recall-quality harness, concurrency proof, consumer integration) stay open.

Refs #45.

…ilarity)

Pure-Rust zero-dependency module (src/graph/algo/) compiled in behind the
existing `graph` feature — no Cargo.toml change, no petgraph. Closes the
Neo4j/GDS algorithm gap flagged in issue #45 Axis C.

- CsrGraph: directed weighted CSR snapshot with dangling-node detection
- pagerank: weighted power iteration with dangling-node redistribution
- community: connected components (union-find) + label propagation
- path: Dijkstra weighted shortest path (distance = -ln(weight))
- similarity: Jaccard, common neighbors, Adamic-Adar, link prediction

smart_recall's graph boost (W_GRAPH) now ranks the top-100 candidates by
true PageRank over their induced subgraph, replacing the approximate
degree-centrality neighbor-weight sum. The SQLite (recall.rs) and
PostgreSQL (pg.rs) recall paths share pagerank_default, permanently
removing the cross-backend boost-logic drift.

All algorithms validated by hand-computed unit tests (diamond PageRank,
jaccard 1/3, adamic-adar 1/ln(2), two-hop-beats-direct Dijkstra) plus
criterion benchmarks (PageRank 1000 nodes: ~4.9us). 570 tests pass,
clippy/fmt/rustdoc clean.
docs/benchmarks/graph.md captures the 2026-06-26 criterion measurements
(PageRank 1000 nodes: 4.87us, connected components 9.50us, Dijkstra 41us,
CSR build 727us) as the v1.0.0 baseline for issue #45 Axis A / ROADMAP #3.
README Benchmarks section now links to it and lists the new algorithm
benchmark groups.
edge_cost now clamps weight to [SHORTEST_PATH_W_MIN, 1.0]. A
contract-violating weight > 1.0 previously produced -ln(w) < 0, a negative
edge cost that breaks Dijkstra's non-negative-edge assumption and silently
returns wrong shortest paths. It is now treated as maximal strength
(cost 0). Adds a regression test asserting no negative distances.
recall_graph_boost asserted only len()==2 despite a comment claiming the
boost was applied. Now also asserts the dangling sink outranks its source:
with hint=None and identical base scores the score difference is purely the
graph boost, so this is the one test exercising its ranking effect.
Normalizes the contract-violating weight 2.0 to 1.0.
@epicsagas epicsagas merged commit 2c26d8a into main Jun 26, 2026
21 of 22 checks passed
@epicsagas epicsagas deleted the graph-algorithms branch June 26, 2026 11:38
epicsagas added a commit that referenced this pull request Jun 26, 2026
)

Resolves RUSTSEC-2026-0185 in quinn-proto, the advisory that was failing
the audit CI gate on every PR (#44, #46). quinn-proto reaches the
lockfile via the reqwest 0.12 tree but is not activated under any
feature/target combination (cargo tree -i reports nothing to print), so
this is a lockfile-only patch. Verified: cargo audit now reports 0
vulnerabilities (exit 0); cargo test --all-features green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant