Skip to main content

sva_formula/spectral_sum/
mod.rs

1// Concern: declares SpectralSum and Lane, the canonical form of a closed form | Non-concern: producing one (build.rs) | IO: none
2
3pub mod atom;
4pub mod build;
5pub mod image;
6pub(crate) mod kink;
7pub mod merge;
8pub mod product;
9pub mod spread;
10pub mod sup;
11
12use crate::closed_form::{Body, ModalBank, Part, Series, Var, map_children};
13use crate::origin::Origin;
14use atom::SpectralAtom;
15
16/// The infinite two sit beside the atoms because they carry their own truncation.
17#[derive(Clone, Debug, PartialEq, Default)]
18pub struct Lane {
19    pub atoms: Vec<SpectralAtom>,
20    pub series: Vec<Series>,
21    pub modal: Vec<ModalBank>,
22}
23
24#[derive(Clone, Debug, PartialEq)]
25pub struct SpectralSum {
26    pub var: Var,
27    pub lanes: Vec<Lane>,
28}
29
30impl Lane {
31    pub fn of(atoms: Vec<SpectralAtom>) -> Lane {
32        Lane {
33            atoms,
34            ..Lane::default()
35        }
36    }
37
38    pub fn is_empty(&self) -> bool {
39        self.atoms.is_empty() && self.series.is_empty() && self.modal.is_empty()
40    }
41
42    /// Finitely many atoms is what every product rule is written over.
43    pub fn is_finite_sum(&self) -> bool {
44        self.series.is_empty() && self.modal.is_empty()
45    }
46
47    pub fn expanded(mut self) -> Lane {
48        for bank in std::mem::take(&mut self.modal) {
49            self.atoms
50                .extend(crate::modal::atoms(&bank, crate::origin::Origin::UNKNOWN));
51        }
52        self
53    }
54}
55
56impl SpectralSum {
57    pub fn of(var: Var, lanes: Vec<Lane>) -> SpectralSum {
58        SpectralSum { var, lanes }
59    }
60
61    pub fn mono(var: Var, atoms: Vec<SpectralAtom>) -> SpectralSum {
62        SpectralSum {
63            var,
64            lanes: vec![Lane::of(atoms)],
65        }
66    }
67
68    pub fn width(&self) -> usize {
69        self.lanes.len()
70    }
71
72    pub fn atoms(&self) -> impl Iterator<Item = &SpectralAtom> {
73        self.lanes.iter().flat_map(|l| l.atoms.iter())
74    }
75
76    /// The same value, every atom and term naming `origin` as where it was written.
77    pub fn located(mut self, origin: Origin) -> SpectralSum {
78        for lane in &mut self.lanes {
79            for atom in &mut lane.atoms {
80                atom.origin = origin;
81            }
82            for series in &mut lane.series {
83                series.term = Part::new(origin, at(&series.term.body, origin));
84            }
85        }
86        self
87    }
88}
89
90fn at(f: &Body, origin: Origin) -> Body {
91    map_children(f, |p| Part::new(origin, at(&p.body, origin)))
92}