anomstream_core/thresholded/mod.rs
1//! Adaptive-threshold layer on top of [`crate::RandomCutForest`].
2//!
3//! Where the bare forest returns a raw anomaly score in `[0, ∞)`,
4//! [`ThresholdedForest`] tracks the running distribution of those
5//! scores and emits a graded verdict — `is_anomaly: bool`,
6//! `grade ∈ [0, 1]`, and the `threshold` in effect at observation
7//! time. Callers no longer have to hand-pick a magic threshold per
8//! deployment: the detector adapts to the traffic it sees.
9//!
10//! Inspired by the AWS *Thresholded Random Cut Forest* (TRCF)
11//! facility in `randomcutforest-parkservices`, but intentionally
12//! lighter: only the adaptive μ + z·σ threshold over an EMA of the
13//! score stream, without the short/long-term duality or the
14//! near-threshold heuristics of the full TRCF.
15//!
16//! # Example
17//!
18//! ```ignore
19//! use anomstream_core::ThresholdedForestBuilder;
20//!
21//! let mut detector = ThresholdedForestBuilder::<4>::new()
22//! .num_trees(100)
23//! .sample_size(256)
24//! .z_factor(3.0)
25//! .min_observations(32)
26//! .seed(42)
27//! .build()?;
28//!
29//! for packet in stream_of_feature_vectors {
30//! let verdict = detector.process(packet)?;
31//! if verdict.is_anomaly() {
32//! eprintln!(
33//! "anomaly: grade={:.2} score={} threshold={:.3}",
34//! verdict.grade(),
35//! verdict.score(),
36//! verdict.threshold(),
37//! );
38//! }
39//! }
40//! # Ok::<(), anomstream_core::RcfError>(())
41//! ```
42
43pub mod config;
44pub mod detector;
45pub mod grade;
46pub mod stats;
47
48pub use config::{
49 DEFAULT_MIN_OBSERVATIONS, DEFAULT_MIN_THRESHOLD, DEFAULT_QUANTILE, DEFAULT_SCORE_DECAY,
50 DEFAULT_Z_FACTOR, ThresholdMode, ThresholdedConfig, ThresholdedForestBuilder,
51};
52pub use detector::ThresholdedForest;
53pub use grade::AnomalyGrade;
54pub use stats::EmaStats;