///|
/// Public algorithm metadata for dashboards and configuration UIs.
pub struct DetectorSpec {
name : String
family : String
online : Bool
multivariate : Bool
robust : Bool
default_threshold : Double
description : String
}
///|
pub fn DetectorSpec::new(
name : String,
family : String,
online : Bool,
multivariate : Bool,
robust : Bool,
default_threshold : Double,
description : String,
) -> DetectorSpec {
{ name, family, online, multivariate, robust, default_threshold, description }
}
///|
pub fn DetectorSpec::summary(self : DetectorSpec) -> String {
self.name +
" [" +
self.family +
"] threshold=" +
self.default_threshold.to_string()
}
///|
pub fn detector_catalog() -> Array[DetectorSpec] {
[
DetectorSpec::new(
"CUSUM", "sequential", true, false, false, 5.0, "small persistent mean shifts",
),
DetectorSpec::new(
"Page-Hinkley", "sequential", true, false, false, 10.0, "mean drift with forgetting",
),
DetectorSpec::new(
"Bayesian", "probabilistic", true, false, false, 0.5, "posterior change probability",
),
DetectorSpec::new(
"Robust-Z", "distribution", true, false, true, 3.5, "median and MAD based spikes",
),
DetectorSpec::new(
"Mahalanobis", "multivariate", true, true, true, 3.0, "vector distance from baseline",
),
DetectorSpec::new(
"Binary segmentation", "offline", false, false, false, 0.5, "multiple historical changes",
),
]
}
///|
pub fn detector_names() -> Array[String] {
let result : Array[String] = []
for spec in detector_catalog() {
result.push(spec.name)
}
result
}
///|
pub fn find_detector(name : String) -> DetectorSpec? {
for spec in detector_catalog() {
if spec.name == name {
return Some(spec)
}
}
None
}
///|
pub fn online_detector_count() -> Int {
let mut count = 0
for spec in detector_catalog() {
if spec.online {
count += 1
}
}
count
}
///|
pub fn robust_detector_count() -> Int {
let mut count = 0
for spec in detector_catalog() {
if spec.robust {
count += 1
}
}
count
}
///|
pub fn catalog_markdown() -> String {
let mut output = "| detector | family | online | multivariate | robust | threshold |\n|---|---|---|---|---|---:|\n"
for spec in detector_catalog() {
output = output +
"| " +
spec.name +
" | " +
spec.family +
" | " +
spec.online.to_string() +
" | " +
spec.multivariate.to_string() +
" | " +
spec.robust.to_string() +
" | " +
spec.default_threshold.to_string() +
" |\n"
}
output
}
///|
pub fn recommended_detector(
multivariate : Bool,
offline : Bool,
robust : Bool,
) -> String {
if offline {
"Binary segmentation"
} else if multivariate {
"Mahalanobis"
} else if robust {
"Robust-Z"
} else {
"CUSUM"
}
}