src/norms.rs

changeset 90
b3c35d16affe
parent 72
44a4f258a1ff
child 86
d5b0e496b72f
--- 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<F : Float, E : NormExponent>{
+    pub(crate) exponent : E,
+    _phantoms : PhantomData<F>
+}
+
 /// 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<F : Float>(self) -> NormMapping<F, Self> {
+        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<A, B, J>(pub A, pub B, pub J);
+
+impl<A, B, J> NormExponent for PairNorm<A, B, J>
+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<F : Num, Exponent : NormExponent> : Norm<F, Exponent> {
+pub trait Dist<F : Num, Exponent : NormExponent> : Norm<F, Exponent> + Space {
     /// Calculate the distance
-    fn dist(&self, other : &Self, _p : Exponent) -> F;
+    fn dist<I : Instance<Self>>(&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<F : Num, Exponent : NormExponent> : Norm<F, Exponent> + Euclidean<F>
+pub trait Projection<F : Num, Exponent : NormExponent> : Norm<F, Exponent> + 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<F : Float, E : Euclidean<F>> Norm<F, L2> for E {
@@ -149,8 +171,149 @@
 }
 
 impl<F : Float, E : Euclidean<F>> Dist<F, HuberL1<F>> for E {
-    fn dist(&self, other : &Self, huber : HuberL1<F>) -> F {
+    fn dist<I : Instance<Self>>(&self, other : I, huber : HuberL1<F>) -> F {
         huber.apply(self.dist2_squared(other))
     }
 }
 
+// impl<F : Float, E : Norm<F, L2>> Norm<F, L21> for Vec<E> {
+//     fn norm(&self, _l21 : L21) -> F {
+//         self.iter().map(|e| e.norm(L2)).sum()
+//     }
+// }
+
+// impl<F : Float, E : Dist<F, L2>> Dist<F, L21> for Vec<E> {
+//     fn dist<I : Instance<Self>>(&self, other : I, _l21 : L21) -> F {
+//         self.iter().zip(other.iter()).map(|(e, g)| e.dist(g, L2)).sum()
+//     }
+// }
+
+impl<E, F, Domain> Mapping<Domain> for NormMapping<F, E>
+where
+    F : Float,
+    E : NormExponent,
+    Domain : Space + Norm<F, E>,
+{
+    type Codomain = F;
+
+    #[inline]
+    fn apply<I : Instance<Domain>>(&self, x : I) -> F {
+        x.eval(|r| r.norm(self.exponent))
+    }
+}
+
+pub trait Normed<F : Num = f64> : Space + Norm<F, Self::NormExp> {
+    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<F : Num = f64> : Normed<F> {
+    type DualSpace : Normed<F>;
+}
+
+/// Automatically implemented trait for reflexive spaces
+pub trait Reflexive<F : Num = f64> : HasDual<F>
+where
+    Self::DualSpace : HasDual<F, DualSpace = Self>
+{ }
+
+impl<F : Num, X : HasDual<F>> Reflexive<F> for X
+where
+    X::DualSpace : HasDual<F, DualSpace = X>
+{ }
+
+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<C, F, D> Norm<F, Weighted<$exponent, C>> for D
+        where
+            F : Float,
+            D : Norm<F, $exponent>,
+            C : Constant<Type = F>,
+        {
+            fn norm(&self, e : Weighted<$exponent, C>) -> F {
+                let v = e.weight.value();
+                assert!(v > F::ZERO);
+                v * self.norm(e.base_fn)
+            }
+        }
+
+        impl<C : Constant> NormExponent for Weighted<$exponent, C> {}
+
+        impl<C : Constant> 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<C, F, T> Projection<F, Weighted<$exponent , C>> for T
+        where
+            T : Projection<F, $exponent >,
+            F : Float,
+            C : Constant<Type = F>,
+        {
+            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);
+

mercurial