Skip to main content

sva_samples/machine/
mod.rs

1// Concern: runs one node renderer a block at a time, span after span, over a tape | Non-concern: the op array's own shape (ops.rs), cutting the spans (live.rs) | IO: (Spanned, reads, tape) -> samples
2
3mod block;
4mod live;
5pub mod ops;
6mod read;
7pub mod renderer;
8pub mod tape;
9
10use crate::error::SampleError;
11use crate::filters::FilterSite;
12use crate::physics::{Solver, site};
13use block::{BLOCK, Block, Here};
14use ops::{Layout, Op, lowered};
15use renderer::{Formula, Grid, Index, NodeRenderer, Site, Slot};
16use tape::{Tape, Window};
17
18pub use live::{Span, Spanned};
19
20pub use ops::Layout as MachineLayout;
21
22/// The op array, each op's width and operand slots, the formulas its ops name and the call
23/// sites the run opens state for.
24#[derive(Clone)]
25pub(super) struct Program {
26    ops: Vec<Op>,
27    widths: Vec<usize>,
28    args: Vec<Vec<usize>>,
29    formulas: Vec<Formula>,
30    indices: Vec<Index<usize>>,
31    sites: Vec<Site>,
32    pub width: usize,
33}
34
35impl NodeRenderer {
36    pub(super) fn compile(&self, layout: &Layout) -> Result<Program, SampleError> {
37        let (lowered, width) = lowered(self, layout)?;
38        let mut pending = Vec::new();
39        let mut args = Vec::with_capacity(lowered.ops.len());
40        for (slot, op) in lowered.ops.iter().enumerate() {
41            args.push(pending.split_off(pending.len() - arity_of(op)));
42            pending.push(slot);
43        }
44        Ok(Program {
45            ops: lowered.ops,
46            widths: lowered.widths,
47            args,
48            formulas: lowered.formulas,
49            indices: lowered.indices,
50            sites: layout.sites.clone(),
51            width,
52        })
53    }
54}
55
56#[derive(Clone)]
57enum State {
58    Filter(FilterSite),
59    Physics(Box<dyn Solver>),
60}
61
62impl Clone for Box<dyn Solver> {
63    fn clone(&self) -> Box<dyn Solver> {
64        self.boxed()
65    }
66}
67
68/// A filter site carries one lane per component of its widest argument, which the compiled
69/// slot width already states.
70fn open(p: &Program, grid: Grid) -> Result<Vec<State>, SampleError> {
71    let mut lanes = vec![1usize; p.sites.len()];
72    for (slot, op) in p.ops.iter().enumerate() {
73        if let Op::Filter { site, .. } = op {
74            lanes[site.0 as usize] = p.widths[slot];
75        }
76    }
77    p.sites
78        .iter()
79        .zip(lanes)
80        .map(|(s, width)| {
81            Ok(match s {
82                Site::Filter(shape) => State::Filter(FilterSite::new(
83                    *shape,
84                    width,
85                    &[0.0],
86                    &[0.0],
87                    &[0.0],
88                    grid.sr(),
89                )),
90                Site::Physics(params) => State::Physics(site(params, grid.sr())?),
91            })
92        })
93        .collect()
94}
95
96/// Component `c` of an operand that may be mono where its neighbour is wide.
97fn part(v: &[f64], c: usize) -> f64 {
98    v[c.min(v.len() - 1)]
99}
100
101/// One compiled node and every call site's state, run over any span of the grid in order.
102/// A span continues exactly where the last ended, so blocks write the samples one run would.
103pub struct Machine {
104    program: Program,
105    states: Vec<State>,
106    block: Block,
107    grid: Grid,
108    /// Each later span's first sample and the program it runs, the next one last.
109    ahead: Vec<(i64, Program)>,
110}
111
112#[derive(Clone)]
113pub struct MachineState {
114    sites: Vec<Site>,
115    states: Vec<State>,
116}
117
118impl State {
119    fn bytes(&self) -> usize {
120        match self {
121            State::Filter(filter) => filter.bytes(),
122            State::Physics(solver) => solver.bytes(),
123        }
124    }
125}
126
127impl MachineState {
128    pub fn bytes(&self) -> usize {
129        let states: usize = self.states.iter().map(State::bytes).sum();
130        size_of::<Self>() + std::mem::size_of_val(self.sites.as_slice()) + states
131    }
132}
133
134impl Machine {
135    /// Stepping from `at`, each span's own program from where it starts.
136    pub fn over(spanned: &Spanned, at: i64) -> Result<Machine, SampleError> {
137        let grid = spanned.grid();
138        let mut ahead: Vec<(i64, Program)> = spanned
139            .compiled()
140            .iter()
141            .filter(|(span, _)| span.to > at)
142            .map(|(span, program)| (span.from, program.clone()))
143            .collect();
144        ahead.reverse();
145        let first = match ahead.pop() {
146            Some((_, program)) => program,
147            None => spanned.silent()?,
148        };
149        let states = open(&first, grid)?;
150        let block = Block::of(&first.widths);
151        Ok(Machine {
152            program: first,
153            states,
154            block,
155            grid,
156            ahead,
157        })
158    }
159
160    pub fn width(&self) -> usize {
161        self.program.width
162    }
163
164    pub fn stateful(&self) -> bool {
165        !self.program.sites.is_empty()
166    }
167
168    pub fn bytes(&self) -> usize {
169        self.states.iter().map(State::bytes).sum()
170    }
171
172    pub fn run_to(&mut self, to: i64, reads: &[Window], own: &mut Tape) -> Result<(), SampleError> {
173        for state in &mut self.states {
174            if let State::Filter(filter) = state {
175                filter.forget_frames();
176            }
177        }
178        self.steps(to, reads, own)
179    }
180
181    /// `run_to`, the filters' frames kept.
182    pub fn run_on(&mut self, to: i64, reads: &[Window], own: &mut Tape) -> Result<(), SampleError> {
183        self.steps(to, reads, own)
184    }
185
186    fn steps(&mut self, to: i64, reads: &[Window], own: &mut Tape) -> Result<(), SampleError> {
187        loop {
188            while let Some((from, _)) = self.ahead.last()
189                && *from <= own.end()
190            {
191                let (_, program) = self.ahead.pop().expect("a span ahead");
192                self.block = Block::of(&program.widths);
193                self.program = program;
194            }
195            let until = self.ahead.last().map_or(to, |(from, _)| (*from).min(to));
196            self.stepped(until, reads, own)?;
197            if own.end() >= to {
198                return Ok(());
199            }
200        }
201    }
202
203    fn stepped(&mut self, to: i64, reads: &[Window], own: &mut Tape) -> Result<(), SampleError> {
204        let p = &self.program;
205        while own.end() < to {
206            let from = own.end();
207            let len = p.block(from, (to - from).min(BLOCK as i64) as usize);
208            let here = Here {
209                reads,
210                own: own.window(),
211                grid: self.grid,
212            };
213            let (held, refused) =
214                block::run(p, &mut self.block, &here, &mut self.states, (from, len));
215            for i in 0..held {
216                let top = self.block.top(p, i);
217                for c in 0..p.width {
218                    own.push(c, part(top, c));
219                }
220            }
221            if let Some(e) = refused {
222                return Err(e);
223            }
224        }
225        Ok(())
226    }
227
228    /// Call site `site`'s solver as it stands now, where that site is one.
229    pub fn solver(&self, site: usize) -> Option<&dyn Solver> {
230        match self.states.get(site)? {
231            State::Physics(solver) => Some(solver.as_ref()),
232            State::Filter(_) => None,
233        }
234    }
235
236    pub fn filter(&self, site: usize) -> Option<&FilterSite> {
237        match self.states.get(site)? {
238            State::Filter(filter) => Some(filter),
239            State::Physics(_) => None,
240        }
241    }
242
243    pub fn state(&self) -> MachineState {
244        MachineState {
245            sites: self.program.sites.clone(),
246            states: self.states.clone(),
247        }
248    }
249
250    pub fn restart(&mut self) {
251        self.states = open(&self.program, self.grid).expect("the sites opened once already");
252    }
253
254    /// Whether `carry` takes `held`: the same sites, a varying parameter's values aside.
255    pub fn accepts(&self, held: &MachineState) -> bool {
256        held.sites == self.program.sites
257    }
258
259    /// Takes `held`'s state whole where its sites are these; `false`, and nothing taken, else.
260    pub fn carry(&mut self, held: &MachineState) -> bool {
261        let taken = self.accepts(held);
262        if taken {
263            self.states.clone_from(&held.states);
264        }
265        taken
266    }
267}
268
269impl Program {
270    /// Up to `most` samples from `from`, each reading its own past only before `from`.
271    fn block(&self, from: i64, most: usize) -> usize {
272        let mut len = most;
273        for op in &self.ops {
274            match op {
275                Op::Read {
276                    slot: Slot::Own,
277                    at,
278                }
279                | Op::ReadScaled {
280                    slot: Slot::Own,
281                    at,
282                    ..
283                } => {
284                    let last = |len: usize| from + len as i64 - 1;
285                    while len > 1 && at.at(from).max(at.at(last(len))) >= from {
286                        len /= 2;
287                    }
288                }
289                Op::Indexed {
290                    slot: Slot::Own,
291                    reach,
292                    ..
293                } => {
294                    len = match reach {
295                        Some((_, most)) if *most < 0 => len.min(most.unsigned_abs() as usize),
296                        _ => 1,
297                    }
298                }
299                _ => {}
300            }
301        }
302        len.max(1)
303    }
304}
305
306fn arity_of(op: &Op) -> usize {
307    match op {
308        Op::Const(_)
309        | Op::Time
310        | Op::Wrap(_)
311        | Op::Noise { .. }
312        | Op::Read { .. }
313        | Op::ReadScaled { .. } => 0,
314        Op::Physics { arity, .. } => *arity,
315        Op::Map(_) | Op::Crop { .. } | Op::Channel(_) | Op::Formula { .. } => 1,
316        Op::Indexed { arity, .. } | Op::Instant { arity, .. } => *arity,
317        Op::Sub | Op::Div | Op::Pow | Op::Zip(_) => 2,
318        Op::Add(n) | Op::Mul(n) | Op::Join(n) => *n,
319        Op::Filter { .. } => 4,
320    }
321}