1mod 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#[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 Ok(Program {
39 ops: lowered.ops,
40 widths: lowered.widths,
41 args: lowered.args,
42 formulas: lowered.formulas,
43 indices: lowered.indices,
44 sites: layout.sites.clone(),
45 width,
46 })
47 }
48}
49
50#[derive(Clone)]
51enum State {
52 Filter(FilterSite),
53 Physics(Box<dyn Solver>),
54}
55
56impl Clone for Box<dyn Solver> {
57 fn clone(&self) -> Box<dyn Solver> {
58 self.boxed()
59 }
60}
61
62fn open(p: &Program, grid: Grid) -> Result<Vec<State>, SampleError> {
65 let mut lanes = vec![1usize; p.sites.len()];
66 for (slot, op) in p.ops.iter().enumerate() {
67 if let Op::Filter { site, .. } = op {
68 lanes[site.0 as usize] = p.widths[slot];
69 }
70 }
71 p.sites
72 .iter()
73 .zip(lanes)
74 .map(|(s, width)| {
75 Ok(match s {
76 Site::Filter(shape) => State::Filter(FilterSite::new(
77 *shape,
78 width,
79 &[0.0],
80 &[0.0],
81 &[0.0],
82 grid.sr(),
83 )),
84 Site::Physics(params) => State::Physics(site(params, grid.sr())?),
85 })
86 })
87 .collect()
88}
89
90fn part(v: &[f64], c: usize) -> f64 {
92 v[c.min(v.len() - 1)]
93}
94
95pub struct Machine {
98 program: Program,
99 states: Vec<State>,
100 block: Block,
101 grid: Grid,
102 ahead: Vec<(i64, Program)>,
104}
105
106#[derive(Clone)]
107pub struct MachineState {
108 sites: Vec<Site>,
109 states: Vec<State>,
110}
111
112impl State {
113 fn bytes(&self) -> usize {
114 match self {
115 State::Filter(filter) => filter.bytes(),
116 State::Physics(solver) => solver.bytes(),
117 }
118 }
119}
120
121impl MachineState {
122 pub fn bytes(&self) -> usize {
123 let states: usize = self.states.iter().map(State::bytes).sum();
124 size_of::<Self>() + std::mem::size_of_val(self.sites.as_slice()) + states
125 }
126}
127
128impl Machine {
129 pub fn over(spanned: &Spanned, at: i64) -> Result<Machine, SampleError> {
131 let grid = spanned.grid();
132 let mut ahead: Vec<(i64, Program)> = spanned
133 .compiled()
134 .iter()
135 .filter(|(span, _)| span.to > at)
136 .map(|(span, program)| (span.from, program.clone()))
137 .collect();
138 ahead.reverse();
139 let first = match ahead.pop() {
140 Some((_, program)) => program,
141 None => spanned.silent()?,
142 };
143 let states = open(&first, grid)?;
144 let block = Block::of(&first.widths);
145 Ok(Machine {
146 program: first,
147 states,
148 block,
149 grid,
150 ahead,
151 })
152 }
153
154 pub fn width(&self) -> usize {
155 self.program.width
156 }
157
158 pub fn stateful(&self) -> bool {
159 !self.program.sites.is_empty()
160 }
161
162 pub fn bytes(&self) -> usize {
163 self.states.iter().map(State::bytes).sum()
164 }
165
166 pub fn run_to(&mut self, to: i64, reads: &[Window], own: &mut Tape) -> Result<(), SampleError> {
167 for state in &mut self.states {
168 if let State::Filter(filter) = state {
169 filter.forget_frames();
170 }
171 }
172 self.steps(to, reads, own)
173 }
174
175 pub fn run_on(&mut self, to: i64, reads: &[Window], own: &mut Tape) -> Result<(), SampleError> {
177 self.steps(to, reads, own)
178 }
179
180 fn steps(&mut self, to: i64, reads: &[Window], own: &mut Tape) -> Result<(), SampleError> {
181 loop {
182 while let Some((from, _)) = self.ahead.last()
183 && *from <= own.end()
184 {
185 let (_, program) = self.ahead.pop().expect("a span ahead");
186 self.block = Block::of(&program.widths);
187 self.program = program;
188 }
189 let until = self.ahead.last().map_or(to, |(from, _)| (*from).min(to));
190 self.stepped(until, reads, own)?;
191 if own.end() >= to {
192 return Ok(());
193 }
194 }
195 }
196
197 fn stepped(&mut self, to: i64, reads: &[Window], own: &mut Tape) -> Result<(), SampleError> {
198 let p = &self.program;
199 while own.end() < to {
200 let from = own.end();
201 let most = (to - from).min(BLOCK as i64) as usize;
202 let len = p.block(from, most, &mut self.block.recurrent);
203 let here = Here {
204 reads,
205 own: own.window(),
206 grid: self.grid,
207 };
208 let (held, refused) =
209 block::run(p, &mut self.block, &here, &mut self.states, (from, len));
210 for i in 0..held {
211 let top = self.block.top(p, i);
212 for c in 0..p.width {
213 own.push(c, part(top, c));
214 }
215 }
216 if let Some(e) = refused {
217 return Err(e);
218 }
219 }
220 Ok(())
221 }
222
223 pub fn solver(&self, site: usize) -> Option<&dyn Solver> {
225 match self.states.get(site)? {
226 State::Physics(solver) => Some(solver.as_ref()),
227 State::Filter(_) => None,
228 }
229 }
230
231 pub fn filter(&self, site: usize) -> Option<&FilterSite> {
232 match self.states.get(site)? {
233 State::Filter(filter) => Some(filter),
234 State::Physics(_) => None,
235 }
236 }
237
238 pub fn state(&self) -> MachineState {
239 MachineState {
240 sites: self.program.sites.clone(),
241 states: self.states.clone(),
242 }
243 }
244
245 pub fn restart(&mut self) {
246 self.states = open(&self.program, self.grid).expect("the sites opened once already");
247 }
248
249 pub fn accepts(&self, held: &MachineState) -> bool {
251 held.sites == self.program.sites
252 }
253
254 pub fn carry(&mut self, held: &MachineState) -> bool {
256 let taken = self.accepts(held);
257 if taken {
258 self.states.clone_from(&held.states);
259 }
260 taken
261 }
262}
263
264impl Program {
265 fn block(&self, from: i64, most: usize, recurrent: &mut Vec<bool>) -> usize {
268 let reach: Vec<Option<usize>> = self
269 .ops
270 .iter()
271 .map(|op| own_reach(op, from, most))
272 .collect();
273 let len = reach
274 .iter()
275 .flatten()
276 .filter(|n| **n >= RUN)
277 .fold(most, |len, n| len.min(*n))
278 .max(1);
279 recurrent.clear();
280 for (slot, reach) in reach.iter().enumerate() {
281 let reads = self.args[slot].iter().any(|a| recurrent[*a]);
282 recurrent.push(reads || reach.is_some_and(|n| n < len));
283 }
284 len
285 }
286}
287
288fn own_reach(op: &Op, from: i64, most: usize) -> Option<usize> {
290 match op {
291 Op::Read {
292 slot: Slot::Own,
293 at,
294 }
295 | Op::ReadScaled {
296 slot: Slot::Own,
297 at,
298 ..
299 } => {
300 let last = |len: usize| from + len as i64 - 1;
301 let mut len = most;
302 while len > 1 && at.at(from).max(at.at(last(len))) >= from {
303 len /= 2;
304 }
305 Some(match at.at(from).max(at.at(last(len))) < from {
306 true => len,
307 false => 0,
308 })
309 }
310 Op::Indexed {
311 slot: Slot::Own,
312 reach,
313 ..
314 } => Some(match reach {
315 Some((_, most)) if *most < 0 => {
316 usize::try_from(most.unsigned_abs()).unwrap_or(usize::MAX)
317 }
318 _ => 0,
319 }),
320 _ => None,
321 }
322}
323
324const RUN: usize = 16;
326
327#[cfg(test)]
329mod counts {
330 use std::cell::Cell;
331
332 thread_local! {
333 pub(super) static PASSES: Cell<u64> = const { Cell::new(0) };
334 pub(super) static FILLS: Cell<u64> = const { Cell::new(0) };
335 pub(super) static READS: Cell<u64> = const { Cell::new(0) };
336 }
337}
338
339#[cfg(test)]
340mod tests {
341 use super::counts::{FILLS, PASSES, READS};
342 use super::renderer::{BufId, Grid, Index, Map, NodeRenderer, Round, Slot, WIDE};
343 use super::*;
344 use crate::collapse::Extent;
345
346 const LONG: [i64; 2] = [1489, 1721];
347
348 fn feedback() -> NodeRenderer {
350 let own = |lag: i64, k: usize| NodeRenderer::Channel {
351 x: Box::new(NodeRenderer::Read {
352 slot: Slot::Own,
353 map: Map::shift(-lag),
354 }),
355 k,
356 };
357 let input = NodeRenderer::Read {
358 slot: Slot::Read(BufId(0)),
359 map: Map::shift(0),
360 };
361 let line = |k: usize| {
362 let mix = LONG
363 .iter()
364 .enumerate()
365 .map(|(j, lag)| NodeRenderer::Mul(vec![NodeRenderer::Const(0.6), own(*lag, j)]));
366 let fed = NodeRenderer::Add(std::iter::once(input.clone()).chain(mix).collect());
367 NodeRenderer::Add(vec![
368 NodeRenderer::Mul(vec![NodeRenderer::Const(0.7), fed]),
369 NodeRenderer::Mul(vec![NodeRenderer::Const(0.2), own(1, k)]),
370 ])
371 };
372 NodeRenderer::Join(vec![line(0), line(1)])
373 }
374
375 fn ran(to: i64, step: i64) -> (Vec<Vec<f64>>, [u64; 3]) {
376 let layout = Layout {
377 grid: Grid::of(48_000),
378 width: 2,
379 read_widths: vec![1],
380 sites: Vec::new(),
381 };
382 let spanned =
383 Spanned::new(&feedback(), &layout, (0, to), &[Extent::EVERYWHERE]).expect("a program");
384 let mut input = Tape::new(1, to as usize, 0);
385 (0..to).for_each(|n| input.push(0, f64::from(u8::from(n % 4800 == 0))));
386 let mut out = Tape::new(2, to as usize, 0);
387 let mut machine = Machine::over(&spanned, 0).expect("a machine");
388 let counted = || [&PASSES, &FILLS, &READS].map(|c| c.with(std::cell::Cell::get));
389 let before = counted();
390 let mut at = 0;
391 while at < to {
392 at = (at + step).min(to);
393 machine
394 .run_to(at, &[input.window()], &mut out)
395 .expect("samples");
396 }
397 let after = counted();
398 (out.into_planes(), [0, 1, 2].map(|k| after[k] - before[k]))
399 }
400
401 #[test]
404 fn a_loop_reading_itself_one_sample_back_runs_a_pass_per_block() {
405 let to = 24_000;
406 let (whole, [passes, fills, reads]) = ran(to, to);
407 let (single, [one_by_one, ..]) = ran(to, 1);
408 assert_eq!(whole, single);
409 assert_eq!(one_by_one, to as u64);
410 let blocks = (to as u64).div_ceil(BLOCK as u64);
411 assert!(passes <= blocks + 1, "{passes} passes over {blocks} blocks");
412 let per_sample = 2 * 4 + 1;
413 let ops = feedback().ops(&Layout {
414 grid: Grid::of(48_000),
415 width: 2,
416 read_widths: vec![1],
417 sites: Vec::new(),
418 });
419 let ops = ops.expect("ops") as u64;
420 assert!(
421 fills <= passes * ops + per_sample * to as u64,
422 "{fills} op runs"
423 );
424 let far = 2 * 2 * LONG.iter().sum::<i64>() as u64;
425 assert!(reads <= 2 * 2 * to as u64 + far, "{reads} reads");
426 }
427
428 #[test]
431 fn identical_reads_of_a_loops_own_past_run_once() {
432 let to = 24_000;
433 let layout = Layout {
434 grid: Grid::of(48_000),
435 width: 2,
436 read_widths: vec![1],
437 sites: Vec::new(),
438 };
439 assert_eq!(feedback().ops(&layout).expect("ops"), 20);
440 let (planes, [_, fills, reads]) = ran(to, to);
441 let mut y = vec![vec![0.0f64; to as usize]; 2];
442 let past = |y: &[Vec<f64>], k: usize, n: i64| match n {
443 n if n < 0 => 0.0,
444 n => y[k][n as usize],
445 };
446 for n in 0..to {
447 let input = f64::from(u8::from(n % 4800 == 0));
448 let mut fed = 0.0 + input;
449 for (j, lag) in LONG.iter().enumerate() {
450 fed += 1.0 * 0.6 * past(&y, j, n - lag);
451 }
452 for k in 0..2 {
453 y[k][n as usize] = 0.0 + 1.0 * 0.7 * fed + 1.0 * 0.2 * past(&y, k, n - 1);
454 }
455 }
456 let bits = |p: &[Vec<f64>]| -> Vec<Vec<u64>> {
457 p.iter()
458 .map(|c| c.iter().map(|v| v.to_bits()).collect())
459 .collect()
460 };
461 assert_eq!(bits(&planes), bits(&y));
462 let blocks = (to as u64).div_ceil(BLOCK as u64) + 1;
463 let (last, channels, scaled, sums, join) = (1, 2, 2, 2, 1);
464 let per_sample = last + channels + scaled + sums + join;
465 assert!(
466 fills <= blocks * 20 + per_sample * to as u64,
467 "{fills} op runs"
468 );
469 let far = 2 * 2 * LONG.iter().sum::<i64>() as u64;
470 assert!(reads <= 2 * to as u64 + far, "{reads} reads");
471 }
472
473 fn delayed() -> NodeRenderer {
475 let now = Index::At(Map::whole(1, 0));
476 let length = NodeRenderer::Add(vec![
477 NodeRenderer::Const(0.002),
478 NodeRenderer::Mul(vec![
479 NodeRenderer::Const(0.000_2),
480 NodeRenderer::Map(
481 super::renderer::Unary::Sin,
482 Box::new(NodeRenderer::Mul(vec![
483 NodeRenderer::Const(18.85),
484 NodeRenderer::Time,
485 ])),
486 ),
487 ]),
488 ]);
489 let back = Index::Neg(Box::new(Index::Step(Box::new(length), Round::Floor)));
490 let echo = Index::Add(vec![now.clone(), Index::At(Map::whole(0, -1489))]);
491 NodeRenderer::Add(vec![
492 NodeRenderer::Indexed {
493 slot: Slot::Read(BufId(0)),
494 index: Index::Add(vec![now, back]),
495 reach: None,
496 },
497 NodeRenderer::Mul(vec![
498 NodeRenderer::Const(0.5),
499 NodeRenderer::Indexed {
500 slot: Slot::Own,
501 index: echo,
502 reach: Some((-1489, -1489)),
503 },
504 ]),
505 ])
506 }
507
508 #[test]
511 fn a_delay_and_an_echo_round_no_index_in_wide_integers() {
512 let to = 9_600;
513 let layout = Layout {
514 grid: Grid::of(48_000),
515 width: 1,
516 read_widths: vec![1],
517 sites: Vec::new(),
518 };
519 let spanned =
520 Spanned::new(&delayed(), &layout, (0, to), &[Extent::EVERYWHERE]).expect("a program");
521 let mut input = Tape::new(1, to as usize, 0);
522 (0..to).for_each(|n| input.push(0, (n as f64 * 0.01).sin()));
523 let mut out = Tape::new(1, to as usize, 0);
524 let mut machine = Machine::over(&spanned, 0).expect("a machine");
525 let before = WIDE.with(std::cell::Cell::get);
526 machine
527 .run_to(to, &[input.window()], &mut out)
528 .expect("samples");
529 assert_eq!(WIDE.with(std::cell::Cell::get), before);
530 }
531}