diff -r 92cae2e8f598 -r b3312eee105c src/seminorms.rs
--- a/src/seminorms.rs Mon Feb 17 14:10:45 2025 -0500
+++ b/src/seminorms.rs Mon Feb 17 14:10:52 2025 -0500
@@ -4,31 +4,31 @@
the trait [`DiscreteMeasureOp`].
*/
-use std::iter::Zip;
-use std::ops::RangeFrom;
-use alg_tools::types::*;
+use crate::measures::{DeltaMeasure, DiscreteMeasure, Radon, SpikeIter, RNDM};
+use alg_tools::bisection_tree::*;
+use alg_tools::instance::Instance;
+use alg_tools::iter::{FilterMapX, Mappable};
+use alg_tools::linops::{BoundedLinear, Linear, Mapping};
use alg_tools::loc::Loc;
-use alg_tools::sets::Cube;
-use alg_tools::bisection_tree::*;
use alg_tools::mapping::RealMapping;
-use alg_tools::iter::{Mappable, FilterMapX};
-use alg_tools::linops::{Mapping, Linear, BoundedLinear};
-use alg_tools::instance::Instance;
use alg_tools::nalgebra_support::ToNalgebraRealField;
use alg_tools::norms::Linfinity;
-use crate::measures::{DiscreteMeasure, DeltaMeasure, SpikeIter, Radon, RNDM};
+use alg_tools::sets::Cube;
+use alg_tools::types::*;
+use itertools::Itertools;
use nalgebra::DMatrix;
+use std::iter::Zip;
use std::marker::PhantomData;
-use itertools::Itertools;
+use std::ops::RangeFrom;
/// Abstraction for operators $𝒟 ∈ 𝕃(𝒵(Ω); C_c(Ω))$.
///
/// Here $𝒵(Ω) ⊂ ℳ(Ω)$ is the space of sums of delta measures, presented by [`DiscreteMeasure`].
-pub trait DiscreteMeasureOp
- : BoundedLinear, Radon, Linfinity, F>
+pub trait DiscreteMeasureOp:
+ BoundedLinear, Radon, Linfinity, F>
where
- F : Float + ToNalgebraRealField,
- Domain : 'static + Clone + PartialEq,
+ F: Float + ToNalgebraRealField,
+ Domain: 'static + Clone + PartialEq,
{
/// The output type of [`Self::preapply`].
type PreCodomain;
@@ -40,12 +40,13 @@
/// for a $x_1, …, x_n$ the coordinates given by the iterator `I`, and $a=(α_1,…,α_n)$.
/// Here $C_* ∈ 𝕃(C_c(Ω); ℝ^n) $ stands for the preadjoint.
///
- fn findim_matrix<'a, I>(&self, points : I) -> DMatrix
- where I : ExactSizeIterator- + Clone;
+ fn findim_matrix<'a, I>(&self, points: I) -> DMatrix
+ where
+ I: ExactSizeIterator
- + Clone;
/// [`Mapping`] that typically returns an uninitialised [`PreBTFN`]
/// instead of a full [`BTFN`].
- fn preapply(&self, μ : DiscreteMeasure) -> Self::PreCodomain;
+ fn preapply(&self, μ: DiscreteMeasure) -> Self::PreCodomain;
}
// Blanket implementation of a measure as a linear functional over a predual
@@ -67,28 +68,37 @@
//
/// A trait alias for simple convolution kernels.
-pub trait SimpleConvolutionKernel
-: RealMapping + Support + Bounded + Clone + 'static {}
+pub trait SimpleConvolutionKernel:
+ RealMapping + Support + Bounded + Clone + 'static
+{
+}
-impl SimpleConvolutionKernel for T
-where T : RealMapping + Support + Bounded + Clone + 'static {}
+impl SimpleConvolutionKernel for T where
+ T: RealMapping + Support + Bounded + Clone + 'static
+{
+}
/// [`SupportGenerator`] for [`ConvolutionOp`].
-#[derive(Clone,Debug)]
-pub struct ConvolutionSupportGenerator
-where K : SimpleConvolutionKernel {
- kernel : K,
- centres : RNDM,
+#[derive(Clone, Debug)]
+pub struct ConvolutionSupportGenerator
+where
+ K: SimpleConvolutionKernel,
+{
+ kernel: K,
+ centres: RNDM,
}
-impl ConvolutionSupportGenerator
-where K : SimpleConvolutionKernel {
-
+impl ConvolutionSupportGenerator
+where
+ K: SimpleConvolutionKernel,
+{
/// Construct the convolution kernel corresponding to `δ`, i.e., one centered at `δ.x` and
/// weighted by `δ.α`.
#[inline]
- fn construct_kernel<'a>(&'a self, δ : &'a DeltaMeasure, F>)
- -> Weighted, F> {
+ fn construct_kernel<'a>(
+ &'a self,
+ δ: &'a DeltaMeasure, F>,
+ ) -> Weighted, F> {
self.kernel.clone().shift(δ.x).weigh(δ.α)
}
@@ -98,22 +108,27 @@
#[inline]
fn construct_kernel_and_id_filtered<'a>(
&'a self,
- (id, δ) : (usize, &'a DeltaMeasure, F>)
+ (id, δ): (usize, &'a DeltaMeasure, F>),
) -> Option<(usize, Weighted, F>)> {
(δ.α != F::ZERO).then(|| (id.into(), self.construct_kernel(δ)))
}
}
-impl SupportGenerator
-for ConvolutionSupportGenerator
-where K : SimpleConvolutionKernel {
+impl SupportGenerator for ConvolutionSupportGenerator
+where
+ K: SimpleConvolutionKernel,
+{
type Id = usize;
type SupportType = Weighted, F>;
- type AllDataIter<'a> = FilterMapX<'a, Zip, SpikeIter<'a, Loc, F>>,
- Self, (Self::Id, Self::SupportType)>;
+ type AllDataIter<'a> = FilterMapX<
+ 'a,
+ Zip, SpikeIter<'a, Loc, F>>,
+ Self,
+ (Self::Id, Self::SupportType),
+ >;
#[inline]
- fn support_for(&self, d : Self::Id) -> Self::SupportType {
+ fn support_for(&self, d: Self::Id) -> Self::SupportType {
self.construct_kernel(&self.centres[d])
}
@@ -124,51 +139,53 @@
#[inline]
fn all_data(&self) -> Self::AllDataIter<'_> {
- (0..).zip(self.centres.iter_spikes())
- .filter_mapX(self, Self::construct_kernel_and_id_filtered)
+ (0..)
+ .zip(self.centres.iter_spikes())
+ .filter_mapX(self, Self::construct_kernel_and_id_filtered)
}
}
/// Representation of a convolution operator $𝒟$.
-#[derive(Clone,Debug)]
-pub struct ConvolutionOp
-where F : Float + ToNalgebraRealField,
- BT : BTImpl,
- K : SimpleConvolutionKernel {
+#[derive(Clone, Debug)]
+pub struct ConvolutionOp
+where
+ F: Float + ToNalgebraRealField,
+ BT: BTImpl,
+ K: SimpleConvolutionKernel,
+{
/// Depth of the [`BT`] bisection tree for the outputs [`Mapping::apply`].
- depth : BT::Depth,
+ depth: BT::Depth,
/// Domain of the [`BT`] bisection tree for the outputs [`Mapping::apply`].
- domain : Cube,
+ domain: Cube,
/// The convolution kernel
- kernel : K,
- _phantoms : PhantomData<(F,BT)>,
+ kernel: K,
+ _phantoms: PhantomData<(F, BT)>,
}
-impl ConvolutionOp
-where F : Float + ToNalgebraRealField,
- BT : BTImpl,
- K : SimpleConvolutionKernel {
-
+impl ConvolutionOp
+where
+ F: Float + ToNalgebraRealField,
+ BT: BTImpl,
+ K: SimpleConvolutionKernel,
+{
/// Creates a new convolution operator $𝒟$ with `kernel` on `domain`.
///
/// The output of [`Mapping::apply`] is a [`BT`] of given `depth`.
- pub fn new(depth : BT::Depth, domain : Cube, kernel : K) -> Self {
+ pub fn new(depth: BT::Depth, domain: Cube, kernel: K) -> Self {
ConvolutionOp {
- depth : depth,
- domain : domain,
- kernel : kernel,
- _phantoms : PhantomData
+ depth: depth,
+ domain: domain,
+ kernel: kernel,
+ _phantoms: PhantomData,
}
}
/// Returns the support generator for this convolution operator.
- fn support_generator(&self, μ : RNDM)
- -> ConvolutionSupportGenerator {
-
+ fn support_generator(&self, μ: RNDM) -> ConvolutionSupportGenerator {
// TODO: can we avoid cloning μ?
ConvolutionSupportGenerator {
- kernel : self.kernel.clone(),
- centres : μ
+ kernel: self.kernel.clone(),
+ centres: μ,
}
}
@@ -178,43 +195,43 @@
}
}
-impl Mapping>
-for ConvolutionOp
+impl Mapping> for ConvolutionOp
where
- F : Float + ToNalgebraRealField,
- BT : BTImpl,
- K : SimpleConvolutionKernel,
- Weighted, F> : LocalAnalysis
+ F: Float + ToNalgebraRealField,
+ BT: BTImpl,
+ K: SimpleConvolutionKernel,
+ Weighted, F>: LocalAnalysis,
{
-
type Codomain = BTFN, BT, N>;
- fn apply(&self, μ : I) -> Self::Codomain
- where I : Instance> {
+ fn apply(&self, μ: I) -> Self::Codomain
+ where
+ I: Instance>,
+ {
let g = self.support_generator(μ.own());
BTFN::construct(self.domain.clone(), self.depth, g)
}
}
/// [`ConvolutionOp`]s as linear operators over [`DiscreteMeasure`]s.
-impl Linear>
-for ConvolutionOp
+impl Linear> for ConvolutionOp
where
- F : Float + ToNalgebraRealField,
- BT : BTImpl,
- K : SimpleConvolutionKernel,
- Weighted, F> : LocalAnalysis
-{ }
+ F: Float + ToNalgebraRealField,
+ BT: BTImpl,
+ K: SimpleConvolutionKernel,
+ Weighted, F>: LocalAnalysis,
+{
+}
-impl
-BoundedLinear, Radon, Linfinity, F>
-for ConvolutionOp
-where F : Float + ToNalgebraRealField,
- BT : BTImpl,
- K : SimpleConvolutionKernel,
- Weighted, F> : LocalAnalysis {
-
- fn opnorm_bound(&self, _ : Radon, _ : Linfinity) -> F {
+impl BoundedLinear, Radon, Linfinity, F>
+ for ConvolutionOp
+where
+ F: Float + ToNalgebraRealField,
+ BT: BTImpl,
+ K: SimpleConvolutionKernel,
+ Weighted, F>: LocalAnalysis,
+{
+ fn opnorm_bound(&self, _: Radon, _: Linfinity) -> F {
// With μ = ∑_i α_i δ_{x_i}, we have
// |𝒟μ|_∞
// = sup_z |∑_i α_i φ(z - x_i)|
@@ -225,31 +242,33 @@
}
}
-
-impl DiscreteMeasureOp, F>
-for ConvolutionOp
-where F : Float + ToNalgebraRealField,
- BT : BTImpl,
- K : SimpleConvolutionKernel,
- Weighted, F> : LocalAnalysis {
+impl DiscreteMeasureOp, F> for ConvolutionOp
+where
+ F: Float + ToNalgebraRealField,
+ BT: BTImpl,
+ K: SimpleConvolutionKernel,
+ Weighted, F>: LocalAnalysis,
+{
type PreCodomain = PreBTFN, N>;
- fn findim_matrix<'a, I>(&self, points : I) -> DMatrix
- where I : ExactSizeIterator
- > + Clone {
+ fn findim_matrix<'a, I>(&self, points: I) -> DMatrix
+ where
+ I: ExactSizeIterator
- > + Clone,
+ {
// TODO: Preliminary implementation. It be best to use sparse matrices or
// possibly explicit operators without matrices
let n = points.len();
let points_clone = points.clone();
let pairs = points.cartesian_product(points_clone);
let kernel = &self.kernel;
- let values = pairs.map(|(x, y)| kernel.apply(y-x).to_nalgebra_mixed());
+ let values = pairs.map(|(x, y)| kernel.apply(y - x).to_nalgebra_mixed());
DMatrix::from_iterator(n, n, values)
}
/// 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, μ : RNDM) -> Self::PreCodomain {
+ fn preapply(&self, μ: RNDM) -> Self::PreCodomain {
BTFN::new_pre(self.support_generator(μ))
}
}
@@ -258,47 +277,46 @@
/// for [`ConvolutionSupportGenerator`].
macro_rules! make_convolutionsupportgenerator_scalarop_rhs {
($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => {
- impl, const N : usize>
- std::ops::$trait_assign
- for ConvolutionSupportGenerator {
- fn $fn_assign(&mut self, t : F) {
+ impl, const N: usize> std::ops::$trait_assign
+ for ConvolutionSupportGenerator
+ {
+ fn $fn_assign(&mut self, t: F) {
self.centres.$fn_assign(t);
}
}
- impl, const N : usize>
- std::ops::$trait
- for ConvolutionSupportGenerator {
+ impl, const N: usize> std::ops::$trait
+ for ConvolutionSupportGenerator
+ {
type Output = ConvolutionSupportGenerator;
- fn $fn(mut self, t : F) -> Self::Output {
+ fn $fn(mut self, t: F) -> Self::Output {
std::ops::$trait_assign::$fn_assign(&mut self.centres, t);
self
}
}
- impl<'a, F : Float, K : SimpleConvolutionKernel, const N : usize>
- std::ops::$trait
- for &'a ConvolutionSupportGenerator {
+ impl<'a, F: Float, K: SimpleConvolutionKernel, const N: usize> std::ops::$trait
+ for &'a ConvolutionSupportGenerator
+ {
type Output = ConvolutionSupportGenerator;
- fn $fn(self, t : F) -> Self::Output {
- ConvolutionSupportGenerator{
- kernel : self.kernel.clone(),
- centres : (&self.centres).$fn(t),
+ fn $fn(self, t: F) -> Self::Output {
+ ConvolutionSupportGenerator {
+ kernel: self.kernel.clone(),
+ centres: (&self.centres).$fn(t),
}
}
}
- }
+ };
}
make_convolutionsupportgenerator_scalarop_rhs!(Mul, mul, MulAssign, mul_assign);
make_convolutionsupportgenerator_scalarop_rhs!(Div, div, DivAssign, div_assign);
-
/// Generates an unary operation (e.g. [`std::ops::Neg`]) for [`ConvolutionSupportGenerator`].
macro_rules! make_convolutionsupportgenerator_unaryop {
($trait:ident, $fn:ident) => {
- impl, const N : usize>
- std::ops::$trait
- for ConvolutionSupportGenerator {
+ impl, const N: usize> std::ops::$trait
+ for ConvolutionSupportGenerator
+ {
type Output = ConvolutionSupportGenerator;
fn $fn(mut self) -> Self::Output {
self.centres = self.centres.$fn();
@@ -306,19 +324,18 @@
}
}
- impl<'a, F : Float, K : SimpleConvolutionKernel, const N : usize>
- std::ops::$trait
- for &'a ConvolutionSupportGenerator {
+ impl<'a, F: Float, K: SimpleConvolutionKernel, const N: usize> std::ops::$trait
+ for &'a ConvolutionSupportGenerator
+ {
type Output = ConvolutionSupportGenerator;
fn $fn(self) -> Self::Output {
- ConvolutionSupportGenerator{
- kernel : self.kernel.clone(),
- centres : (&self.centres).$fn(),
+ ConvolutionSupportGenerator {
+ kernel: self.kernel.clone(),
+ centres: (&self.centres).$fn(),
}
}
}
- }
+ };
}
make_convolutionsupportgenerator_unaryop!(Neg, neg);
-