hpr_validate/metrics.rs
1//! References and measured values: what an oracle said, and what hpr said.
2
3use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6
7/// One reference value and where it comes from.
8///
9/// [Loft lesson L77][l77]: Loft shipped "stored results" that were hand-written, one set
10/// internally inconsistent. A value without a source is not a reference, so `source` is required.
11///
12/// [l77]: https://nrdptel.github.io/hpr-sim/decisions-and-roadmap.html#l77
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14#[serde(deny_unknown_fields)]
15pub struct ReferenceValue {
16 /// The value, in the metric's own unit.
17 pub value: f64,
18 /// Where it came from: the oracle's own field, a printed page, or a closed form.
19 pub source: String,
20}
21
22/// An oracle's answers for one case, with the provenance of the run that produced them.
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24pub struct Reference {
25 /// What produced it, as the generator records it (for example `rocketpy 1.13.0`).
26 pub oracle: String,
27 /// The generator script, relative to the repository root.
28 pub generator: String,
29 /// The command that regenerates it.
30 pub command: String,
31 /// What the oracle modeled, in the generator's words.
32 pub model: String,
33 /// What the generator overrode to make the comparison like-for-like.
34 pub overrides: String,
35 /// The reference's own case id.
36 pub case: String,
37 /// The file it was read from, relative to the repository root.
38 pub file: String,
39 /// That file's SHA-256, so an edited reference shows up in the report itself.
40 pub sha256: String,
41 /// The values, by metric name.
42 pub values: BTreeMap<String, ReferenceValue>,
43}
44
45impl Reference {
46 /// The metrics that carry no source, which is what [Loft lesson L77][l77] refuses: a value
47 /// without a source is not a reference.
48 ///
49 /// [l77]: https://nrdptel.github.io/hpr-sim/decisions-and-roadmap.html#l77
50 #[must_use]
51 pub fn without_provenance(&self) -> Vec<String> {
52 self.values
53 .iter()
54 .filter(|(_, value)| value.source.trim().is_empty())
55 .map(|(name, _)| name.clone())
56 .collect()
57 }
58}
59
60/// What hpr measured for one case, by metric name.
61#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
62pub struct Measured {
63 /// The values, by metric name, in the same units as the reference's.
64 pub values: BTreeMap<String, f64>,
65}
66
67impl Measured {
68 /// Records `value` for `name`.
69 pub fn insert(&mut self, name: &str, value: f64) {
70 self.values.insert(name.to_owned(), value);
71 }
72}