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