| Crate | Version | Documentation | License |
|---|---|---|---|
| libspot (C FFI) | |||
| libspot-rs (Pure Rust) |
Rust implementations of the SPOT (Streaming Peaks Over Threshold) algorithm for real-time anomaly detection in time series data.
Choose your preferred implementation:
# C FFI version (faster, requires C dependencies)
cargo add libspot
# Pure Rust version (safer, no dependencies)
cargo add libspot-rsBoth implementations provide identical APIs - you can switch between them by just changing the crate import!
// Choose your implementation:
// use libspot::{SpotDetector, SpotConfig, SpotStatus}; // C FFI version
use libspot_rs::{SpotDetector, SpotConfig, SpotStatus}; // Pure Rust version
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create detector with default configuration
let config = SpotConfig::default();
let mut detector = SpotDetector::new(config)?;
// Fit with training data (normal distribution around 5.0)
let training_data: Vec<f64> = (0..1000)
.map(|i| 5.0 + (i as f64 * 0.01).sin() * 2.0)
.collect();
detector.fit(&training_data)?;
// Detect anomalies in real-time
let test_value = 50.0; // This should be an anomaly
match detector.step(test_value)? {
SpotStatus::Normal => println!("Normal data point"),
SpotStatus::Excess => println!("In the tail distribution"),
SpotStatus::Anomaly => println!("Anomaly detected! 🚨"),
}
Ok(())
}Both implementations support identical configuration:
use libspot_rs::SpotConfig; // or use libspot::SpotConfig;
let config = SpotConfig {
q: 0.0001, // Anomaly probability threshold (lower = more sensitive)
low_tail: false, // Monitor upper tail (set true for lower tail)
discard_anomalies: true, // Exclude anomalies from model updates
level: 0.998, // Quantile level that defines the tail
max_excess: 200, // Maximum number of excess values to store
};| Feature | libspot (C FFI) |
libspot-rs (Pure Rust) |
|---|---|---|
| Installation | cargo add libspot |
cargo add libspot-rs |
| Type | C FFI Bindings | Pure Rust Implementation |
| API | ✅ Identical | ✅ Identical |
| Performance | ✅ ~1.04s (50M samples) | ✅ ~0.83s (50M samples) |
| Memory Safety | ✅ Guaranteed | |
| Dependencies | 📦 C library + bindgen | 🎯 None |
| Cross-platform | ✅ Easy | |
| WebAssembly | ❌ Limited support | ✅ Full support |
| Results | ✅ Reference standard | ✅ Mathematically identical |
| Key Benefits | Fast, Proven, Compatible | Safe, Portable, WebAssembly |
| Documentation | docs.rs/libspot | docs.rs/libspot-rs |
Both implementations provide identical results to the original C implementation. Benchmark tests process 50M samples and produce mathematically equivalent anomaly counts and thresholds:
| Metric | C Implementation | Rust Wrapper (FFI) | Pure Rust (libspot-rs) |
|---|---|---|---|
| Anomalies | 90,007 | 90,007 ✓ | 90,007 ✓ |
| Excess | 7,829 | 7,829 ✓ | 7,829 ✓ |
| Normal | 49,902,164 | 49,902,164 ✓ | 49,902,164 ✓ |
| Z | 6.237668 | 6.237668 ✓ | 6.237668 ✓ |
| T | 6.236165 | 6.236165 ✓ | 6.236165 ✓ |
| Performance | ~0.67s | ~1.04s ≈ | ~1.13s ≈ |
Benchmark Commands:
- Pure Rust:
cargo run -r --example basic(incrates/libspot-rs) - C FFI:
cargo run -r --example basic(incrates/libspot) - Original C:
cd crates/libspot/libspot && make && cc -O3 -o /tmp/basic ../examples/basic.c dist/libspot.a.$(cat version) -Idist/ -lm && /tmp/basic
The results demonstrate that both Rust implementations achieve excellent performance while maintaining mathematical correctness. The pure Rust version is actually the fastest, showing the effectiveness of Rust's optimizations.
- API Documentation: docs.rs/libspot | docs.rs/libspot-rs
- Original C Library: asiffer/libspot
Contributions are welcome! Please feel free to submit issues and pull requests.
This project is licensed under the GNU Lesser General Public License v3.0 (LGPL-3.0) to comply with the underlying libspot C library license.