///|
pub fn batch_mean_by_name(
batches : Array[BatchRun],
name : String,
) -> StatsSummary {
let values : Array[Double] = []
for batch in batches {
for measurement in batch.records {
if measurement.name == name {
values.push(measurement.value)
}
}
}
describe_samples(values)
}
///|
pub fn batch_decision_rate(batches : Array[BatchRun]) -> Double {
let mut total = 0
let mut accepted = 0
for batch in batches {
let summary = batch.summary()
total += summary.total
accepted += summary.pass + summary.warn
}
if total == 0 {
0.0
} else {
Double::from_int(accepted) / Double::from_int(total)
}
}
///|
pub fn batch_values_by_index(
batches : Array[BatchRun],
index : Int,
) -> Array[Double] {
let result : Array[Double] = []
for batch in batches {
if index >= 0 && index < batch.records.length() {
result.push(batch.records[index].value)
}
}
result
}
///|
pub fn batch_control_limits(
values : Array[Double],
sigma : Double,
) -> DoubleBounds {
let summary = describe_samples(values)
let margin = sigma.abs() * summary.standard_deviation
{ min: summary.mean - margin, max: summary.mean + margin }
}
///|
pub fn batch_out_of_control(
values : Array[Double],
limits : DoubleBounds,
) -> Array[Bool] {
values.map(fn(value) { value < limits.min || value > limits.max })
}
///|
pub fn batch_moving_average(
values : Array[Double],
window : Int,
) -> Array[Double] {
moving_average(values, window)
}
///|
pub fn batch_cumulative_sum(values : Array[Double]) -> Array[Double] {
let result : Array[Double] = []
let mut total = 0.0
for value in values {
total += value
result.push(total)
}
result
}
///|
pub fn batch_cumulative_mean(values : Array[Double]) -> Array[Double] {
let result : Array[Double] = []
let mut total = 0.0
for i in 0.. Double {
if values.length() < 2 {
0.0
} else {
(values[values.length() - 1] - values[0]) /
Double::from_int(values.length() - 1)
}
}
///|
pub fn batch_linear_trend(values : Array[Double]) -> Double {
if values.length() < 2 {
0.0
} else {
let x : Array[Double] = []
for i in 0.. Array[Array[Measurement]] {
let pass : Array[Measurement] = []
let warn : Array[Measurement] = []
let fail : Array[Measurement] = []
for measurement in measurements {
match measurement.decision {
Pass => pass.push(measurement)
Warn => warn.push(measurement)
Fail => fail.push(measurement)
}
}
[pass, warn, fail]
}
///|
pub fn batch_measurement_table(batch : BatchRun) -> MeasurementTable {
let rows : Array[Array[String]] = []
for measurement in batch.records {
rows.push([
measurement.name,
measurement.value.to_string(),
measurement.unit,
decision_name(measurement.decision),
measurement.deviation.to_string(),
])
}
{ columns: ["name", "value", "unit", "decision", "deviation"], rows }
}
///|
pub fn render_measurement_table(table : MeasurementTable) -> String {
let out = StringBuilder()
for column in table.columns {
out.write_string(column)
out.write_string("\t")
}
out.write_string("\n")
for row in table.rows {
for cell in row {
out.write_string(cell)
out.write_string("\t")
}
out.write_string("\n")
}
out.to_string()
}
///|
pub fn batch_snapshot(batch : BatchRun) -> String {
let stats = batch_statistics(batch)
batch.id +
":" +
stats.total.to_string() +
":" +
stats.accepted.to_string() +
":" +
stats.rejected.to_string() +
":" +
stats.mean.to_string()
}
///|
pub fn compare_batches(
first : BatchRun,
second : BatchRun,
) -> Array[Measurement] {
measurement_delta(first.records, second.records)
}