///|
pub(all) struct QuantileBand {
lower : Model
upper : Model
lower_tau : Double
upper_tau : Double
} derive(Debug)
///|
pub fn train_band(
samples : Array[Sample],
lower_tau : Double,
upper_tau : Double,
direction? : Direction = Increasing,
) -> Result[QuantileBand, String] {
if !finite(lower_tau) ||
!finite(upper_tau) ||
lower_tau <= 0.0 ||
upper_tau >= 1.0 ||
lower_tau >= upper_tau {
return Err("invalid quantile envelope levels")
}
let lower = match train_quantile(samples, lower_tau, direction~) {
Err(e) => return Err(e)
Ok(v) => v
}
let upper = match train_quantile(samples, upper_tau, direction~) {
Err(e) => return Err(e)
Ok(v) => v
}
for i = 0; i < lower.knots.length(); i = i + 1 {
if lower.knots[i].x != upper.knots[i].x ||
lower.knots[i].y > upper.knots[i].y {
return Err("crossing empirical quantiles")
}
}
Ok({ lower, upper, lower_tau, upper_tau, })
}
///|
pub fn predict_band(
band : QuantileBand,
queries : Array[Double],
) -> Result[Array[InverseRange], String] {
if band.lower_tau <= 0.0 ||
band.upper_tau >= 1.0 ||
band.lower_tau >= band.upper_tau {
return Err("invalid band levels")
}
let lower = match predict_many(band.lower, queries) {
Err(e) => return Err(e)
Ok(v) => v
}
let upper = match predict_many(band.upper, queries) {
Err(e) => return Err(e)
Ok(v) => v
}
let ranges : Array[InverseRange] = []
for i = 0; i < queries.length(); i = i + 1 {
if lower[i] > upper[i] {
return Err("crossing band at query")
}
ranges.push({ lower: lower[i], upper: upper[i], })
}
Ok(ranges)
}
///|
pub(all) struct BandCoverage {
count : Int
weight : Double
covered_weight : Double
coverage : Double
mean_width : Double
} derive(Debug)
///|
/// Descriptive empirical coverage, not a confidence guarantee.
pub fn band_coverage(
band : QuantileBand,
samples : Array[Sample],
) -> Result[BandCoverage, String] {
match validate_samples(samples) {
Err(e) => return Err(e)
Ok(_) => ()
}
let ranges = match predict_band(band, samples.map(fn(s) { s.x })) {
Err(e) => return Err(e)
Ok(v) => v
}
let mut weight = 0.0
let mut covered_weight = 0.0
let mut width = 0.0
for i = 0; i < samples.length(); i = i + 1 {
let s = samples[i]
let r = ranges[i]
weight = weight + s.weight
if s.y >= r.lower && s.y <= r.upper {
covered_weight = covered_weight + s.weight
}
width = width + s.weight * (r.upper - r.lower)
}
if !finite(width) {
return Err("band width overflow")
}
Ok({
count: samples.length(),
weight,
covered_weight,
coverage: covered_weight / weight,
mean_width: width / weight,
})
}
///|
#deprecated
pub extend QuantileBand with @debug.Debug::{to_repr}
///|
#deprecated
pub extend BandCoverage with @debug.Debug::{to_repr}