Sun, 11 Dec 2022 23:19:17 +0200
Print out experiment information when running it
/*! This module implementes delta measures, i.e., single spikes $\alpha \delta_x$ for some location $x$ and mass $\alpha$. */ use super::base::*; use crate::types::*; use std::ops::{Div, Mul, DivAssign, MulAssign, Neg}; use serde::ser::{Serialize, Serializer, SerializeStruct}; use alg_tools::norms::{Norm, Dist}; use alg_tools::linops::{Apply, Linear}; /// Representation of a delta measure. /// /// This is a single spike $\alpha \delta\_x$ for some location $x$ in `Domain` and /// a mass $\alpha$ in `F`. #[derive(Clone,Copy,Debug)] pub struct DeltaMeasure<Domain, F : Num> { // This causes [`csv`] to crash. //#[serde(flatten)] /// Location of the spike pub x : Domain, /// Mass of the spike pub α : F } const COORDINATE_NAMES : &'static [&'static str] = &[ "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7" ]; // Need to manually implement serialisation as [`csv`] writer fails on // structs with nested arrays as well as with #[serde(flatten)]. impl<F : Num, const N : usize> Serialize for DeltaMeasure<Loc<F, N>, F> where F: Serialize, { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { assert!(N <= COORDINATE_NAMES.len()); let mut s = serializer.serialize_struct("DeltaMeasure", N+1)?; for (i, e) in (0..).zip(self.x.iter()) { s.serialize_field(COORDINATE_NAMES[i], e)?; } s.serialize_field("weight", &self.α)?; s.end() } } impl<Domain : PartialEq, F : Float> Measure<F> for DeltaMeasure<Domain, F> { type Domain = Domain; } impl<Domain : PartialEq, F : Float> Norm<F, Radon> for DeltaMeasure<Domain, F> { #[inline] fn norm(&self, _ : Radon) -> F { self.α.abs() } } impl<Domain : PartialEq, F : Float> Dist<F, Radon> for DeltaMeasure<Domain, F> { #[inline] fn dist(&self, other : &Self, _ : Radon) -> F { if self.x == other. x { (self.α - other.α).abs() } else { self.α.abs() + other.α.abs() } } } impl<'b, Domain, G, F : Num, V : Mul<F, Output=V>> Apply<G> for DeltaMeasure<Domain, F> where G: for<'a> Apply<&'a Domain, Output = V>, V : Mul<F> { type Output = V; #[inline] fn apply(&self, g : G) -> Self::Output { g.apply(&self.x) * self.α } } impl<Domain, G, F : Num, V : Mul<F, Output=V>> Linear<G> for DeltaMeasure<Domain, F> where G: for<'a> Apply<&'a Domain, Output = V> { type Codomain = V; } // /// Partial blanket implementation of [`DeltaMeasure`] as a linear functional of [`Mapping`]s. // /// A full blanket implementation is not possible due to annoying Rust limitations: only [`Apply`] // /// on a reference is implemented, but a consuming [`Apply`] has to be implemented on a case-by-case // /// basis, not because an implementation could not be written, but because the Rust trait system // /// chokes up. // impl<Domain, G, F : Num, V> Linear<G> for DeltaMeasure<Domain, F> // where G: for<'a> Apply<&'a Domain, Output = V>, // V : Mul<F>, // Self: Apply<G, Output = <V as Mul<F>>::Output> { // type Codomain = <V as Mul<F>>::Output; // } // impl<'b, Domain, G, F : Num, V> Apply<&'b G> for DeltaMeasure<Domain, F> // where G: for<'a> Apply<&'a Domain, Output = V>, // V : Mul<F> { // type Output = <V as Mul<F>>::Output; // #[inline] // fn apply(&self, g : &'b G) -> Self::Output { // g.apply(&self.x) * self.α // } // } // /// Implementation of the necessary apply for BTFNs // mod btfn_apply { // use super::*; // use alg_tools::bisection_tree::{BTFN, BTImpl, SupportGenerator, LocalAnalysis}; // impl<F : Float, BT, G, V, const N : usize> Apply<BTFN<F, G, BT, N>> // for DeltaMeasure<Loc<F, N>, F> // where BT : BTImpl<F, N>, // G : SupportGenerator<F, N, Id=BT::Data>, // G::SupportType : LocalAnalysis<F, BT::Agg, N> + for<'a> Apply<&'a Loc<F, N>, Output = V>, // V : std::iter::Sum + Mul<F> { // type Output = <V as Mul<F>>::Output; // #[inline] // fn apply(&self, g : BTFN<F, G, BT, N>) -> Self::Output { // g.apply(&self.x) * self.α // } // } // } impl<D, Domain, F : Num> From<(D, F)> for DeltaMeasure<Domain, F> where D : Into<Domain> { #[inline] fn from((x, α) : (D, F)) -> Self { DeltaMeasure{x: x.into(), α: α} } } /*impl<F : Num> From<(F, F)> for DeltaMeasure<Loc<F, 1>, F> { #[inline] fn from((x, α) : (F, F)) -> Self { DeltaMeasure{x: Loc([x]), α: α} } }*/ impl<Domain, F : Num> DeltaMeasure<Domain, F> { /// Set the mass of the spike. #[inline] pub fn set_mass(&mut self, α : F) { self.α = α } /// Set the location of the spike. #[inline] pub fn set_location(&mut self, x : Domain) { self.x = x } /// Get the mass of the spike. #[inline] pub fn get_mass(&self) -> F { self.α } /// Get a mutable reference to the mass of the spike. #[inline] pub fn get_mass_mut(&mut self) -> &mut F { &mut self.α } /// Get a reference to the location of the spike. #[inline] pub fn get_location(&self) -> &Domain { &self.x } /// Get a mutable reference to the location of the spike. #[inline] pub fn get_location_mut(&mut self) -> &mut Domain { &mut self.x } } macro_rules! make_delta_scalarop_rhs { ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { impl<F : Num, Domain> $trait<F> for DeltaMeasure<Domain, F> { type Output = Self; fn $fn(mut self, b : F) -> Self { self.α.$fn_assign(b); self } } impl<'a, F : Num, Domain> $trait<&'a F> for DeltaMeasure<Domain, F> { type Output = Self; fn $fn(mut self, b : &'a F) -> Self { self.α.$fn_assign(*b); self } } impl<'b, F : Num, Domain : Clone> $trait<F> for &'b DeltaMeasure<Domain, F> { type Output = DeltaMeasure<Domain, F>; fn $fn(self, b : F) -> Self::Output { DeltaMeasure { α : self.α.$fn(b), x : self.x.clone() } } } impl<'a, 'b, F : Num, Domain : Clone> $trait<&'a F> for &'b DeltaMeasure<Domain, F> { type Output = DeltaMeasure<Domain, F>; fn $fn(self, b : &'a F) -> Self::Output { DeltaMeasure { α : self.α.$fn(*b), x : self.x.clone() } } } impl<F : Num, Domain> $trait_assign<F> for DeltaMeasure<Domain, F> { fn $fn_assign(&mut self, b : F) { self.α.$fn_assign(b) } } impl<'a, F : Num, Domain> $trait_assign<&'a F> for DeltaMeasure<Domain, F> { fn $fn_assign(&mut self, b : &'a F) { self.α.$fn_assign(*b) } } } } make_delta_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); make_delta_scalarop_rhs!(Div, div, DivAssign, div_assign); macro_rules! make_delta_scalarop_lhs { ($trait:ident, $fn:ident; $($f:ident)+) => { $( impl<Domain> $trait<DeltaMeasure<Domain, $f>> for $f { type Output = DeltaMeasure<Domain, $f>; fn $fn(self, mut δ : DeltaMeasure<Domain, $f>) -> Self::Output { δ.α = self.$fn(δ.α); δ } } impl<'a, Domain : Clone> $trait<&'a DeltaMeasure<Domain, $f>> for $f { type Output = DeltaMeasure<Domain, $f>; fn $fn(self, δ : &'a DeltaMeasure<Domain, $f>) -> Self::Output { DeltaMeasure{ x : δ.x.clone(), α : self.$fn(δ.α) } } } impl<'b, Domain> $trait<DeltaMeasure<Domain, $f>> for &'b $f { type Output = DeltaMeasure<Domain, $f>; fn $fn(self, mut δ : DeltaMeasure<Domain, $f>) -> Self::Output { δ.α = self.$fn(δ.α); δ } } impl<'a, 'b, Domain : Clone> $trait<&'a DeltaMeasure<Domain, $f>> for &'b $f { type Output = DeltaMeasure<Domain, $f>; fn $fn(self, δ : &'a DeltaMeasure<Domain, $f>) -> Self::Output { DeltaMeasure{ x : δ.x.clone(), α : self.$fn(δ.α) } } } )+ } } make_delta_scalarop_lhs!(Mul, mul; f32 f64 i8 i16 i32 i64 isize u8 u16 u32 u64 usize); make_delta_scalarop_lhs!(Div, div; f32 f64 i8 i16 i32 i64 isize u8 u16 u32 u64 usize); macro_rules! make_delta_unary { ($trait:ident, $fn:ident, $type:ty) => { impl<'a, F : Num + Neg<Output=F>, Domain : Clone> Neg for $type { type Output = DeltaMeasure<Domain, F>; fn $fn(self) -> Self::Output { let mut tmp = self.clone(); tmp.α = tmp.α.$fn(); tmp } } } } make_delta_unary!(Neg, neg, DeltaMeasure<Domain, F>); make_delta_unary!(Neg, neg, &'a DeltaMeasure<Domain, F>);