///|
/// Diagnostic time-series helpers for monitoring robust estimators in production.
pub fn diagnostic_series_mean(reports : ArrayView[DiagnosticReport]) -> Double {
if reports.length() == 0 {
0.0
} else {
let mut total = 0.0
for report in reports {
total += report.rms
}
total / reports.length().to_double()
}
}
///|
pub fn diagnostic_series_maximum(
reports : ArrayView[DiagnosticReport],
) -> Double {
let mut result = 0.0
for report in reports {
result = result.max(report.rms)
}
result
}
///|
pub fn diagnostic_series_minimum(
reports : ArrayView[DiagnosticReport],
) -> Double {
if reports.length() == 0 {
0.0
} else {
let mut result = reports[0].rms
for report in reports {
result = result.min(report.rms)
}
result
}
}
///|
pub fn diagnostic_series_improvement(
reports : ArrayView[DiagnosticReport],
) -> Double {
if reports.length() < 2 {
0.0
} else {
let first = reports[0].rms
let last = reports[reports.length() - 1].rms
if first <= 0.0 {
0.0
} else {
(first - last) / first
}
}
}
///|
pub fn diagnostic_series_inlier_mean(
reports : ArrayView[DiagnosticReport],
) -> Double {
if reports.length() == 0 {
0.0
} else {
let mut total = 0.0
for report in reports {
total += report.inlier_ratio
}
total / reports.length().to_double()
}
}
///|
pub fn diagnostic_series_stable(
reports : ArrayView[DiagnosticReport],
tolerance : Double,
) -> Bool {
if reports.length() < 2 {
true
} else {
(diagnostic_series_maximum(reports) - diagnostic_series_minimum(reports)).abs() <=
tolerance.max(0.0)
}
}
///|
pub fn diagnostic_series_pass_count(
reports : ArrayView[DiagnosticReport],
minimum_inliers : Int,
maximum_rms : Double,
) -> Int {
let mut result = 0
for report in reports {
if diagnostic_report_passes(report, minimum_inliers, maximum_rms) {
result += 1
}
}
result
}
///|
pub fn diagnostic_series_pass_ratio(
reports : ArrayView[DiagnosticReport],
minimum_inliers : Int,
maximum_rms : Double,
) -> Double {
if reports.length() == 0 {
0.0
} else {
diagnostic_series_pass_count(reports, minimum_inliers, maximum_rms).to_double() /
reports.length().to_double()
}
}
///|
pub fn diagnostic_series_buckets(
reports : ArrayView[DiagnosticReport],
) -> Array[Int] {
let result = [0, 0, 0]
for report in reports {
let bucket = diagnostic_quality_bucket(report).min(2).max(0)
result[bucket] += 1
}
result
}
///|
pub fn diagnostic_series_last(
reports : ArrayView[DiagnosticReport],
) -> DiagnosticReport? {
if reports.length() == 0 {
None
} else {
Some(reports[reports.length() - 1])
}
}
///|
pub fn diagnostic_series_best(
reports : ArrayView[DiagnosticReport],
) -> DiagnosticReport? {
if reports.length() == 0 {
None
} else {
let mut result = reports[0]
for report in reports[1:] {
if report.rms < result.rms {
result = report
}
}
Some(result)
}
}
///|
pub fn diagnostic_series_take(
reports : ArrayView[DiagnosticReport],
count : Int,
) -> Array[DiagnosticReport] {
let result : Array[DiagnosticReport] = []
for i in 0.. Array[DiagnosticReport] {
let result : Array[DiagnosticReport] = []
for i in count.max(0).min(reports.length()).. Array[DiagnosticReport] {
diagnostic_series_take(diagnostic_series_drop(reports, start), width)
}
///|
pub fn diagnostic_series_append(
target : Array[DiagnosticReport],
reports : ArrayView[DiagnosticReport],
) -> Unit {
for report in reports {
target.push(report)
}
}
///|
pub fn diagnostic_series_merge(
left : ArrayView[DiagnosticReport],
right : ArrayView[DiagnosticReport],
) -> Array[DiagnosticReport] {
let result = left.to_owned()
diagnostic_series_append(result, right)
result
}
///|
pub fn diagnostic_series_scale(
reports : ArrayView[DiagnosticReport],
scale : Double,
) -> Array[DiagnosticReport] {
let result : Array[DiagnosticReport] = []
for report in reports {
result.push(diagnostic_report_scale(report, scale))
}
result
}
///|
pub fn diagnostic_series_labels(
reports : ArrayView[DiagnosticReport],
) -> Array[String] {
let result : Array[String] = []
for report in reports {
result.push(report.label)
}
result
}
///|
pub fn diagnostic_series_summary(
reports : ArrayView[DiagnosticReport],
) -> String {
diagnostic_series_mean(reports).to_string() +
"," +
diagnostic_series_maximum(reports).to_string() +
"," +
diagnostic_series_inlier_mean(reports).to_string()
}
///|
pub fn diagnostic_series_quality(
reports : ArrayView[DiagnosticReport],
minimum_inliers : Int,
maximum_rms : Double,
) -> Double {
diagnostic_series_pass_ratio(reports, minimum_inliers, maximum_rms) *
(1.0 / (1.0 + diagnostic_series_mean(reports)))
}