use libspot_rs::{SpotConfig, SpotDetector, SpotStatus};
use std::time::Instant;
pub struct CRand;
impl CRand {
pub fn new(seed: u32) -> Self {
unsafe {
libc::srand(seed);
}
CRand
}
pub fn rand(&mut self) -> u32 {
unsafe { libc::rand() as u32 }
}
pub fn runif(&mut self) -> f64 {
self.rand() as f64 / 2147483647.0 }
pub fn rexp(&mut self) -> f64 {
-self.runif().ln()
}
}
fn version() -> String {
env!("CARGO_PKG_VERSION").to_string()
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Testing libspot from Rust using the pure Rust API!");
let lib_version = version();
println!("libspot version: {lib_version}");
let config = SpotConfig {
q: 0.0001, low_tail: false, discard_anomalies: true, level: 0.998, max_excess: 200, };
let mut detector = SpotDetector::new(config)?;
println!("SPOT detector created successfully");
let n = 20000;
let mut initial_data = Vec::with_capacity(n);
let mut rng = CRand::new(1);
for _ in 0..n {
initial_data.push(rng.rexp());
}
detector.fit(&initial_data)?;
println!("Model successfully fitted with {n} data points");
let k = 50_000_000;
let mut normal = 0;
let mut excess = 0;
let mut anomaly = 0;
println!("Starting anomaly detection on {k} samples...");
let start = Instant::now();
for _ in 0..k {
let val = rng.rexp();
match detector.step(val)? {
SpotStatus::Normal => normal += 1,
SpotStatus::Excess => excess += 1,
SpotStatus::Anomaly => anomaly += 1,
}
}
let duration = start.elapsed();
println!("{:.6}", duration.as_secs_f64());
println!("ANOMALY={anomaly} EXCESS={excess} NORMAL={normal}");
println!(
"Z={:.6} T={:.6}",
detector.anomaly_threshold(),
detector.excess_threshold()
);
println!("Detection completed successfully!");
Ok(())
}