--- a/src/seminorms.rs Tue Aug 01 10:25:09 2023 +0300 +++ b/src/seminorms.rs Mon Feb 17 13:54:53 2025 -0500 @@ -12,9 +12,11 @@ use alg_tools::bisection_tree::*; use alg_tools::mapping::RealMapping; use alg_tools::iter::{Mappable, FilterMapX}; -use alg_tools::linops::{Apply, Linear, BoundedLinear}; +use alg_tools::linops::{Mapping, Linear, BoundedLinear}; +use alg_tools::instance::Instance; use alg_tools::nalgebra_support::ToNalgebraRealField; -use crate::measures::{DiscreteMeasure, DeltaMeasure, SpikeIter}; +use alg_tools::norms::Linfinity; +use crate::measures::{DiscreteMeasure, DeltaMeasure, SpikeIter, Radon, RNDM}; use nalgebra::DMatrix; use std::marker::PhantomData; use itertools::Itertools; @@ -22,9 +24,12 @@ /// Abstraction for operators $𝒟 ∈ 𝕃(𝒵(Ω); C_c(Ω))$. /// /// Here $𝒵(Ω) ⊂ ℳ(Ω)$ is the space of sums of delta measures, presented by [`DiscreteMeasure`]. -pub trait DiscreteMeasureOp<Domain, F> : BoundedLinear<DiscreteMeasure<Domain, F>, FloatType=F> -where F : Float + ToNalgebraRealField, - Domain : 'static { +pub trait DiscreteMeasureOp<Domain, F> + : BoundedLinear<DiscreteMeasure<Domain, F>, Radon, Linfinity, F> +where + F : Float + ToNalgebraRealField, + Domain : 'static + Clone + PartialEq, +{ /// The output type of [`Self::preapply`]. type PreCodomain; @@ -38,7 +43,7 @@ fn findim_matrix<'a, I>(&self, points : I) -> DMatrix<F::MixedType> where I : ExactSizeIterator<Item=&'a Domain> + Clone; - /// [`Apply::apply`] that typically returns an uninitialised [`PreBTFN`] + /// [`Mapping`] that typically returns an uninitialised [`PreBTFN`] /// instead of a full [`BTFN`]. fn preapply(&self, μ : DiscreteMeasure<Domain, F>) -> Self::PreCodomain; } @@ -73,7 +78,7 @@ pub struct ConvolutionSupportGenerator<F : Float, K, const N : usize> where K : SimpleConvolutionKernel<F, N> { kernel : K, - centres : DiscreteMeasure<Loc<F, N>, F>, + centres : RNDM<F, N>, } impl<F : Float, K, const N : usize> ConvolutionSupportGenerator<F, K, N> @@ -130,9 +135,9 @@ where F : Float + ToNalgebraRealField, BT : BTImpl<F, N, Data=usize>, K : SimpleConvolutionKernel<F, N> { - /// Depth of the [`BT`] bisection tree for the outputs [`Apply::apply`]. + /// Depth of the [`BT`] bisection tree for the outputs [`Mapping::apply`]. depth : BT::Depth, - /// Domain of the [`BT`] bisection tree for the outputs [`Apply::apply`]. + /// Domain of the [`BT`] bisection tree for the outputs [`Mapping::apply`]. domain : Cube<F, N>, /// The convolution kernel kernel : K, @@ -146,7 +151,7 @@ /// Creates a new convolution operator $𝒟$ with `kernel` on `domain`. /// - /// The output of [`Apply::apply`] is a [`BT`] of given `depth`. + /// The output of [`Mapping::apply`] is a [`BT`] of given `depth`. pub fn new(depth : BT::Depth, domain : Cube<F, N>, kernel : K) -> Self { ConvolutionOp { depth : depth, @@ -157,7 +162,7 @@ } /// Returns the support generator for this convolution operator. - fn support_generator(&self, μ : DiscreteMeasure<Loc<F, N>, F>) + fn support_generator(&self, μ : RNDM<F, N>) -> ConvolutionSupportGenerator<F, K, N> { // TODO: can we avoid cloning μ? @@ -173,94 +178,43 @@ } } -impl<F, K, BT, const N : usize> Apply<DiscreteMeasure<Loc<F, N>, F>> +impl<F, K, BT, const N : usize> Mapping<RNDM<F, N>> for ConvolutionOp<F, K, BT, N> -where F : Float + ToNalgebraRealField, - BT : BTImpl<F, N, Data=usize>, - K : SimpleConvolutionKernel<F, N>, - Weighted<Shift<K, F, N>, F> : LocalAnalysis<F, BT::Agg, N> { +where + F : Float + ToNalgebraRealField, + BT : BTImpl<F, N, Data=usize>, + K : SimpleConvolutionKernel<F, N>, + Weighted<Shift<K, F, N>, F> : LocalAnalysis<F, BT::Agg, N> +{ - type Output = BTFN<F, ConvolutionSupportGenerator<F, K, N>, BT, N>; + type Codomain = BTFN<F, ConvolutionSupportGenerator<F, K, N>, BT, N>; - fn apply(&self, μ : DiscreteMeasure<Loc<F, N>, F>) -> Self::Output { - let g = self.support_generator(μ); + fn apply<I>(&self, μ : I) -> Self::Codomain + where I : Instance<RNDM<F, N>> { + let g = self.support_generator(μ.own()); BTFN::construct(self.domain.clone(), self.depth, g) } } -impl<'a, F, K, BT, const N : usize> Apply<&'a DiscreteMeasure<Loc<F, N>, F>> +/// [`ConvolutionOp`]s as linear operators over [`DiscreteMeasure`]s. +impl<F, K, BT, const N : usize> Linear<RNDM<F, N>> +for ConvolutionOp<F, K, BT, N> +where + F : Float + ToNalgebraRealField, + BT : BTImpl<F, N, Data=usize>, + K : SimpleConvolutionKernel<F, N>, + Weighted<Shift<K, F, N>, F> : LocalAnalysis<F, BT::Agg, N> +{ } + +impl<F, K, BT, const N : usize> +BoundedLinear<RNDM<F, N>, Radon, Linfinity, F> for ConvolutionOp<F, K, BT, N> where F : Float + ToNalgebraRealField, BT : BTImpl<F, N, Data=usize>, K : SimpleConvolutionKernel<F, N>, Weighted<Shift<K, F, N>, F> : LocalAnalysis<F, BT::Agg, N> { - type Output = BTFN<F, ConvolutionSupportGenerator<F, K, N>, BT, N>; - - fn apply(&self, μ : &'a DiscreteMeasure<Loc<F, N>, F>) -> Self::Output { - self.apply(μ.clone()) - } -} - -/// [`ConvolutionOp`]s as linear operators over [`DiscreteMeasure`]s. -impl<F, K, BT, const N : usize> Linear<DiscreteMeasure<Loc<F, N>, F>> -for ConvolutionOp<F, K, BT, N> -where F : Float + ToNalgebraRealField, - BT : BTImpl<F, N, Data=usize>, - K : SimpleConvolutionKernel<F, N>, - Weighted<Shift<K, F, N>, F> : LocalAnalysis<F, BT::Agg, N> { - type Codomain = BTFN<F, ConvolutionSupportGenerator<F, K, N>, BT, N>; -} - -impl<F, K, BT, const N : usize> Apply<DeltaMeasure<Loc<F, N>, F>> -for ConvolutionOp<F, K, BT, N> -where F : Float + ToNalgebraRealField, - BT : BTImpl<F, N, Data=usize>, - K : SimpleConvolutionKernel<F, N> { - - type Output = Weighted<Shift<K, F, N>, F>; - - #[inline] - fn apply(&self, δ : DeltaMeasure<Loc<F, N>, F>) -> Self::Output { - self.kernel.clone().shift(δ.x).weigh(δ.α) - } -} - -impl<'a, F, K, BT, const N : usize> Apply<&'a DeltaMeasure<Loc<F, N>, F>> -for ConvolutionOp<F, K, BT, N> -where F : Float + ToNalgebraRealField, - BT : BTImpl<F, N, Data=usize>, - K : SimpleConvolutionKernel<F, N> { - - type Output = Weighted<Shift<K, F, N>, F>; - - #[inline] - fn apply(&self, δ : &'a DeltaMeasure<Loc<F, N>, F>) -> Self::Output { - self.kernel.clone().shift(δ.x).weigh(δ.α) - } -} - -/// [`ConvolutionOp`]s as linear operators over [`DeltaMeasure`]s. -/// -/// The codomain is different from the implementation for [`DiscreteMeasure`]. -impl<F, K, BT, const N : usize> Linear<DeltaMeasure<Loc<F, N>, F>> -for ConvolutionOp<F, K, BT, N> -where F : Float + ToNalgebraRealField, - BT : BTImpl<F, N, Data=usize>, - K : SimpleConvolutionKernel<F, N> { - type Codomain = Weighted<Shift<K, F, N>, F>; -} - -impl<F, K, BT, const N : usize> BoundedLinear<DiscreteMeasure<Loc<F, N>, F>> -for ConvolutionOp<F, K, BT, N> -where F : Float + ToNalgebraRealField, - BT : BTImpl<F, N, Data=usize>, - K : SimpleConvolutionKernel<F, N>, - Weighted<Shift<K, F, N>, F> : LocalAnalysis<F, BT::Agg, N> { - - type FloatType = F; - - fn opnorm_bound(&self) -> F { + fn opnorm_bound(&self, _ : Radon, _ : Linfinity) -> F { // With μ = ∑_i α_i δ_{x_i}, we have // |𝒟μ|_∞ // = sup_z |∑_i α_i φ(z - x_i)| @@ -292,10 +246,10 @@ DMatrix::from_iterator(n, n, values) } - /// A version of [`Apply::apply`] that does not instantiate the [`BTFN`] codomain with + /// A version of [`Mapping::apply`] that does not instantiate the [`BTFN`] codomain with /// a bisection tree, instead returning a [`PreBTFN`]. This can improve performance when /// the output is to be added as the right-hand-side operand to a proper BTFN. - fn preapply(&self, μ : DiscreteMeasure<Loc<F, N>, F>) -> Self::PreCodomain { + fn preapply(&self, μ : RNDM<F, N>) -> Self::PreCodomain { BTFN::new_pre(self.support_generator(μ)) } } @@ -368,11 +322,3 @@ make_convolutionsupportgenerator_unaryop!(Neg, neg); -/// Trait for indicating that `Self` is Lipschitz with respect to the seminorm `D`. -pub trait Lipschitz<D> { - /// The type of floats - type FloatType : Float; - - /// Returns the Lipschitz factor of `self` with respect to the seminorm `D`. - fn lipschitz_factor(&self, seminorm : &D) -> Option<Self::FloatType>; -}