diff -r d14c877e14b7 -r b3c35d16affe src/norms.rs --- a/src/norms.rs Tue Feb 20 12:33:16 2024 -0500 +++ b/src/norms.rs Mon Feb 03 19:22:16 2025 -0500 @@ -3,18 +3,31 @@ */ use serde::Serialize; +use std::marker::PhantomData; use crate::types::*; use crate::euclidean::*; +use crate::mapping::{Mapping, Space, Instance}; // // Abstract norms // +#[derive(Copy,Clone,Debug)] +/// Helper structure to convert a [`NormExponent`] into a [`Mapping`] +pub struct NormMapping{ + pub(crate) exponent : E, + _phantoms : PhantomData +} + /// An exponent for norms. /// -// Just a collection of desirabl attributes for a marker type -pub trait NormExponent : Copy + Send + Sync + 'static {} - +// Just a collection of desirable attributes for a marker type +pub trait NormExponent : Copy + Send + Sync + 'static { + /// Return the norm as a mappin + fn as_mapping(self) -> NormMapping { + NormMapping{ exponent : self, _phantoms : PhantomData } + } +} /// Exponent type for the 1-[`Norm`]. #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] @@ -37,6 +50,15 @@ pub struct L21; impl NormExponent for L21 {} +/// Norms for pairs (a, b). ‖(a,b)‖ = ‖(‖a‖_A, ‖b‖_B)‖_J +/// For use with [`crate::direct_product::Pair`] +#[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] +pub struct PairNorm(pub A, pub B, pub J); + +impl NormExponent for PairNorm +where A : NormExponent, B : NormExponent, J : NormExponent {} + + /// A Huber/Moreau–Yosida smoothed [`L1`] norm. (Not a norm itself.) /// /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher @@ -82,9 +104,9 @@ } /// Trait for distances with respect to a norm. -pub trait Dist : Norm { +pub trait Dist : Norm + Space { /// Calculate the distance - fn dist(&self, other : &Self, _p : Exponent) -> F; + fn dist>(&self, other : I, _p : Exponent) -> F; } /// Trait for Euclidean projections to the `Exponent`-[`Norm`]-ball. @@ -97,7 +119,7 @@ /// /// println!("{:?}, {:?}", x.proj_ball(1.0, L2), x.proj_ball(0.5, Linfinity)); /// ``` -pub trait Projection : Norm + Euclidean +pub trait Projection : Norm + Sized where F : Float { /// Projection of `self` to the `q`-norm-ball of radius ρ. fn proj_ball(mut self, ρ : F, q : Exponent) -> Self { @@ -106,7 +128,7 @@ } /// In-place projection of `self` to the `q`-norm-ball of radius ρ. - fn proj_ball_mut(&mut self, ρ : F, _q : Exponent); + fn proj_ball_mut(&mut self, ρ : F, q : Exponent); } /*impl> Norm for E { @@ -149,8 +171,149 @@ } impl> Dist> for E { - fn dist(&self, other : &Self, huber : HuberL1) -> F { + fn dist>(&self, other : I, huber : HuberL1) -> F { huber.apply(self.dist2_squared(other)) } } +// impl> Norm for Vec { +// fn norm(&self, _l21 : L21) -> F { +// self.iter().map(|e| e.norm(L2)).sum() +// } +// } + +// impl> Dist for Vec { +// fn dist>(&self, other : I, _l21 : L21) -> F { +// self.iter().zip(other.iter()).map(|(e, g)| e.dist(g, L2)).sum() +// } +// } + +impl Mapping for NormMapping +where + F : Float, + E : NormExponent, + Domain : Space + Norm, +{ + type Codomain = F; + + #[inline] + fn apply>(&self, x : I) -> F { + x.eval(|r| r.norm(self.exponent)) + } +} + +pub trait Normed : Space + Norm { + type NormExp : NormExponent; + + fn norm_exponent(&self) -> Self::NormExp; + + #[inline] + fn norm_(&self) -> F { + self.norm(self.norm_exponent()) + } + + // fn similar_origin(&self) -> Self; + + fn is_zero(&self) -> bool; +} + +pub trait HasDual : Normed { + type DualSpace : Normed; +} + +/// Automatically implemented trait for reflexive spaces +pub trait Reflexive : HasDual +where + Self::DualSpace : HasDual +{ } + +impl> Reflexive for X +where + X::DualSpace : HasDual +{ } + +pub trait HasDualExponent : NormExponent { + type DualExp : NormExponent; + + fn dual_exponent(&self) -> Self::DualExp; +} + +impl HasDualExponent for L2 { + type DualExp = L2; + + #[inline] + fn dual_exponent(&self) -> Self::DualExp { + L2 + } +} + +impl HasDualExponent for L1 { + type DualExp = Linfinity; + + #[inline] + fn dual_exponent(&self) -> Self::DualExp { + Linfinity + } +} + + +impl HasDualExponent for Linfinity { + type DualExp = L1; + + #[inline] + fn dual_exponent(&self) -> Self::DualExp { + L1 + } +} + +#[macro_export] +macro_rules! impl_weighted_norm { + ($exponent : ty) => { + impl Norm> for D + where + F : Float, + D : Norm, + C : Constant, + { + fn norm(&self, e : Weighted<$exponent, C>) -> F { + let v = e.weight.value(); + assert!(v > F::ZERO); + v * self.norm(e.base_fn) + } + } + + impl NormExponent for Weighted<$exponent, C> {} + + impl HasDualExponent for Weighted<$exponent, C> + where $exponent : HasDualExponent { + type DualExp = Weighted<<$exponent as HasDualExponent>::DualExp, C::Type>; + + fn dual_exponent(&self) -> Self::DualExp { + Weighted { + weight : C::Type::ONE / self.weight.value(), + base_fn : self.base_fn.dual_exponent() + } + } + } + + impl Projection> for T + where + T : Projection, + F : Float, + C : Constant, + { + fn proj_ball(self, ρ : F, q : Weighted<$exponent , C>) -> Self { + self.proj_ball(ρ / q.weight.value(), q.base_fn) + } + + fn proj_ball_mut(&mut self, ρ : F, q : Weighted<$exponent , C>) { + self.proj_ball_mut(ρ / q.weight.value(), q.base_fn) + } + } + } +} + +//impl_weighted_norm!(L1); +//impl_weighted_norm!(L2); +//impl_weighted_norm!(Linfinity); +