diff -r 000000000000 -r e8f3b6c55ce7 src/discrete.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/discrete.rs Fri Nov 28 12:48:17 2025 -0500 @@ -0,0 +1,1143 @@ +//! This module implementes discrete measures. + +use super::base::*; +use super::delta::*; +use alg_tools::collection::Collection; +use alg_tools::instance::{ClosedSpace, Decomposition, EitherDecomp, Instance, MyCow, Space}; +use alg_tools::iter::{MapF, Mappable}; +use alg_tools::linops::{Linear, Mapping}; +use alg_tools::loc::Loc; +use alg_tools::nalgebra_support::ToNalgebraRealField; +use alg_tools::norms::{Norm, Normed}; +use alg_tools::self_ownable; +use alg_tools::tabledump::TableDump; +use alg_tools::types::*; +use nalgebra::DVector; +use serde::ser::{Serialize, SerializeSeq, Serializer}; +use std::iter::Sum; +use std::ops::{ + Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, +}; + +/// Representation of a discrete measure. +/// +/// This is the measure $μ = ∑_{k=1}^n α_k δ_{x_k}$, consisting of several +/// [`DeltaMeasure`], i.e., “spikes” $α_k δ_{x_k}$ with weights $\alpha_k$ in `F` at locations +/// $x_k$ in `Domain`. +#[derive(Clone, Debug)] +pub struct DiscreteMeasure { + pub(super) spikes: Vec>, +} + +pub type RNDM = DiscreteMeasure, F>; + +/// Iterator over the [`DeltaMeasure`] spikes of a [`DiscreteMeasure`]. +pub type SpikeIter<'a, Domain, F> = std::slice::Iter<'a, DeltaMeasure>; + +/// Iterator over mutable [`DeltaMeasure`] spikes of a [`DiscreteMeasure`]. +pub type SpikeIterMut<'a, Domain, F> = std::slice::IterMut<'a, DeltaMeasure>; + +/// Iterator over the locations of the spikes of a [`DiscreteMeasure`]. +pub type LocationIter<'a, Domain, F> = + std::iter::Map, fn(&'a DeltaMeasure) -> &'a Domain>; + +/// Iterator over the masses of the spikes of a [`DiscreteMeasure`]. +pub type MassIter<'a, Domain, F> = + std::iter::Map, fn(&'a DeltaMeasure) -> F>; + +/// Iterator over the mutable locations of the spikes of a [`DiscreteMeasure`]. +pub type MassIterMut<'a, Domain, F> = std::iter::Map< + SpikeIterMut<'a, Domain, F>, + for<'r> fn(&'r mut DeltaMeasure) -> &'r mut F, +>; + +impl DiscreteMeasure { + /// Create a new zero measure (empty spike set). + pub fn new() -> Self { + DiscreteMeasure { spikes: Vec::new() } + } + + /// Number of [`DeltaMeasure`] spikes in the measure + #[inline] + pub fn len(&self) -> usize { + self.spikes.len() + } + + /// Replace with the zero measure. + #[inline] + pub fn clear(&mut self) { + self.spikes.clear() + } + + /// Remove `i`:th spike, not maintaining order. + /// + /// Panics if indiex is out of bounds. + #[inline] + pub fn swap_remove(&mut self, i: usize) -> DeltaMeasure { + self.spikes.swap_remove(i) + } + + /// Iterate over (references to) the [`DeltaMeasure`] spikes in this measure + #[inline] + pub fn iter_spikes(&self) -> SpikeIter<'_, Domain, F> { + self.spikes.iter() + } + + /// Iterate over mutable references to the [`DeltaMeasure`] spikes in this measure + #[inline] + pub fn iter_spikes_mut(&mut self) -> SpikeIterMut<'_, Domain, F> { + self.spikes.iter_mut() + } + + /// Iterate over the location of the spikes in this measure + #[inline] + pub fn iter_locations(&self) -> LocationIter<'_, Domain, F> { + self.iter_spikes().map(DeltaMeasure::get_location) + } + + /// Iterate over the masses of the spikes in this measure + #[inline] + pub fn iter_masses(&self) -> MassIter<'_, Domain, F> { + self.iter_spikes().map(DeltaMeasure::get_mass) + } + + /// Iterate over the masses of the spikes in this measure + #[inline] + pub fn iter_masses_mut(&mut self) -> MassIterMut<'_, Domain, F> { + self.iter_spikes_mut().map(DeltaMeasure::get_mass_mut) + } + + /// Update the masses of all the spikes to those produced by an iterator. + #[inline] + pub fn set_masses>(&mut self, iter: I) { + self.spikes + .iter_mut() + .zip(iter) + .for_each(|(δ, α)| δ.set_mass(α)); + } + + /// Update the locations of all the spikes to those produced by an iterator. + #[inline] + pub fn set_locations<'a, I: Iterator>(&mut self, iter: I) + where + Domain: 'static + Clone, + { + self.spikes + .iter_mut() + .zip(iter.cloned()) + .for_each(|(δ, α)| δ.set_location(α)); + } + + // /// Map the masses of all the spikes using a function and an iterator + // #[inline] + // pub fn zipmap_masses< + // I : Iterator, + // G : Fn(F, I::Item) -> F + // > (&mut self, iter : I, g : G) { + // self.spikes.iter_mut().zip(iter).for_each(|(δ, v)| δ.set_mass(g(δ.get_mass(), v))); + // } + + /// Prune all spikes with zero mass. + #[inline] + pub fn prune(&mut self) { + self.prune_by(|δ| δ.α != F::ZERO); + } + + /// Prune spikes by the predicate `g`. + #[inline] + pub fn prune_by) -> bool>(&mut self, g: G) { + self.spikes.retain(g); + } + + /// Add the spikes produced by `iter` to this measure. + #[inline] + pub fn extend>>(&mut self, iter: I) { + self.spikes.extend(iter); + } + + /// Add a spike to the measure + #[inline] + pub fn push(&mut self, δ: DeltaMeasure) { + self.spikes.push(δ); + } + + /// Iterate over triples of masses and locations of two discrete measures, which are assumed + /// to have equal locations of same spike indices. + pub fn both_matching<'a>( + &'a self, + other: &'a DiscreteMeasure, + ) -> impl Iterator { + let m = self.len().max(other.len()); + self.iter_spikes() + .map(Some) + .chain(std::iter::repeat(None)) + .zip(other.iter_spikes().map(Some).chain(std::iter::repeat(None))) + .take(m) + .map(|(oδ, orδ)| { + match (oδ, orδ) { + (Some(δ), Some(rδ)) => (δ.α, rδ.α, &δ.x), // Assumed δ.x=rδ.x + (Some(δ), None) => (δ.α, F::ZERO, &δ.x), + (None, Some(rδ)) => (F::ZERO, rδ.α, &rδ.x), + (None, None) => panic!("This cannot happen!"), + } + }) + } + + /// Subtract `other` from `self`, assuming equal locations of same spike indices + pub fn sub_matching(&self, other: &DiscreteMeasure) -> DiscreteMeasure + where + Domain: Clone, + { + self.both_matching(other) + .map(|(α, β, x)| (x.clone(), α - β)) + .collect() + } + + /// Add `other` to `self`, assuming equal locations of same spike indices + pub fn add_matching(&self, other: &DiscreteMeasure) -> DiscreteMeasure + where + Domain: Clone, + { + self.both_matching(other) + .map(|(α, β, x)| (x.clone(), α + β)) + .collect() + } + + /// Calculate the Radon-norm distance of `self` to `other`, + /// assuming equal locations of same spike indices. + pub fn dist_matching(&self, other: &DiscreteMeasure) -> F + where + F: Float, + { + self.both_matching(other) + .map(|(α, β, _)| (α - β).abs()) + .sum() + } +} + +impl IntoIterator for DiscreteMeasure { + type Item = DeltaMeasure; + type IntoIter = std::vec::IntoIter>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.spikes.into_iter() + } +} + +impl<'a, Domain, F: Num> IntoIterator for &'a DiscreteMeasure { + type Item = &'a DeltaMeasure; + type IntoIter = SpikeIter<'a, Domain, F>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.spikes.iter() + } +} + +impl Sum> for DiscreteMeasure { + // Required method + fn sum(iter: I) -> Self + where + I: Iterator>, + { + Self::from_iter(iter) + } +} + +impl<'a, Domain: Clone, F: Num> Sum<&'a DeltaMeasure> for DiscreteMeasure { + // Required method + fn sum(iter: I) -> Self + where + I: Iterator>, + { + Self::from_iter(iter.cloned()) + } +} + +impl Sum> for DiscreteMeasure { + // Required method + fn sum(iter: I) -> Self + where + I: Iterator>, + { + Self::from_iter(iter.map(|μ| μ.into_iter()).flatten()) + } +} + +impl<'a, Domain: Clone, F: Num> Sum<&'a DiscreteMeasure> for DiscreteMeasure { + // Required method + fn sum(iter: I) -> Self + where + I: Iterator>, + { + Self::from_iter(iter.map(|μ| μ.iter_spikes()).flatten().cloned()) + } +} + +impl DiscreteMeasure { + /// Computes `μ1 ← θ * μ1 - ζ * μ2`, pruning entries where both `μ1` (`self`) and `μ2` have + // zero weight. `μ2` will contain a pruned copy of pruned original `μ1` without arithmetic + /// performed. **This expects `self` and `μ2` to have matching coordinates in each index**. + // `μ2` can be than `self`, but not longer. + pub fn pruning_sub(&mut self, θ: F, ζ: F, μ2: &mut Self) { + for δ in &self[μ2.len()..] { + μ2.push(DeltaMeasure { x: δ.x.clone(), α: F::ZERO }); + } + debug_assert_eq!(self.len(), μ2.len()); + let mut dest = 0; + for i in 0..self.len() { + let α = self[i].α; + let α_new = θ * α - ζ * μ2[i].α; + if dest < i { + μ2[dest] = DeltaMeasure { x: self[i].x.clone(), α }; + self[dest] = DeltaMeasure { x: self[i].x.clone(), α: α_new }; + } else { + μ2[i].α = α; + self[i].α = α_new; + } + dest += 1; + } + self.spikes.truncate(dest); + μ2.spikes.truncate(dest); + } +} + +impl DiscreteMeasure { + /// Prune all spikes with mass absolute value less than the given `tolerance`. + #[inline] + pub fn prune_approx(&mut self, tolerance: F) { + self.spikes.retain(|δ| δ.α.abs() > tolerance); + } +} + +impl DiscreteMeasure { + /// Extracts the masses of the spikes as a [`DVector`]. + pub fn masses_dvector(&self) -> DVector { + DVector::from_iterator( + self.len(), + self.iter_masses().map(|α| α.to_nalgebra_mixed()), + ) + } + + /// Sets the masses of the spikes from the values of a [`DVector`]. + pub fn set_masses_dvector(&mut self, x: &DVector) { + self.set_masses(x.iter().map(|&α| F::from_nalgebra_mixed(α))); + } + + // /// Extracts the masses of the spikes as a [`Vec`]. + // pub fn masses_vec(&self) -> Vec { + // self.iter_masses() + // .map(|α| α.to_nalgebra_mixed()) + // .collect() + // } + + // /// Sets the masses of the spikes from the values of a [`Vec`]. + // pub fn set_masses_vec(&mut self, x : &Vec) { + // self.set_masses(x.iter().map(|&α| F::from_nalgebra_mixed(α))); + // } +} + +// impl Index for DiscreteMeasure { +// type Output = DeltaMeasure; +// #[inline] +// fn index(&self, i : usize) -> &Self::Output { +// self.spikes.index(i) +// } +// } + +// impl IndexMut for DiscreteMeasure { +// #[inline] +// fn index_mut(&mut self, i : usize) -> &mut Self::Output { +// self.spikes.index_mut(i) +// } +// } + +impl]>> Index + for DiscreteMeasure +{ + type Output = ]>>::Output; + #[inline] + fn index(&self, i: I) -> &Self::Output { + self.spikes.index(i) + } +} + +impl]>> IndexMut + for DiscreteMeasure +{ + #[inline] + fn index_mut(&mut self, i: I) -> &mut Self::Output { + self.spikes.index_mut(i) + } +} + +impl>, const K: usize> From<[D; K]> + for DiscreteMeasure +{ + #[inline] + fn from(list: [D; K]) -> Self { + list.into_iter().collect() + } +} + +impl From>> for DiscreteMeasure { + #[inline] + fn from(spikes: Vec>) -> Self { + DiscreteMeasure { spikes } + } +} + +impl<'a, Domain, F: Num, D> From<&'a [D]> for DiscreteMeasure +where + &'a D: Into>, +{ + #[inline] + fn from(list: &'a [D]) -> Self { + list.into_iter().map(|d| d.into()).collect() + } +} + +impl From> for DiscreteMeasure { + #[inline] + fn from(δ: DeltaMeasure) -> Self { + DiscreteMeasure { spikes: vec![δ] } + } +} + +impl<'a, Domain: Clone, F: Num> From<&'a DeltaMeasure> for DiscreteMeasure { + #[inline] + fn from(δ: &'a DeltaMeasure) -> Self { + DiscreteMeasure { spikes: vec![δ.clone()] } + } +} + +impl>> FromIterator + for DiscreteMeasure +{ + #[inline] + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + DiscreteMeasure { spikes: iter.into_iter().map(|m| m.into()).collect() } + } +} + +impl<'a, F: Num, const N: usize> TableDump<'a> for DiscreteMeasure, F> +where + DeltaMeasure, F>: Serialize + 'a, +{ + type Iter = std::slice::Iter<'a, DeltaMeasure, F>>; + + // fn tabledump_headers(&'a self) -> Vec { + // let mut v : Vec = (0..N).map(|i| format!("x{}", i)).collect(); + // v.push("weight".into()); + // v + // } + + fn tabledump_entries(&'a self) -> Self::Iter { + // Ensure order matching the headers above + self.spikes.iter() + } +} + +// Need to manually implement serialisation for DeltaMeasure, F> [`csv`] writer fails on +// structs with nested arrays as well as with #[serde(flatten)]. +// Then derive no longer works for DiscreteMeasure +impl Serialize for DiscreteMeasure, F> +where + F: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut s = serializer.serialize_seq(Some(self.spikes.len()))?; + for δ in self.spikes.iter() { + s.serialize_element(δ)?; + } + s.end() + } +} + +impl Measure for DiscreteMeasure { + type Domain = Domain; +} + +impl Norm for DiscreteMeasure +where + DeltaMeasure: Norm, +{ + #[inline] + fn norm(&self, _: Radon) -> F { + self.spikes.iter().map(|m| m.norm(Radon)).sum() + } +} + +impl Mapping for DiscreteMeasure +where + Domain: Space, + G::Codomain: Sum + Mul, + G: Mapping + Clone + ClosedSpace, + for<'b> &'b Domain: Instance, +{ + type Codomain = G::Codomain; + + #[inline] + fn apply>(&self, g: I) -> Self::Codomain { + g.eval(|g| self.spikes.iter().map(|m| g.apply(&m.x) * m.α).sum()) + } +} + +impl Linear for DiscreteMeasure +where + Domain: Space, + G::Codomain: Sum + Mul, + G: Mapping + Clone + ClosedSpace, + for<'b> &'b Domain: Instance, +{ +} + +/// Helper trait for constructing arithmetic operations for combinations +/// of [`DiscreteMeasure`] and [`DeltaMeasure`], and their references. +trait Lift { + type Producer: Iterator>; + + #[allow(dead_code)] + /// Lifts `self` into a [`DiscreteMeasure`]. + fn lift(self) -> DiscreteMeasure; + + /// Lifts `self` into a [`DiscreteMeasure`], apply either `f` or `f_mut` whether the type + /// this method is implemented for is a reference or or not. + fn lift_with( + self, + f: impl Fn(&DeltaMeasure) -> DeltaMeasure, + f_mut: impl FnMut(&mut DeltaMeasure), + ) -> DiscreteMeasure; + + /// Extend `self` into a [`DiscreteMeasure`] with the spikes produced by `iter`. + fn lift_extend>>( + self, + iter: I, + ) -> DiscreteMeasure; + + /// Returns an iterator for producing copies of the spikes of `self`. + fn produce(self) -> Self::Producer; +} + +impl Lift for DiscreteMeasure { + type Producer = std::vec::IntoIter>; + + #[inline] + fn lift(self) -> DiscreteMeasure { + self + } + + fn lift_with( + mut self, + _f: impl Fn(&DeltaMeasure) -> DeltaMeasure, + f_mut: impl FnMut(&mut DeltaMeasure), + ) -> DiscreteMeasure { + self.spikes.iter_mut().for_each(f_mut); + self + } + + #[inline] + fn lift_extend>>( + mut self, + iter: I, + ) -> DiscreteMeasure { + self.spikes.extend(iter); + self + } + + #[inline] + fn produce(self) -> Self::Producer { + self.spikes.into_iter() + } +} + +impl<'a, F: Num, Domain: Clone> Lift for &'a DiscreteMeasure { + type Producer = MapF>, DeltaMeasure>; + + #[inline] + fn lift(self) -> DiscreteMeasure { + self.clone() + } + + fn lift_with( + self, + f: impl Fn(&DeltaMeasure) -> DeltaMeasure, + _f_mut: impl FnMut(&mut DeltaMeasure), + ) -> DiscreteMeasure { + DiscreteMeasure { spikes: self.spikes.iter().map(f).collect() } + } + + #[inline] + fn lift_extend>>( + self, + iter: I, + ) -> DiscreteMeasure { + let mut res = self.clone(); + res.spikes.extend(iter); + res + } + + #[inline] + fn produce(self) -> Self::Producer { + // TODO: maybe not optimal to clone here and would benefit from + // a reference version of lift_extend. + self.spikes.iter().mapF(Clone::clone) + } +} + +impl Lift for DeltaMeasure { + type Producer = std::iter::Once>; + + #[inline] + fn lift(self) -> DiscreteMeasure { + DiscreteMeasure { spikes: vec![self] } + } + + #[inline] + fn lift_with( + mut self, + _f: impl Fn(&DeltaMeasure) -> DeltaMeasure, + mut f_mut: impl FnMut(&mut DeltaMeasure), + ) -> DiscreteMeasure { + f_mut(&mut self); + DiscreteMeasure { spikes: vec![self] } + } + + #[inline] + fn lift_extend>>( + self, + iter: I, + ) -> DiscreteMeasure { + let mut spikes = vec![self]; + spikes.extend(iter); + DiscreteMeasure { spikes: spikes } + } + + #[inline] + fn produce(self) -> Self::Producer { + std::iter::once(self) + } +} + +impl<'a, F: Num, Domain: Clone> Lift for &'a DeltaMeasure { + type Producer = std::iter::Once>; + + #[inline] + fn lift(self) -> DiscreteMeasure { + DiscreteMeasure { spikes: vec![self.clone()] } + } + + #[inline] + fn lift_with( + self, + f: impl Fn(&DeltaMeasure) -> DeltaMeasure, + _f_mut: impl FnMut(&mut DeltaMeasure), + ) -> DiscreteMeasure { + DiscreteMeasure { spikes: vec![f(self)] } + } + + #[inline] + fn lift_extend>>( + self, + iter: I, + ) -> DiscreteMeasure { + let mut spikes = vec![self.clone()]; + spikes.extend(iter); + DiscreteMeasure { spikes: spikes } + } + + #[inline] + fn produce(self) -> Self::Producer { + std::iter::once(self.clone()) + } +} + +macro_rules! make_discrete_addsub_assign { + ($rhs:ty) => { + // Discrete += (&)Discrete + impl<'a, F: Num, Domain: Clone> AddAssign<$rhs> for DiscreteMeasure { + fn add_assign(&mut self, other: $rhs) { + self.spikes.extend(other.produce()); + } + } + + impl<'a, F: Num + Neg, Domain: Clone> SubAssign<$rhs> + for DiscreteMeasure + { + fn sub_assign(&mut self, other: $rhs) { + self.spikes.extend(other.produce().map(|δ| -δ)); + } + } + }; +} + +make_discrete_addsub_assign!(DiscreteMeasure); +make_discrete_addsub_assign!(&'a DiscreteMeasure); +make_discrete_addsub_assign!(DeltaMeasure); +make_discrete_addsub_assign!(&'a DeltaMeasure); + +macro_rules! make_discrete_addsub { + ($lhs:ty, $rhs:ty, $alt_order:expr) => { + impl<'a, 'b, F: Num, Domain: Clone> Add<$rhs> for $lhs { + type Output = DiscreteMeasure; + fn add(self, other: $rhs) -> DiscreteMeasure { + if !$alt_order { + self.lift_extend(other.produce()) + } else { + other.lift_extend(self.produce()) + } + } + } + + impl<'a, 'b, F: Num + Neg, Domain: Clone> Sub<$rhs> for $lhs { + type Output = DiscreteMeasure; + fn sub(self, other: $rhs) -> DiscreteMeasure { + self.lift_extend(other.produce().map(|δ| -δ)) + } + } + }; +} + +make_discrete_addsub!(DiscreteMeasure, DiscreteMeasure, false); +make_discrete_addsub!(DiscreteMeasure, &'b DiscreteMeasure, false); +make_discrete_addsub!(&'a DiscreteMeasure, DiscreteMeasure, true); +make_discrete_addsub!( + &'a DiscreteMeasure, + &'b DiscreteMeasure, + false +); +make_discrete_addsub!(DeltaMeasure, DiscreteMeasure, false); +make_discrete_addsub!(DeltaMeasure, &'b DiscreteMeasure, false); +make_discrete_addsub!(&'a DeltaMeasure, DiscreteMeasure, true); +make_discrete_addsub!( + &'a DeltaMeasure, + &'b DiscreteMeasure, + false +); +make_discrete_addsub!(DiscreteMeasure, DeltaMeasure, false); +make_discrete_addsub!(DiscreteMeasure, &'b DeltaMeasure, false); +make_discrete_addsub!(&'a DiscreteMeasure, DeltaMeasure, false); +make_discrete_addsub!( + &'a DiscreteMeasure, + &'b DeltaMeasure, + false +); +make_discrete_addsub!(DeltaMeasure, DeltaMeasure, false); +make_discrete_addsub!(DeltaMeasure, &'b DeltaMeasure, false); +make_discrete_addsub!(&'a DeltaMeasure, DeltaMeasure, false); +make_discrete_addsub!( + &'a DeltaMeasure, + &'b DeltaMeasure, + false +); + +macro_rules! make_discrete_scalarop_rhs { + ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { + make_discrete_scalarop_rhs!(@assign DiscreteMeasure, F, $trait_assign, $fn_assign); + make_discrete_scalarop_rhs!(@assign DiscreteMeasure, &'a F, $trait_assign, $fn_assign); + make_discrete_scalarop_rhs!(@new DiscreteMeasure, F, $trait, $fn, $fn_assign); + make_discrete_scalarop_rhs!(@new DiscreteMeasure, &'a F, $trait, $fn, $fn_assign); + make_discrete_scalarop_rhs!(@new &'b DiscreteMeasure, F, $trait, $fn, $fn_assign); + make_discrete_scalarop_rhs!(@new &'b DiscreteMeasure, &'a F, $trait, $fn, $fn_assign); + }; + + (@assign $lhs:ty, $rhs:ty, $trait_assign:ident, $fn_assign:ident) => { + impl<'a, 'b, F : Num, Domain> $trait_assign<$rhs> for $lhs { + fn $fn_assign(&mut self, b : $rhs) { + self.spikes.iter_mut().for_each(|δ| δ.$fn_assign(b)); + } + } + }; + (@new $lhs:ty, $rhs:ty, $trait:ident, $fn:ident, $fn_assign:ident) => { + impl<'a, 'b, F : Num, Domain : Clone> $trait<$rhs> for $lhs { + type Output = DiscreteMeasure; + fn $fn(self, b : $rhs) -> Self::Output { + self.lift_with(|δ| δ.$fn(b), |δ| δ.$fn_assign(b)) + } + } + }; +} + +make_discrete_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); +make_discrete_scalarop_rhs!(Div, div, DivAssign, div_assign); + +macro_rules! make_discrete_unary { + ($trait:ident, $fn:ident, $type:ty) => { + impl<'a, F: Num + Neg, Domain: Clone> Neg for $type { + type Output = DiscreteMeasure; + fn $fn(self) -> Self::Output { + self.lift_with(|δ| δ.$fn(), |δ| δ.α = δ.α.$fn()) + } + } + }; +} + +make_discrete_unary!(Neg, neg, DiscreteMeasure); +make_discrete_unary!(Neg, neg, &'a DiscreteMeasure); + +// impl Neg for DiscreteMeasure { +// type Output = Self; +// fn $fn(mut self, b : F) -> Self { +// self.lift().spikes.iter_mut().for_each(|δ| δ.neg(b)); +// self +// } +// } + +macro_rules! make_discrete_scalarop_lhs { + ($trait:ident, $fn:ident; $($f:ident)+) => { $( + impl $trait> for $f { + type Output = DiscreteMeasure; + fn $fn(self, mut v : DiscreteMeasure) -> Self::Output { + v.spikes.iter_mut().for_each(|δ| δ.α = self.$fn(δ.α)); + v + } + } + + impl<'a, Domain : Copy> $trait<&'a DiscreteMeasure> for $f { + type Output = DiscreteMeasure; + fn $fn(self, v : &'a DiscreteMeasure) -> Self::Output { + DiscreteMeasure{ + spikes : v.spikes.iter().map(|δ| self.$fn(δ)).collect() + } + } + } + + impl<'b, Domain> $trait> for &'b $f { + type Output = DiscreteMeasure; + fn $fn(self, mut v : DiscreteMeasure) -> Self::Output { + v.spikes.iter_mut().for_each(|δ| δ.α = self.$fn(δ.α)); + v + } + } + + impl<'a, 'b, Domain : Copy> $trait<&'a DiscreteMeasure> for &'b $f { + type Output = DiscreteMeasure; + fn $fn(self, v : &'a DiscreteMeasure) -> Self::Output { + DiscreteMeasure{ + spikes : v.spikes.iter().map(|δ| self.$fn(δ)).collect() + } + } + } + )+ } +} + +make_discrete_scalarop_lhs!(Mul, mul; f32 f64 i8 i16 i32 i64 isize u8 u16 u32 u64 usize); +make_discrete_scalarop_lhs!(Div, div; f32 f64 i8 i16 i32 i64 isize u8 u16 u32 u64 usize); + +impl Collection for DiscreteMeasure { + type Element = DeltaMeasure; + type RefsIter<'a> + = std::slice::Iter<'a, Self::Element> + where + Self: 'a; + + #[inline] + fn iter_refs(&self) -> Self::RefsIter<'_> { + self.iter_spikes() + } +} + +impl Space for DiscreteMeasure { + type Principal = Self; + + type Decomp = MeasureDecomp; +} + +pub type SpikeSlice<'b, Domain, F> = &'b [DeltaMeasure]; + +pub type EitherSlice<'b, Domain, F> = + EitherDecomp>, SpikeSlice<'b, Domain, F>>; + +impl Decomposition> for MeasureDecomp { + type Decomposition<'b> + = EitherSlice<'b, Domain, F> + where + DiscreteMeasure: 'b; + type Reference<'b> + = SpikeSlice<'b, Domain, F> + where + DiscreteMeasure: 'b; + + /// Left the lightweight reference type into a full decomposition type. + fn lift<'b>(r: Self::Reference<'b>) -> Self::Decomposition<'b> { + EitherDecomp::Borrowed(r) + } +} + +impl Instance, MeasureDecomp> + for DiscreteMeasure +{ + fn eval_ref<'b, R>(&'b self, f: impl FnOnce(SpikeSlice<'b, Domain, F>) -> R) -> R + where + DiscreteMeasure: 'b, + Self: 'b, + { + f(self.spikes.as_slice()) + } + + fn cow<'b>(self) -> MyCow<'b, DiscreteMeasure> + where + Self: 'b, + { + MyCow::Owned(self) + } + + fn own(self) -> DiscreteMeasure { + self + } + + fn decompose<'b>(self) -> EitherSlice<'b, Domain, F> + where + Self: 'b, + { + EitherDecomp::Owned(self.spikes) + } +} + +impl<'a, F: Num, Domain: Clone> Instance, MeasureDecomp> + for &'a DiscreteMeasure +{ + fn eval_ref<'b, R>(&'b self, f: impl FnOnce(SpikeSlice<'b, Domain, F>) -> R) -> R + where + DiscreteMeasure: 'b, + Self: 'b, + { + f(self.spikes.as_slice()) + } + + fn cow<'b>(self) -> MyCow<'b, DiscreteMeasure> + where + Self: 'b, + { + MyCow::Borrowed(self) + } + + fn own(self) -> DiscreteMeasure { + self.clone() + } + + fn decompose<'b>(self) -> EitherSlice<'b, Domain, F> + where + Self: 'b, + { + EitherDecomp::Borrowed(self.spikes.as_slice()) + } +} + +impl<'a, F: Num, Domain: Clone> Instance, MeasureDecomp> + for EitherSlice<'a, Domain, F> +{ + fn eval_ref<'b, R>(&'b self, f: impl FnOnce(SpikeSlice<'b, Domain, F>) -> R) -> R + where + DiscreteMeasure: 'b, + Self: 'b, + { + match self { + EitherDecomp::Owned(v) => f(v.as_slice()), + EitherDecomp::Borrowed(s) => f(s), + } + } + + fn cow<'b>(self) -> MyCow<'b, DiscreteMeasure> + where + Self: 'b, + { + MyCow::Owned(self.own()) + } + + fn own(self) -> DiscreteMeasure { + match self { + EitherDecomp::Owned(v) => v.into(), + EitherDecomp::Borrowed(s) => s.into(), + } + } + + fn decompose<'b>(self) -> EitherSlice<'b, Domain, F> + where + Self: 'b, + { + self + } +} + +impl<'a, F: Num, Domain: Clone> Instance, MeasureDecomp> + for &'a EitherSlice<'a, Domain, F> +{ + fn eval_ref<'b, R>(&'b self, f: impl FnOnce(SpikeSlice<'b, Domain, F>) -> R) -> R + where + DiscreteMeasure: 'b, + Self: 'b, + { + match self { + EitherDecomp::Owned(v) => f(v.as_slice()), + EitherDecomp::Borrowed(s) => f(s), + } + } + + fn cow<'b>(self) -> MyCow<'b, DiscreteMeasure> + where + Self: 'b, + { + MyCow::Owned(self.own()) + } + + fn own(self) -> DiscreteMeasure { + match self { + EitherDecomp::Owned(v) => v.as_slice(), + EitherDecomp::Borrowed(s) => s, + } + .into() + } + + fn decompose<'b>(self) -> EitherSlice<'b, Domain, F> + where + Self: 'b, + { + match self { + EitherDecomp::Owned(v) => EitherDecomp::Borrowed(v.as_slice()), + EitherDecomp::Borrowed(s) => EitherDecomp::Borrowed(s), + } + } +} + +impl<'a, F: Num, Domain: Clone> Instance, MeasureDecomp> + for SpikeSlice<'a, Domain, F> +{ + fn eval_ref<'b, R>(&'b self, f: impl FnOnce(SpikeSlice<'b, Domain, F>) -> R) -> R + where + DiscreteMeasure: 'b, + Self: 'b, + { + f(self) + } + + fn cow<'b>(self) -> MyCow<'b, DiscreteMeasure> + where + Self: 'b, + { + MyCow::Owned(self.own()) + } + + fn own(self) -> DiscreteMeasure { + self.into() + } + + fn decompose<'b>(self) -> EitherSlice<'b, Domain, F> + where + Self: 'b, + { + EitherDecomp::Borrowed(self) + } +} + +impl<'a, F: Num, Domain: Clone> Instance, MeasureDecomp> + for &'a SpikeSlice<'a, Domain, F> +{ + fn eval_ref<'b, R>(&'b self, f: impl FnOnce(SpikeSlice<'b, Domain, F>) -> R) -> R + where + DiscreteMeasure: 'b, + Self: 'b, + { + f(*self) + } + + fn cow<'b>(self) -> MyCow<'b, DiscreteMeasure> + where + Self: 'b, + { + MyCow::Owned(self.own()) + } + + fn own(self) -> DiscreteMeasure { + (*self).into() + } + + fn decompose<'b>(self) -> EitherSlice<'b, Domain, F> + where + Self: 'b, + { + EitherDecomp::Borrowed(*self) + } +} + +impl Instance, MeasureDecomp> + for DeltaMeasure +{ + fn eval_ref<'b, R>(&'b self, f: impl FnOnce(SpikeSlice<'b, Domain, F>) -> R) -> R + where + DiscreteMeasure: 'b, + Self: 'b, + { + f(std::slice::from_ref(self)) + } + + fn cow<'b>(self) -> MyCow<'b, DiscreteMeasure> + where + Self: 'b, + { + MyCow::Owned(self.own()) + } + + fn own(self) -> DiscreteMeasure { + self.into() + } + + fn decompose<'b>(self) -> EitherSlice<'b, Domain, F> + where + Self: 'b, + { + EitherDecomp::Owned(vec![self]) + } +} + +impl<'a, F: Num, Domain: Clone> Instance, MeasureDecomp> + for &'a DeltaMeasure +{ + fn eval_ref<'b, R>(&'b self, f: impl FnOnce(SpikeSlice<'b, Domain, F>) -> R) -> R + where + DiscreteMeasure: 'b, + Self: 'b, + { + f(std::slice::from_ref(*self)) + } + + fn cow<'b>(self) -> MyCow<'b, DiscreteMeasure> + where + Self: 'b, + { + MyCow::Owned(self.own()) + } + + fn own(self) -> DiscreteMeasure { + self.into() + } + + fn decompose<'b>(self) -> EitherSlice<'b, Domain, F> + where + Self: 'b, + { + EitherDecomp::Borrowed(std::slice::from_ref(self)) + } +} + +impl Normed for DiscreteMeasure +where + F: Float, + Domain: Clone + PartialEq, + DeltaMeasure: Norm, +{ + type NormExp = Radon; + + fn norm_exponent(&self) -> Radon { + Radon + } +} + +self_ownable!(DiscreteMeasure where Domain: Clone, F: Num);