1use sva_formula::{Body, C64, Shape, SpectralSum};
4
5use crate::collapse::Extent;
6use crate::error::CollapseError;
7use crate::physics::Params;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
10pub struct BufId(pub u32);
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
13pub struct SiteId(pub u32);
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18pub struct Map {
19 pub a: i128,
20 pub b: i128,
21 pub d: i128,
22 pub between: Between,
23}
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
26pub enum Between {
27 Exact,
28 Floor,
29 Even,
30}
31
32impl Map {
33 pub const fn shift(b: i64) -> Map {
34 Map::whole(1, b)
35 }
36
37 pub const fn whole(a: i128, b: i64) -> Map {
39 Map {
40 a,
41 b: b as i128,
42 d: 1,
43 between: Between::Exact,
44 }
45 }
46
47 pub fn new(a: i128, b: i128, d: i128) -> Option<Map> {
49 Map::rounded(a, b, d, Between::Exact)
50 }
51
52 pub fn rounded(a: i128, b: i128, d: i128, between: Between) -> Option<Map> {
54 let g = gcd(gcd(a.abs(), b.abs()), d.abs()).max(1);
55 let sign = d.signum();
56 let limit = 1i128 << 100;
57 let map = Map {
58 a: sign * a / g,
59 b: sign * b / g,
60 d: d.abs() / g,
61 between,
62 };
63 let held = map.d > 0 && map.a.abs() < limit && map.b.abs() < limit && map.d < limit;
64 held.then(|| map.settled())
65 .filter(|m| m.d == 1 || m.between != Between::Exact)
66 }
67
68 fn settled(self) -> Map {
69 let exact = match self.between {
70 _ if self.d == 1 => true,
71 Between::Exact => false,
72 Between::Floor => self.a % self.d == 0,
73 Between::Even => {
74 let tie = 2 * self.b.rem_euclid(self.d) == self.d;
75 self.a % self.d == 0 && (!tie || (self.a / self.d) % 2 == 0)
76 }
77 };
78 match exact {
79 true => Map {
80 a: self.a / self.d,
81 b: self.index_at(0),
82 d: 1,
83 between: Between::Exact,
84 },
85 false => self,
86 }
87 }
88
89 pub fn at(self, n: i64) -> i64 {
90 let clamp = |k: i128| k.clamp(i128::from(i64::MIN), i128::from(i64::MAX)) as i64;
91 self.whole_at(n)
92 .unwrap_or_else(|| clamp(self.index_at(i128::from(n))))
93 }
94
95 fn whole_at(self, n: i64) -> Option<i64> {
96 if self.d != 1 {
97 return None;
98 }
99 let (a, b) = (i64::try_from(self.a).ok()?, i64::try_from(self.b).ok()?);
100 a.checked_mul(n)?.checked_add(b)
101 }
102
103 pub fn ahead(self) -> bool {
104 self.a != self.d || self.lead() > 0
105 }
106
107 pub fn lead(self) -> i64 {
108 let most = match self.between {
109 Between::Exact | Between::Floor => self.b.div_euclid(self.d),
110 Between::Even => (2 * self.b + self.d).div_euclid(2 * self.d),
111 };
112 most.clamp(i128::from(i64::MIN / 2), i128::from(i64::MAX / 2)) as i64
113 }
114
115 pub fn least(self) -> i64 {
116 let least = match self.between {
117 Between::Exact | Between::Floor => self.b.div_euclid(self.d),
118 Between::Even => (2 * self.b + self.d - 1).div_euclid(2 * self.d),
119 };
120 least.clamp(i128::from(i64::MIN / 2), i128::from(i64::MAX / 2)) as i64
121 }
122
123 pub fn image(self, over: Extent) -> Extent {
124 if over.is_empty() {
125 return over;
126 }
127 if self.a == 0 {
128 let at = self.at(0);
129 return Extent::new(at, at.saturating_add(1));
130 }
131 let ends = (first(over), last(over));
132 let at = |n: Option<i128>| n.map(|n| self.index_at(n));
133 let (lo, hi) = match self.a > 0 {
134 true => (at(ends.0), at(ends.1)),
135 false => (at(ends.1), at(ends.0)),
136 };
137 extent(lo, hi.map(|h| h + 1))
138 }
139
140 pub fn preimage(self, into: Extent) -> Extent {
143 if into.is_empty() {
144 return into;
145 }
146 if self.between == Between::Even {
147 let up = Map {
148 a: 2 * self.a,
149 b: 2 * self.b + self.d,
150 d: 2 * self.d,
151 between: Between::Floor,
152 };
153 let end = match into.end {
154 i64::MAX => i64::MAX,
155 e => e.saturating_add(1),
156 };
157 return up.preimage(Extent::new(into.start, end));
158 }
159 if self.a == 0 {
160 return match into.contains(self.at(0)) {
161 true => Extent::EVERYWHERE,
162 false => Extent::NOWHERE,
163 };
164 }
165 let (a, b, d) = (self.a, self.b, self.d);
166 let (first, last) = (first(into), last(into));
167 let lowest = |m: i128| ceil_div(m * d - b, a);
168 let highest = |m: i128| floor_div((m + 1) * d - 1 - b, a);
169 let (lo, hi) = match self.a > 0 {
170 true => (first.map(lowest), last.map(highest)),
171 false => (
172 last.map(|m| ceil_div((m + 1) * d - 1 - b, a)),
173 first.map(|m| floor_div(m * d - b, a)),
174 ),
175 };
176 extent(lo, hi.map(|h| h + 1))
177 }
178
179 fn index_at(self, n: i128) -> i128 {
180 let num = self.a.saturating_mul(n).saturating_add(self.b);
181 let (floor, rem) = (num.div_euclid(self.d), num.rem_euclid(self.d));
182 match self.between {
183 Between::Exact | Between::Floor => floor,
184 Between::Even => match (2 * rem).cmp(&self.d) {
185 std::cmp::Ordering::Less => floor,
186 std::cmp::Ordering::Greater => floor + 1,
187 std::cmp::Ordering::Equal => floor + floor.rem_euclid(2),
188 },
189 }
190 }
191}
192
193fn gcd(a: i128, b: i128) -> i128 {
194 match b {
195 0 => a,
196 b => gcd(b, a % b),
197 }
198}
199
200fn first(e: Extent) -> Option<i128> {
201 (e.start != i64::MIN).then(|| i128::from(e.start))
202}
203
204fn last(e: Extent) -> Option<i128> {
205 (e.end != i64::MAX).then(|| i128::from(e.end) - 1)
206}
207
208fn floor_div(num: i128, den: i128) -> i128 {
209 match den < 0 {
210 true => (-num).div_euclid(-den),
211 false => num.div_euclid(den),
212 }
213}
214
215fn ceil_div(num: i128, den: i128) -> i128 {
216 -floor_div(-num, den)
217}
218
219fn extent(lo: Option<i128>, hi: Option<i128>) -> Extent {
220 let clamp = |n: i128| n.clamp(i128::from(i64::MIN + 1), i128::from(i64::MAX - 1)) as i64;
221 let (start, end) = (lo.map_or(i64::MIN, clamp), hi.map_or(i64::MAX, clamp));
222 match start < end {
223 true => Extent::new(start, end),
224 false => Extent::NOWHERE,
225 }
226}
227
228#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
231pub struct Grid {
232 pub rate: u32,
233 pub a: i128,
234 pub d: i128,
235}
236
237impl Grid {
238 pub const fn of(rate: u32) -> Grid {
239 Grid { rate, a: 1, d: 1 }
240 }
241
242 pub fn finer(rate: u32, scale: usize) -> Grid {
244 Grid {
245 rate,
246 a: 1,
247 d: scale as i128,
248 }
249 }
250
251 pub fn is_rate(&self) -> bool {
252 (self.a, self.d) == (1, 1)
253 }
254
255 fn exact(&self, n: i64) -> Option<(i128, i128)> {
256 let num = self.a.checked_mul(i128::from(n))?;
257 Some((num, self.d.checked_mul(i128::from(self.rate))?))
258 }
259
260 pub fn instant(&self, n: i64) -> f64 {
263 if self.is_rate() {
264 return n as f64 / f64::from(self.rate);
265 }
266 let num = self.a.saturating_mul(i128::from(n));
267 num as f64 / self.d.saturating_mul(i128::from(self.rate)) as f64
268 }
269
270 pub fn position(&self, n: i64) -> f64 {
271 self.a.saturating_mul(i128::from(n)) as f64 / self.d as f64
272 }
273
274 pub fn sr(&self) -> f64 {
275 f64::from(self.rate) * self.d as f64 / self.a as f64
276 }
277
278 pub fn count(&self, t: f64) -> f64 {
279 t * f64::from(self.rate) * self.d as f64 / self.a as f64
280 }
281
282 pub fn step_at(&self, t: f64, round: Round) -> Option<i64> {
285 if !t.is_finite() {
286 return None;
287 }
288 let bits = t.abs().to_bits();
289 let (exp, frac) = ((bits >> 52) as i32, (bits & ((1 << 52) - 1)) as i128);
290 let (mantissa, shift) = match exp {
291 0 => (frac, 1074),
292 e => (frac | (1 << 52), 1075 - e),
293 };
294 let zeros = mantissa.trailing_zeros().min(127) as i32;
295 let (mantissa, shift) = match mantissa {
296 0 => (0, 0),
297 m => (m >> zeros, shift - zeros),
298 };
299 let mantissa = if t < 0.0 { -mantissa } else { mantissa };
300 let (num, den) = match shift {
301 s if s <= 0 => (mantissa.checked_mul(1i128.checked_shl((-s) as u32)?)?, 1),
302 s if s < 127 => (mantissa, 1i128 << s),
303 _ => return None,
304 };
305 let top = num.checked_mul(self.d.checked_mul(i128::from(self.rate))?)?;
306 let bottom = self.a.checked_mul(den)?;
307 let (floor, rem) = (top.div_euclid(bottom), top.rem_euclid(bottom));
308 let k = match round {
309 Round::Floor => floor,
310 Round::Ceil => floor + i128::from(rem != 0),
311 Round::Even => match (2 * rem).cmp(&bottom) {
312 std::cmp::Ordering::Less => floor,
313 std::cmp::Ordering::Greater => floor + 1,
314 std::cmp::Ordering::Equal => floor + floor.rem_euclid(2),
315 },
316 };
317 i64::try_from(k).ok()
318 }
319}
320
321#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
326pub struct Wrap {
327 pub scale: (i128, i128),
328 pub shift: (i128, i128),
329 pub gain: (i128, i128),
330 pub inner: [(i128, i128); 2],
331 pub period: (i128, i128),
332}
333
334impl Wrap {
335 pub fn on(self, grid: Grid) -> Option<Stepped> {
337 let (_, rate) = grid.exact(0)?;
338 let [(s, sd), (o, od)] = self.inner;
339 let over = sd.checked_mul(rate)?;
340 let den = lcm(lcm(over, od)?, self.period.1)?;
341 let line = self.scale.1.checked_mul(rate)?;
342 let wrapped = self.gain.1.checked_mul(den)?;
343 let whole = lcm(lcm(line, self.shift.1)?, wrapped)?;
344 Some(Stepped {
345 step: grid.a,
346 inner: s,
347 over: den / over,
348 offset: o.checked_mul(den / od)?,
349 period: self.period.0.checked_mul(den / self.period.1)?,
350 scale: self.scale.0,
351 line: whole / line,
352 shift: self.shift.0.checked_mul(whole / self.shift.1)?,
353 gain: self.gain.0,
354 wrapped: whole / wrapped,
355 whole,
356 })
357 }
358
359 pub fn most(self, t: f64) -> f64 {
361 let q = |(num, den): (i128, i128)| num as f64 / den as f64;
362 q(self.scale).abs() * t.abs() + q(self.shift).abs() + q(self.gain).abs() * q(self.period)
363 }
364}
365
366#[derive(Clone, Copy, Debug, PartialEq, Eq)]
367pub struct Stepped {
368 step: i128,
369 inner: i128,
370 over: i128,
371 offset: i128,
372 period: i128,
373 scale: i128,
374 line: i128,
375 shift: i128,
376 gain: i128,
377 wrapped: i128,
378 whole: i128,
379}
380
381impl Stepped {
382 pub fn at(self, n: i64) -> Option<f64> {
384 let n = self.step.checked_mul(i128::from(n))?;
385 let x = self
386 .inner
387 .checked_mul(n)?
388 .checked_mul(self.over)?
389 .checked_add(self.offset)?;
390 let rem = x.rem_euclid(self.period);
391 let sum = self
392 .scale
393 .checked_mul(n)?
394 .checked_mul(self.line)?
395 .checked_add(self.shift)?
396 .checked_add(self.gain.checked_mul(rem)?.checked_mul(self.wrapped)?)?;
397 Some(sum as f64 / self.whole as f64)
398 }
399}
400
401fn lcm(a: i128, b: i128) -> Option<i128> {
402 (a / gcd(a, b)).checked_mul(b)
403}
404
405#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
406pub enum Round {
407 Even,
408 Floor,
409 Ceil,
410}
411
412#[derive(Clone, Debug, PartialEq)]
414pub enum Index<T = Box<NodeRenderer>> {
415 At(Map),
416 Step(T, Round),
417 Add(Vec<Index<T>>),
418 Neg(Box<Index<T>>),
419 Mul(Vec<Index<T>>),
420}
421
422impl<T> Index<T> {
423 pub fn times(&self) -> Vec<&T> {
424 let mut out = Vec::new();
425 self.each(&mut |t| out.push(t));
426 out
427 }
428
429 fn each<'a>(&'a self, f: &mut impl FnMut(&'a T)) {
430 match self {
431 Index::At(_) => {}
432 Index::Step(t, _) => f(t),
433 Index::Add(parts) | Index::Mul(parts) => parts.iter().for_each(|p| p.each(f)),
434 Index::Neg(p) => p.each(f),
435 }
436 }
437
438 pub fn mapped<U, E>(&self, f: &mut impl FnMut(&T) -> Result<U, E>) -> Result<Index<U>, E> {
439 let mut each = |parts: &[Index<T>]| -> Result<Vec<Index<U>>, E> {
440 parts.iter().map(|p| p.mapped(f)).collect()
441 };
442 Ok(match self {
443 Index::At(map) => Index::At(*map),
444 Index::Step(t, round) => Index::Step(f(t)?, *round),
445 Index::Add(parts) => Index::Add(each(parts)?),
446 Index::Mul(parts) => Index::Mul(each(parts)?),
447 Index::Neg(p) => Index::Neg(Box::new(p.mapped(f)?)),
448 })
449 }
450
451 pub fn at(&self, n: i64, grid: Grid, time: &impl Fn(&T) -> f64) -> Option<i64> {
452 match self {
453 Index::At(map) => map
454 .whole_at(n)
455 .or_else(|| i64::try_from(map.index_at(i128::from(n))).ok()),
456 Index::Step(t, round) => grid.step_at(time(t), *round),
457 Index::Add(parts) => parts
458 .iter()
459 .try_fold(0i64, |held, p| held.checked_add(p.at(n, grid, time)?)),
460 Index::Mul(parts) => parts
461 .iter()
462 .try_fold(1i64, |held, p| held.checked_mul(p.at(n, grid, time)?)),
463 Index::Neg(p) => p.at(n, grid, time)?.checked_neg(),
464 }
465 }
466}
467
468#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
470pub enum Slot {
471 Read(BufId),
472 Own,
473}
474
475#[derive(Clone, Copy, Debug, PartialEq, Eq)]
476pub enum Unary {
477 Sin,
478 Cos,
479 Exp,
480 Sqrt,
481 Abs,
482 Tanh,
483 Log,
484 Sat,
485 Step,
486}
487
488#[derive(Clone, Copy, Debug, PartialEq, Eq)]
489pub enum Binary {
490 Max,
491 Min,
492 Mod,
493}
494
495#[derive(Clone, Debug, PartialEq)]
498pub enum Formula {
499 Sum(Box<SpectralSum>),
500 Written(Box<Body>),
501 Drawn { seed: u64, rate: u32 },
502}
503
504impl Formula {
505 pub fn at(&self, component: usize, t: f64) -> Result<f64, CollapseError> {
506 let value: C64 =
507 match self {
508 Formula::Drawn { seed, rate } => {
509 let step = Grid::of(*rate).step_at(t, Round::Even).ok_or(
510 CollapseError::NotEvaluable("a draw at an instant past any step"),
511 )?;
512 return Ok(sva_formula::draw(*seed, step));
513 }
514 Formula::Sum(sum) => crate::collapse::eval_spectral_sum_at(sum, component, t)?,
515 Formula::Written(body) => {
516 crate::collapse::eval_written_at(body, component, t, &crate::collapse::NoRefs)?
517 }
518 };
519 Ok(value.re)
520 }
521
522 pub fn ops(&self) -> usize {
524 fn terms(body: &Body) -> usize {
525 1 + sva_formula::closed_form::children(body)
526 .iter()
527 .map(|p| terms(&p.body))
528 .sum::<usize>()
529 }
530 match self {
531 Formula::Sum(sum) => sum.atoms().count().max(1),
532 Formula::Written(body) => terms(body),
533 Formula::Drawn { .. } => 1,
534 }
535 }
536}
537
538#[derive(Clone, Debug, PartialEq)]
541pub enum NodeRenderer {
542 Const(f64),
543 Time,
544 Wrap(Wrap),
545 Read {
546 slot: Slot,
547 map: Map,
548 },
549 Formula {
551 formula: Formula,
552 width: usize,
553 time: Box<NodeRenderer>,
554 },
555 Noise(u64),
556 Indexed {
559 slot: Slot,
560 index: Index,
561 reach: Option<(i64, i64)>,
562 },
563 Instant(Index),
565 Add(Vec<NodeRenderer>),
566 Mul(Vec<NodeRenderer>),
567 Sub(Box<NodeRenderer>, Box<NodeRenderer>),
568 Div(Box<NodeRenderer>, Box<NodeRenderer>),
569 Pow(Box<NodeRenderer>, Box<NodeRenderer>),
570 Map(Unary, Box<NodeRenderer>),
571 Zip(Binary, Box<NodeRenderer>, Box<NodeRenderer>),
572 Crop {
575 x: Box<NodeRenderer>,
576 window: (i64, i64),
577 a: f64,
578 b: f64,
579 rise: f64,
580 fall: f64,
581 },
582 Join(Vec<NodeRenderer>),
583 Channel {
584 x: Box<NodeRenderer>,
585 k: usize,
586 },
587 Filter {
589 site: SiteId,
590 from: i64,
591 x: Box<NodeRenderer>,
592 cutoff: Box<NodeRenderer>,
593 q: Box<NodeRenderer>,
594 gain: Box<NodeRenderer>,
595 },
596 Physics {
597 site: SiteId,
598 from: i64,
599 args: Vec<NodeRenderer>,
600 },
601}
602
603impl NodeRenderer {
604 pub fn stateless(&self) -> bool {
607 !self.holds_state() && self.operands().into_iter().all(NodeRenderer::stateless)
608 }
609
610 pub(crate) fn holds_state(&self) -> bool {
611 matches!(
612 self,
613 NodeRenderer::Filter { .. }
614 | NodeRenderer::Physics { .. }
615 | NodeRenderer::Read {
616 slot: Slot::Own,
617 ..
618 }
619 | NodeRenderer::Indexed {
620 slot: Slot::Own,
621 ..
622 }
623 )
624 }
625
626 pub(crate) fn operands(&self) -> Vec<&NodeRenderer> {
628 match self {
629 NodeRenderer::Add(set) | NodeRenderer::Mul(set) | NodeRenderer::Join(set) => {
630 set.iter().collect()
631 }
632 NodeRenderer::Sub(a, b)
633 | NodeRenderer::Div(a, b)
634 | NodeRenderer::Pow(a, b)
635 | NodeRenderer::Zip(_, a, b) => vec![a, b],
636 NodeRenderer::Map(_, x)
637 | NodeRenderer::Crop { x, .. }
638 | NodeRenderer::Channel { x, .. } => vec![x],
639 NodeRenderer::Filter {
640 x, cutoff, q, gain, ..
641 } => vec![x, cutoff, q, gain],
642 NodeRenderer::Physics { args, .. } => args.iter().collect(),
643 NodeRenderer::Formula { time, .. } => vec![time],
644 NodeRenderer::Indexed { index, .. } | NodeRenderer::Instant(index) => {
645 index.times().into_iter().map(|t| &**t).collect()
646 }
647 NodeRenderer::Const(_)
648 | NodeRenderer::Time
649 | NodeRenderer::Wrap(_)
650 | NodeRenderer::Noise(_)
651 | NodeRenderer::Read { .. } => Vec::new(),
652 }
653 }
654}
655
656#[derive(Clone, Debug, PartialEq)]
657pub enum Site {
658 Filter(Shape),
659 Physics(Box<Params>),
660}
661
662impl From<sva_formula::Unary> for Unary {
663 fn from(written: sva_formula::Unary) -> Unary {
664 match written {
665 sva_formula::Unary::Sin => Unary::Sin,
666 sva_formula::Unary::Cos => Unary::Cos,
667 sva_formula::Unary::Exp => Unary::Exp,
668 sva_formula::Unary::Sqrt => Unary::Sqrt,
669 sva_formula::Unary::Abs => Unary::Abs,
670 sva_formula::Unary::Tanh => Unary::Tanh,
671 sva_formula::Unary::Log => Unary::Log,
672 sva_formula::Unary::Sat => Unary::Sat,
673 sva_formula::Unary::Step => Unary::Step,
674 }
675 }
676}
677
678impl Unary {
679 pub fn apply(self, x: f64) -> f64 {
680 match self {
681 Unary::Sin => x.sin(),
682 Unary::Cos => x.cos(),
683 Unary::Exp => x.exp(),
684 Unary::Sqrt => x.sqrt(),
685 Unary::Abs => x.abs(),
686 Unary::Tanh => x.tanh(),
687 Unary::Log => x.ln(),
688 Unary::Sat => x.clamp(-1.0, 1.0),
689 Unary::Step => sva_formula::affine::step(x),
690 }
691 }
692}
693
694impl Binary {
695 pub fn apply(self, a: f64, b: f64) -> f64 {
696 match self {
697 Binary::Max => a.max(b),
698 Binary::Min => a.min(b),
699 Binary::Mod => a.rem_euclid(b),
700 }
701 }
702}