feat(aura-engine): WalkForwardResult::named_params — mirror SweepFamily::named_params

Add the typed/named convenience view on `WalkForwardResult`, closing the
symmetry cycle 0048 left open: it shares the `(space, tag-free Vec<Cell>)`
idiom with `SweepFamily` but had no named-params accessor, so a consumer
hand-wrote `zip_params(&result.space, &result.windows[i].run.chosen_params)`.

`named_params(window)` pairs each param-space name with that window's chosen
value in slot order, delegating to `zip_params` — the direct mirror of
`SweepFamily::named_params`. A derived view, no new stored state.

closes #76
This commit is contained in:
2026-06-17 14:21:06 +02:00
parent 91ef69ed7b
commit 8b22fa6c73
+52 -1
View File
@@ -13,7 +13,7 @@
use crate::sweep::run_indexed;
use crate::{MetricStats, ParamSpec, RunReport, ScalarKind, Timestamp};
use aura_core::Cell;
use aura_core::{zip_params, Cell, Scalar};
/// One rolling split's time bounds: an in-sample window and the out-of-sample
/// window that follows it. Carries ONLY bounds — never tick data (#71). C2
@@ -165,6 +165,15 @@ pub struct WalkForwardResult {
pub stitched_oos_equity: Vec<(Timestamp, f64)>,
}
impl WalkForwardResult {
/// The chosen params of the `window`-th outcome paired with their names — a
/// derived view over the carried param-space (reuses [`zip_params`]); the
/// walk-forward mirror of [`SweepFamily::named_params`](crate::SweepFamily).
pub fn named_params(&self, window: usize) -> Vec<(String, Scalar)> {
zip_params(&self.space, &self.windows[window].run.chosen_params)
}
}
/// Roll the windows, run `run_window` on each disjointly in parallel (C1, via the
/// shared [`run_indexed`](crate::sweep) core), then stitch the OOS equity into one
/// continuous curve. The varying dimension is the *data window* (C12 axis 3).
@@ -437,6 +446,48 @@ mod tests {
assert_eq!(stab[0].mean, 0.75);
}
#[test]
fn named_params_pairs_each_name_with_the_chosen_window_value() {
// #76: WalkForwardResult::named_params(w) is the typed/named view — it
// pairs each param-space NAME with window `w`'s chosen VALUE, in slot
// order, reading the right window. Mirror of SweepFamily::named_params.
// Expected vectors are spelled out explicitly (not via zip_params) so the
// assertion pins the observable pairing, not the implementation.
let mk = |fast: i64, scale: f64| WindowOutcome {
bounds: WindowBounds {
is: (Timestamp(0), Timestamp(0)),
oos: (Timestamp(0), Timestamp(0)),
},
run: WindowRun {
chosen_params: vec![Cell::from_i64(fast), Cell::from_f64(scale)],
oos_equity: vec![],
oos_report: dummy_report(),
},
};
let result = WalkForwardResult {
space: vec![
ParamSpec { name: "sma.fast".to_string(), kind: ScalarKind::I64 },
ParamSpec { name: "exposure.scale".to_string(), kind: ScalarKind::F64 },
],
windows: vec![mk(8, 0.25), mk(13, 0.75)],
stitched_oos_equity: vec![],
};
assert_eq!(
result.named_params(0),
vec![
("sma.fast".to_string(), Scalar::i64(8)),
("exposure.scale".to_string(), Scalar::f64(0.25)),
],
);
assert_eq!(
result.named_params(1),
vec![
("sma.fast".to_string(), Scalar::i64(13)),
("exposure.scale".to_string(), Scalar::f64(0.75)),
],
);
}
#[test]
fn roller_rolling_emits_consecutive_oos_windows() {
// spec §Testing 1: rolling, origin=0, is_len=10, oos_len=5, step=5, end=24.