This project implements a profitable cycle detector for weighted directed graphs (e.g., currency arbitrage), using:
-
Compressed Sparse Row (CSR) graph representation for compact and cache-friendly storage.
-
SPFA (Shortest Path Faster Algorithm) variant with hop cap to detect negative cycles efficiently.
-
Streaming updates via async ingestion pipeline to simulate live rate changes.
-
Clean, well-structured code that passes formatting and linting checks.
| Component | Description |
|---|---|
| CSR Builder | Converts edge lists into a compressed sparse row format for efficient traversal. |
| SPFA Cycle Detection | Detects profitable cycles (negative log-sum loops) with optional hop limit. |
| Async Updates Ingest | Receives edge/rate updates and applies them to shared graph state. |
| Numeric Kernel | Handles rate transformations with clamping, quantization, and epsilon gating. |
| Data Layout (AoS β SoA) | Demonstrates memory layout performance differences via benchmarks. |
src/
βββ lib.rs # Core logic: CSR, SPFA, numeric kernel, data structs
βββ bin/
β βββ async_pipeline.rs # Async update ingestion + cycle recheck demo
β βββ bench_aos.rs # AoS benchmark
β βββ bench_soa.rs # SoA benchmark
β βββ cycle_finder.rs # Build graph + detect profitable cycle- Rust 1.75+
- Cargo package manager
cargo build --releasecargo run --release --bin cycle_findercargo run --release --bin bench_aos
cargo run --release --bin bench_soacargo testcargo run --release --bin async_pipeline- CSR Graph Format: Nodes and edges are stored compactly in arrays (offsets, targets, weights) to improve memory locality and speed up SPFA traversal.
- SPFA with Hop Cap: Similar to BellmanβFord but uses a queue and hop limit to avoid infinite loops. Detects negative cycles (i.e., profitable cycles in log-space).
- Profitability Criterion: Rates are transformed with w(u,v) = -ln(rate). A cycle is profitable if the sum of weights (logs) < 0 β product of rates > 1.
- Async Update Pipeline: Uses tokio::sync::mpsc with a bounded channel to ingest updates, apply them to the graph, and trigger recalculation periodically.
- Performance & Safety:
- Bounded channels provide backpressure.
- Locking (RwLock) is kept minimal.
- Arithmetic kernels are clamped, quantized, and epsilon-filtered for stability.
- All code passes:
cargo fmt --check cargo clippy -- -D warnings
Cycle found: Cycle { nodes: [2, 0, 1], ... }
Product: 0.5500, log_sum: -0.5978