Skip to main content

henad_core/explore/
spec.rs

1//! Sweep specs, as a spec file or the command line writes them.
2
3use std::time::Duration;
4
5use crate::explore::design::DesignKind;
6use crate::explore::factor::FactorSpec;
7use crate::explore::reducer::ReducerSpec;
8use crate::explore::search::SearchSpec;
9use crate::explore::seed::SeedScheme;
10use crate::explore::stop::StopSpec;
11
12/// Prefix of the column that holds an action's tick, as in `action.second_wave`.
13pub const ACTION_COLUMN_PREFIX: &str = "action.";
14
15/// A sweep as written, with parameter values still in text.
16///
17/// [`SweepSpec::plan`] checks it against a model and lists its configs.
18#[derive(Debug, Clone, PartialEq)]
19pub struct SweepSpec {
20    /// Id of the model to run.
21    pub model: String,
22    /// Values every config shares, as `(id, value)` pairs in the form that `--set` accepts.
23    pub fixed: Vec<(String, String)>,
24    /// Length and end of each run, and the number of runs per config.
25    pub run: RunSettings,
26    /// Ticks each run samples, and the values it keeps from them.
27    pub measure: MeasureSettings,
28    /// Seeds of the runs.
29    pub seeds: SeedSettings,
30    /// Actions every run fires. Actions due at the same tick fire in list order.
31    pub actions: Vec<ActionSpec>,
32    /// Blocks whose configs the sweep runs, in order. An empty list runs the fixed values alone.
33    pub blocks: Vec<BlockSpec>,
34    /// Search that picks the configs to run instead of blocks, `None` for a sweep.
35    ///
36    /// Each candidate of a search runs [`RunSettings::replicates`] times, over the fixed values and actions above.
37    pub search: Option<SearchSpec>,
38}
39
40impl SweepSpec {
41    /// Returns a spec for `model` with default settings and no blocks.
42    pub fn new(model: impl Into<String>) -> Self {
43        Self {
44            model: model.into(),
45            fixed: Vec::new(),
46            run: RunSettings::default(),
47            measure: MeasureSettings::default(),
48            seeds: SeedSettings::default(),
49            actions: Vec::new(),
50            blocks: Vec::new(),
51            search: None,
52        }
53    }
54}
55
56/// A model action a sweep fires in every run, as written.
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct ActionSpec {
59    /// Id of the action the model declares.
60    pub id: String,
61    /// Name that factors and output columns use for the action, unique within a spec.
62    pub name: String,
63    /// Tick the action fires at, where no block varies it.
64    ///
65    /// Tick 0 fires before the first step, and any later tick after the step that reaches it.
66    pub tick: u64,
67}
68
69impl ActionSpec {
70    /// Returns action `id` at `tick`, with `id` as its name.
71    pub fn new(id: impl Into<String>, tick: u64) -> Self {
72        let id = id.into();
73        Self {
74            name: id.clone(),
75            id,
76            tick,
77        }
78    }
79
80    /// Returns the name of the column that holds the action's tick, as in `action.second_wave`.
81    pub fn column_name(&self) -> String {
82        format!("{ACTION_COLUMN_PREFIX}{}", self.name)
83    }
84}
85
86/// Factors combined under one design, as written.
87#[derive(Debug, Clone, Default, PartialEq)]
88pub struct BlockSpec {
89    /// Design that combines the factors into configs.
90    pub design: DesignKind,
91    /// Factors of the block. A table design gets its factors from its table, and this list stays empty.
92    pub factors: Vec<FactorSpec>,
93    /// Seed of a sampled design's draws, or `None` to derive it with [`design_seed`] from the root seed and the block.
94    ///
95    /// [`design_seed`]: crate::explore::seed::design_seed
96    pub design_seed: Option<u64>,
97}
98
99/// Length and end of each run, and the number of runs per config.
100#[derive(Debug, Clone, PartialEq)]
101pub struct RunSettings {
102    /// Number of ticks stepped after the warm-up.
103    pub steps: u64,
104    /// Number of ticks stepped before the first sample.
105    pub warmup: u64,
106    /// Number of runs per config, each with its own seed.
107    pub replicates: u64,
108    /// Condition that ends a run at the first sample where it holds.
109    pub stop: Option<StopSpec>,
110    /// Wall-clock time after which a run is abandoned, checked between slices of steps. On a GPU track, a run's
111    /// clock counts its share of the time the sweep spends on the tracks.
112    ///
113    /// Note that a timed-out run depends on the machine, so no plan or results hash covers the timeout.
114    pub timeout: Option<Duration>,
115}
116
117impl Default for RunSettings {
118    fn default() -> Self {
119        Self {
120            steps: 1000,
121            warmup: 0,
122            replicates: 1,
123            stop: None,
124            timeout: None,
125        }
126    }
127}
128
129/// Ticks a run samples, and the values it keeps from them.
130#[derive(Debug, Clone, PartialEq)]
131pub struct MeasureSettings {
132    /// Ticks between two samples, counted from the end of the warm-up.
133    pub stats_every: u64,
134    /// Ticks between two rows of the series, a multiple of `stats_every`.
135    ///
136    /// The final sample is always a row. A value of 0 keeps no series at all.
137    pub series_every: u64,
138    /// Whether every column other than a histogram bucket gets the [`ReducerKind::DEFAULTS`] reducers.
139    ///
140    /// [`ReducerKind::DEFAULTS`]: crate::explore::reducer::ReducerKind::DEFAULTS
141    pub default_reducers: bool,
142    /// Reducers added after the defaults.
143    pub reducers: Vec<ReducerSpec>,
144}
145
146impl Default for MeasureSettings {
147    fn default() -> Self {
148        Self {
149            stats_every: 1,
150            series_every: 1,
151            default_reducers: true,
152            reducers: Vec::new(),
153        }
154    }
155}
156
157/// Root seed, and the scheme that derives each run's seed from it.
158#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
159pub struct SeedSettings {
160    /// Seed each run's seed is derived from.
161    pub root: u64,
162    /// Scheme that derives each run's seed from [`Self::root`].
163    pub scheme: SeedScheme,
164}