Skip to main content

sva_samples/machine/
live.rs

1// Concern: cuts one renderer into spans, each compiled without the reads and crops zero there | Non-concern: where a read is zero, running a span | IO: (NodeRenderer, supports) -> Spanned
2
3use super::CompiledOps;
4use super::ops::{self, Layout};
5use super::renderer::{Index, NodeRenderer, Slot};
6use crate::error::SampleError;
7use crate::grid::Extent;
8
9#[derive(Clone)]
10pub struct Span {
11    pub from: i64,
12    pub to: i64,
13    pub renderer: NodeRenderer,
14}
15
16/// A renderer cut into spans each stripped of what is exact zero there: a sample's program
17/// depends on its index alone.
18#[derive(Clone)]
19pub struct Spanned {
20    spans: Vec<(Span, CompiledOps)>,
21    layout: Layout,
22}
23
24impl Spanned {
25    /// Outside `live[k]` read `k` answers exactly +0.0.
26    pub fn new(
27        renderer: &NodeRenderer,
28        layout: &Layout,
29        (from, to): (i64, i64),
30        live: &[Extent],
31    ) -> Result<Spanned, SampleError> {
32        let spans = renderer
33            .spans(layout, (from, to), live)?
34            .into_iter()
35            .map(|span| {
36                let compiled_ops = span.renderer.compile(layout)?;
37                Ok((span, compiled_ops))
38            })
39            .collect::<Result<_, SampleError>>()?;
40        Ok(Spanned {
41            spans,
42            layout: layout.clone(),
43        })
44    }
45
46    pub fn spans(&self) -> impl Iterator<Item = &Span> {
47        self.spans.iter().map(|(span, _)| span)
48    }
49
50    pub(super) fn grid(&self) -> crate::grid::Grid {
51        self.layout.grid
52    }
53
54    pub(super) fn compiled(&self) -> &[(Span, CompiledOps)] {
55        &self.spans
56    }
57
58    /// A program writing +0 where no span reaches.
59    pub(super) fn silent(&self) -> Result<CompiledOps, SampleError> {
60        let zero = match self.layout.width {
61            0 | 1 => NodeRenderer::Const(0.0),
62            w => NodeRenderer::Join(vec![NodeRenderer::Const(0.0); w]),
63        };
64        zero.compile(&self.layout)
65    }
66}
67
68impl NodeRenderer {
69    /// `[from, to)` cut where the dead reads or shut crops change, each span stripped of exact
70    /// zeros; any cut of a run writes the same bits.
71    pub fn spans(
72        &self,
73        layout: &Layout,
74        (from, to): (i64, i64),
75        live: &[Extent],
76    ) -> Result<Vec<Span>, SampleError> {
77        let mut root = Cut::of(self, layout, live)?;
78        let mut edges = vec![from, to];
79        root.edges(&mut edges);
80        edges.retain(|e| from <= *e && *e <= to);
81        edges.sort_unstable();
82        edges.dedup();
83        let mut out: Vec<Span> = Vec::new();
84        for pair in edges.windows(2) {
85            let span = Extent::new(pair[0], pair[1]);
86            let changed = root.strip_exact_zeros(span, layout)?;
87            match out.last_mut() {
88                Some(last) if !changed => last.to = span.end,
89                last => {
90                    let renderer = root.made();
91                    match last {
92                        Some(last) if last.renderer == renderer => last.to = span.end,
93                        _ => out.push(Span {
94                            from: span.start,
95                            to: span.end,
96                            renderer,
97                        }),
98                    }
99                }
100            }
101        }
102        Ok(out)
103    }
104
105    /// Each index read no reach bounds held to the samples up to the one being written, all a
106    /// machine stepping beside its source has, where `beside` names that source.
107    pub fn stepwise(&self, beside: &dyn Fn(Slot) -> bool) -> NodeRenderer {
108        match self {
109            NodeRenderer::Indexed {
110                slot,
111                index,
112                reach: None,
113            } if beside(*slot) => NodeRenderer::Indexed {
114                slot: *slot,
115                index: index.clone(),
116                reach: Some((i64::MIN, 0)),
117            },
118            other => rebuilt(other, &mut |p| p.stepwise(beside)),
119        }
120    }
121}
122
123/// One node of the renderer, its width settled once, and what stripping exact zeros made of it over the
124/// latest span; that holds over every later span ending by `until`, since only the reads
125/// and crops under it decide it.
126struct Cut<'r> {
127    node: &'r NodeRenderer,
128    width: usize,
129    operands: Vec<Cut<'r>>,
130    /// Where a read of another node can be nonzero, in this node's samples.
131    reach: Option<Extent>,
132    until: i64,
133    made: Made,
134    held: Held,
135}
136
137#[derive(Clone, PartialEq)]
138enum Made {
139    Kept,
140    /// Exact +0 in each component.
141    Zeros,
142    /// A sum over only these operands.
143    Terms(Vec<usize>),
144    /// A difference whose subtrahend is exact zero, as its minuend.
145    Minuend,
146}
147
148/// What the node as made holds over the span.
149#[derive(Default)]
150struct Held {
151    /// Exactly +0.0 at every sample.
152    zero: bool,
153    /// Exactly +0.0 or -0.0 at every sample, which a sum starting from +0 drops alike.
154    nil: bool,
155    stateless: bool,
156    /// Each component where every sample is the same number.
157    constant: Option<Vec<f64>>,
158}
159
160impl<'r> Cut<'r> {
161    fn of(
162        node: &'r NodeRenderer,
163        layout: &Layout,
164        live: &[Extent],
165    ) -> Result<Cut<'r>, SampleError> {
166        let operands = node
167            .operands()
168            .into_iter()
169            .map(|p| Cut::of(p, layout, live))
170            .collect::<Result<Vec<_>, _>>()?;
171        let widths: Vec<usize> = operands.iter().map(|o| o.width).collect();
172        let reach = match node {
173            NodeRenderer::Read {
174                slot: Slot::Read(id),
175                map,
176            } => Some(map.preimage(live[id.0 as usize])),
177            _ => None,
178        };
179        Ok(Cut {
180            node,
181            width: ops::width(node, &widths, layout)?,
182            operands,
183            reach,
184            until: i64::MIN,
185            made: Made::Kept,
186            held: Held::default(),
187        })
188    }
189
190    fn edges(&self, out: &mut Vec<i64>) {
191        if let Some(reach) = self.reach {
192            out.extend([reach.start, reach.end]);
193        }
194        if let NodeRenderer::Crop { window, .. } = self.node {
195            out.extend([window.0, window.1]);
196        }
197        for o in &self.operands {
198            o.edges(out);
199        }
200    }
201
202    /// Strips the exact zeros again of what `span` passes the `until` of, bottom-up; whether
203    /// what it makes changed.
204    fn strip_exact_zeros(&mut self, span: Extent, layout: &Layout) -> Result<bool, SampleError> {
205        if span.end <= self.until {
206            return Ok(false);
207        }
208        let mut below = false;
209        for o in &mut self.operands {
210            below |= o.strip_exact_zeros(span, layout)?;
211        }
212        let mut until = self
213            .operands
214            .iter()
215            .map(|o| o.until)
216            .min()
217            .unwrap_or(i64::MAX);
218        let over = |e: Extent| {
219            [e.start, e.end]
220                .into_iter()
221                .filter(|&x| x > span.start)
222                .min()
223        };
224        let shut = match self.node {
225            NodeRenderer::Crop { window, .. } => {
226                let open = Extent::new(window.0.min(window.1), window.1);
227                until = until.min(over(open).unwrap_or(i64::MAX));
228                open.intersect(span).is_empty()
229            }
230            _ => false,
231        };
232        let dead = self.reach.is_some_and(|reach| {
233            until = until.min(over(reach).unwrap_or(i64::MAX));
234            reach.intersect(span).is_empty()
235        });
236        let made = self.decided(shut, layout)?;
237        let changed = self.until == i64::MIN || made != self.made || (below && made != Made::Zeros);
238        self.held = self.holding(&made, shut, dead);
239        self.made = made;
240        self.until = until;
241        Ok(changed)
242    }
243
244    /// A product with a factor exact zero over the span, every other factor holding no
245    /// state, is exact +0 there whatever those factors hold: its zero factor is outside its
246    /// support. A sum drops the terms that are exact zero where that keeps its width.
247    fn decided(&self, shut: bool, layout: &Layout) -> Result<Made, SampleError> {
248        let ops = &self.operands;
249        Ok(match self.node {
250            NodeRenderer::Crop { .. } if shut && ops[0].held.stateless => Made::Zeros,
251            NodeRenderer::Mul(_)
252                if ops.iter().any(|o| o.held.zero) && ops.iter().all(|o| o.held.stateless) =>
253            {
254                Made::Zeros
255            }
256            NodeRenderer::Add(_) => {
257                let live: Vec<usize> = (0..ops.len()).filter(|&k| !ops[k].held.nil).collect();
258                let widths: Vec<usize> = live.iter().map(|&k| ops[k].width).collect();
259                match live.is_empty() {
260                    true if self.width == 1 => Made::Zeros,
261                    false if live.len() == ops.len() => Made::Kept,
262                    false if ops::width(self.node, &widths, layout)? == self.width => {
263                        Made::Terms(live)
264                    }
265                    _ => Made::Kept,
266                }
267            }
268            NodeRenderer::Sub(..) if ops[1].held.zero && ops[0].width == self.width => {
269                Made::Minuend
270            }
271            _ => Made::Kept,
272        })
273    }
274
275    fn holding(&self, made: &Made, shut: bool, dead: bool) -> Held {
276        let ops = &self.operands;
277        let of = |k: usize| &ops[k].held;
278        match made {
279            Made::Zeros => Held {
280                zero: true,
281                nil: true,
282                stateless: true,
283                constant: Some(vec![0.0; self.width]),
284            },
285            Made::Minuend => Held {
286                zero: of(0).zero,
287                nil: of(0).nil,
288                stateless: of(0).stateless,
289                constant: of(0).constant.clone(),
290            },
291            Made::Terms(live) => {
292                let zero = live.iter().all(|&k| of(k).nil);
293                Held {
294                    zero,
295                    nil: zero,
296                    stateless: live.iter().all(|&k| of(k).stateless),
297                    constant: fold(live.iter().map(|&k| of(k)), 0.0, |a, b| a + b),
298                }
299            }
300            Made::Kept => {
301                let all = |f: fn(&Held) -> bool| ops.iter().all(|o| f(&o.held));
302                let zero = match self.node {
303                    NodeRenderer::Read {
304                        slot: Slot::Read(_),
305                        ..
306                    } => dead,
307                    NodeRenderer::Const(v) => v.to_bits() == 0,
308                    NodeRenderer::Crop { .. } => shut || of(0).zero,
309                    NodeRenderer::Add(_) => all(|h| h.nil),
310                    NodeRenderer::Join(_) => all(|h| h.zero),
311                    NodeRenderer::Sub(..) => of(0).zero && of(1).zero,
312                    _ => false,
313                };
314                let nil = match self.node {
315                    NodeRenderer::Mul(_) => match ops.iter().position(|o| o.held.nil) {
316                        None => false,
317                        Some(at) => {
318                            finite(fold(ops[..at].iter().map(|o| &o.held), 1.0, |a, b| a * b))
319                                && ops[at + 1..]
320                                    .iter()
321                                    .all(|o| o.held.nil || finite(o.held.constant.clone()))
322                        }
323                    },
324                    NodeRenderer::Crop { .. } => zero || of(0).nil,
325                    _ => zero,
326                };
327                let held = ops.iter().map(|o| &o.held);
328                let constant = match self.node {
329                    NodeRenderer::Const(v) => Some(vec![*v]),
330                    NodeRenderer::Join(_) => {
331                        held.map(|h| h.constant.clone())
332                            .try_fold(Vec::new(), |mut all, c| {
333                                all.extend(c?);
334                                Some(all)
335                            })
336                    }
337                    NodeRenderer::Add(_) => fold(held, 0.0, |a, b| a + b),
338                    NodeRenderer::Mul(_) => fold(held, 1.0, |a, b| a * b),
339                    _ => None,
340                };
341                Held {
342                    zero,
343                    nil,
344                    stateless: !self.node.holds_state() && all(|h| h.stateless),
345                    constant,
346                }
347            }
348        }
349    }
350
351    fn made(&self) -> NodeRenderer {
352        match &self.made {
353            Made::Zeros => match self.width {
354                1 => NodeRenderer::Const(0.0),
355                w => NodeRenderer::Join(vec![NodeRenderer::Const(0.0); w]),
356            },
357            Made::Minuend => self.operands[0].made(),
358            Made::Terms(live) => {
359                NodeRenderer::Add(live.iter().map(|&k| self.operands[k].made()).collect())
360            }
361            Made::Kept => {
362                let mut each = self.operands.iter();
363                rebuilt(self.node, &mut |_| {
364                    each.next().expect("one per operand").made()
365                })
366            }
367        }
368    }
369}
370
371fn finite(value: Option<Vec<f64>>) -> bool {
372    value.is_some_and(|v| v.iter().all(|x| x.is_finite()))
373}
374
375/// As the machine folds operands, each component from `start`, a mono operand read at every one.
376fn fold<'h>(
377    set: impl Iterator<Item = &'h Held>,
378    start: f64,
379    op: fn(f64, f64) -> f64,
380) -> Option<Vec<f64>> {
381    let values = set
382        .map(|h| h.constant.as_deref())
383        .collect::<Option<Vec<_>>>()?;
384    let width = values.iter().map(|v| v.len()).max().unwrap_or(1);
385    Some(
386        (0..width)
387            .map(|c| {
388                values
389                    .iter()
390                    .fold(start, |acc, v| op(acc, super::part(v, c)))
391            })
392            .collect(),
393    )
394}
395
396fn rebuilt(r: &NodeRenderer, each: &mut dyn FnMut(&NodeRenderer) -> NodeRenderer) -> NodeRenderer {
397    let mut one = |p: &NodeRenderer| Box::new(each(p));
398    match r {
399        NodeRenderer::Add(set) => NodeRenderer::Add(set.iter().map(&mut *each).collect()),
400        NodeRenderer::Mul(set) => NodeRenderer::Mul(set.iter().map(&mut *each).collect()),
401        NodeRenderer::Join(set) => NodeRenderer::Join(set.iter().map(&mut *each).collect()),
402        NodeRenderer::Sub(a, b) => NodeRenderer::Sub(one(a), one(b)),
403        NodeRenderer::Div(a, b) => NodeRenderer::Div(one(a), one(b)),
404        NodeRenderer::Pow(a, b) => NodeRenderer::Pow(one(a), one(b)),
405        NodeRenderer::Zip(f, a, b) => NodeRenderer::Zip(*f, one(a), one(b)),
406        NodeRenderer::Map(f, x) => NodeRenderer::Map(*f, one(x)),
407        NodeRenderer::Channel { x, k } => NodeRenderer::Channel { x: one(x), k: *k },
408        NodeRenderer::Crop {
409            x,
410            window,
411            a,
412            b,
413            rise,
414            fall,
415        } => NodeRenderer::Crop {
416            x: one(x),
417            window: *window,
418            a: *a,
419            b: *b,
420            rise: *rise,
421            fall: *fall,
422        },
423        NodeRenderer::Filter {
424            site,
425            from,
426            x,
427            cutoff,
428            q,
429            gain,
430        } => NodeRenderer::Filter {
431            site: *site,
432            from: *from,
433            x: one(x),
434            cutoff: one(cutoff),
435            q: one(q),
436            gain: one(gain),
437        },
438        NodeRenderer::Physics { site, from, args } => NodeRenderer::Physics {
439            site: *site,
440            from: *from,
441            args: args.iter().map(&mut *each).collect(),
442        },
443        NodeRenderer::Formula {
444            formula,
445            width,
446            time,
447        } => NodeRenderer::Formula {
448            formula: formula.clone(),
449            width: *width,
450            time: one(time),
451        },
452        NodeRenderer::Indexed { slot, index, reach } => NodeRenderer::Indexed {
453            slot: *slot,
454            index: held(index, &mut one),
455            reach: *reach,
456        },
457        NodeRenderer::Instant(index) => NodeRenderer::Instant(held(index, &mut one)),
458        leaf => leaf.clone(),
459    }
460}
461
462fn held(index: &Index, one: &mut dyn FnMut(&NodeRenderer) -> Box<NodeRenderer>) -> Index {
463    let mapped = index.mapped(&mut |t| Ok::<_, std::convert::Infallible>(one(t)));
464    match mapped {
465        Ok(index) => index,
466    }
467}