batch.rsannotatedbatch.rssource155 lines · 5.1 KB · raw

The batch planner: how each row reaches the model (contract Execution, "Request layout").

A row with two or more distinct questions is sent as the state, each question a branch. A row with exactly one would be sent in that question's instructions, beside other rows' questions, but that layout has no accuracy measurement against row as state, so it waits on the layout-parity release gate (Testing). Until the gate passes it is unreachable: [LayoutParity] has no values, so no [Planner] can hold one, and every row is sent as the state.

12use std::collections::{HashMap, HashSet};
13use std::hash::Hash;
15use jev_protocol::{Json, ProtocolError};
16
17use crate::Layout;

Evidence that row in instructions passed the layout-parity release gate: jev-orderby-bench's mean |Δp|, Spearman and position effect against row as state, recorded against the pinned model version.

It has not been run, so the type is uninhabited. Giving it a value is the change that enables row in instructions, and it belongs with the recorded result.

26#[derive(Clone, Copy, Debug)]
27pub enum LayoutParity {}

Chooses each row's layout, and builds its state.

30#[derive(Clone, Copy, Debug, Default)]
31pub struct Planner {

Always None while [LayoutParity] is uninhabited.

33    parity: Option<LayoutParity>,
34}

A row's layout as the [Planner] chose it. Only a planner makes one, and row in instructions carries the [LayoutParity] evidence, so a layout the gate has not passed cannot be written down, let alone handed to [Planner::place].

40#[derive(Clone, Copy, Debug)]
41pub struct Planned(Plan);
43#[derive(Clone, Copy, Debug)]
44enum Plan {
45    RowAsState,
46    RowInInstructions(LayoutParity),
47}
48
49impl Planned {
50    pub fn layout(self) -> Layout {
51        match self.0 {
52            Plan::RowAsState => Layout::RowAsState,
53            Plan::RowInInstructions(gate) => match gate {},
54        }
55    }
56}

Where a row goes in its request: its layout and the request's state. Only a [Planner] makes one, so a layout the gate has not passed never reaches a request or a cache key.

61#[derive(Clone)]
62pub struct Placement {
63    layout: Layout,
64    state: Json,
65}
67impl Placement {
68    pub(crate) fn new(layout: Layout, state: Json) -> Self {
69        Placement { layout, state }
70    }
71
72    pub fn layout(&self) -> Layout {
73        self.layout
74    }

Under row as state, the row's canonical JSON.

77    pub fn state(&self) -> &Json {
78        &self.state
79    }
80}
82impl Planner {
83    pub const fn new() -> Self {
84        Planner { parity: None }
85    }

The layout for a row with questions distinct questions.

88    pub fn layout(&self, questions: usize) -> Planned {
89        match (questions, self.parity) {
90            (1, Some(gate)) => Planned(Plan::RowInInstructions(gate)),
91            _ => Planned(Plan::RowAsState),
92        }
93    }

Each row's layout, from the questions asked about it: asks pairs a row with one question's serialized bytes, and a question asked twice about the same row counts once.

98    pub fn layouts<'q, R: Hash + Eq>(&self, asks: impl IntoIterator<Item = (R, &'q [u8])>) -> HashMap<R, Planned> {
99        let mut questions: HashMap<R, HashSet<&'q [u8]>> = HashMap::new();
100        for (row, question) in asks {
101            questions.entry(row).or_default().insert(question);
102        }
103        questions.into_iter().map(|(row, q)| (row, self.layout(q.len()))).collect()
104    }

row, a JSON text, placed as planned. Refused when the row is not JSON.

108    pub fn place(&self, planned: Planned, row: &str) -> Result<Placement, ProtocolError> {
109        match planned.0 {
110            Plan::RowAsState => Ok(Placement::new(Layout::RowAsState, Json::canonical(row)?)),
111            Plan::RowInInstructions(gate) => match gate {},
112        }
113    }
114}
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn two_or_more_questions_are_row_as_state() {
122        let p = Planner::new();
123        assert_eq!(p.layout(2).layout(), Layout::RowAsState);
124        assert_eq!(p.layout(255).layout(), Layout::RowAsState);
125    }
126
127    #[test]
128    fn one_question_is_row_as_state_until_the_gate_passes() {
129        assert_eq!(Planner::new().layout(1).layout(), Layout::RowAsState);
130        assert_eq!(Planner::default().layout(1).layout(), Layout::RowAsState);
131    }
132
133    #[test]
134    fn layouts_count_distinct_questions_per_row() {
135        let (a, b): (&[u8], &[u8]) = (b"{\"noul\":1}", b"{\"noul\":2}");
136        let layouts = Planner::new().layouts([("r1", a), ("r1", b), ("r2", a), ("r2", a)]);
137        assert_eq!(layouts.len(), 2);
138        assert_eq!(layouts["r1"].layout(), Layout::RowAsState);
139        assert_eq!(layouts["r2"].layout(), Layout::RowAsState);
140    }
141
142    #[test]
143    fn row_as_state_sends_the_canonical_row() {
144        let p = Planner::new();
145        let placed = p.place(p.layout(1), r#"{ "b": 1, "a": "x" }"#).unwrap();
146        assert_eq!(placed.layout(), Layout::RowAsState);
147        assert_eq!(placed.state().as_str(), r#"{"a":"x","b":1}"#);
148    }
149
150    #[test]
151    fn a_row_that_is_not_json_is_refused() {
152        let p = Planner::new();
153        assert!(p.place(p.layout(2), "{").is_err());
154    }
155}