src/mapping.rs

changeset 198
3868555d135c
parent 194
a5ee4bfb0b87
--- a/src/mapping.rs	Sun Apr 27 20:29:43 2025 -0500
+++ b/src/mapping.rs	Fri May 15 14:46:30 2026 -0500
@@ -2,84 +2,94 @@
 Traits for mathematical functions.
 */
 
-use std::marker::PhantomData;
-use std::borrow::Cow;
-use crate::types::{Num, Float, ClosedMul};
+use crate::error::DynResult;
+use crate::instance::MyCow;
+pub use crate::instance::{BasicDecomposition, ClosedSpace, Decomposition, Instance, Space};
 use crate::loc::Loc;
-pub use crate::instance::{Instance, Decomposition, BasicDecomposition, Space};
 use crate::norms::{Norm, NormExponent};
-use crate::operator_arithmetic::{Weighted, Constant};
+use crate::operator_arithmetic::{Constant, Weighted};
+use crate::types::{ClosedMul, Float, Num};
+use std::marker::PhantomData;
+use std::ops::Mul;
 
 /// A mapping from `Domain` to `Self::Codomain`.
-pub trait Mapping<Domain : Space> {
-    type Codomain : Space;
+pub trait Mapping<Domain: Space> {
+    type Codomain: ClosedSpace;
 
     /// Compute the value of `self` at `x`.
-    fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain;
+    fn apply<I: Instance<Domain>>(&self, x: I) -> Self::Codomain;
 
     #[inline]
     /// Form the composition `self ∘ other`
-    fn compose<X : Space, T : Mapping<X, Codomain=Domain>>(self, other : T)
-        -> Composition<Self, T>
+    fn compose<X: Space, T: Mapping<X, Codomain = Domain>>(self, other: T) -> Composition<Self, T>
     where
-        Self : Sized
+        Self: Sized,
     {
-        Composition{ outer : self, inner : other, intermediate_norm_exponent : () }
+        Composition { outer: self, inner: other, intermediate_norm_exponent: () }
     }
 
-
     #[inline]
     /// Form the composition `self ∘ other`, assigning a norm to the inermediate space
-    fn compose_with_norm<F, X, T, E>(
-        self, other : T, norm : E
-    )  -> Composition<Self, T, E>
+    fn compose_with_norm<F, X, T, E>(self, other: T, norm: E) -> Composition<Self, T, E>
     where
-        Self : Sized,
-        X : Space,
-        T : Mapping<X, Codomain=Domain>,
-        E : NormExponent,
-        Domain : Norm<F, E>,
-        F : Num
+        Self: Sized,
+        X: Space,
+        T: Mapping<X, Codomain = Domain>,
+        E: NormExponent,
+        Domain: Norm<E, F>,
+        F: Num,
     {
-        Composition{ outer : self, inner : other, intermediate_norm_exponent : norm }
+        Composition { outer: self, inner: other, intermediate_norm_exponent: norm }
     }
 
     /// Multiply `self` by the scalar `a`.
     #[inline]
-    fn weigh<C>(self, a : C) -> Weighted<Self, C>
+    fn weigh<C>(self, a: C) -> Weighted<Self, C>
     where
-        Self : Sized,
-        C : Constant,
-        Self::Codomain : ClosedMul<C::Type>,
+        Self: Sized,
+        C: Constant,
+        Self::Codomain: ClosedMul<C::Type>,
     {
-        Weighted { weight : a, base_fn : self }
+        Weighted { weight: a, base_fn: self }
     }
 }
 
-/// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc<F, N>`] to `F`.
-pub trait RealMapping<F : Float, const N : usize>
-: Mapping<Loc<F, N>, Codomain = F> {}
+/// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc<N, F>`] to `F`.
+pub trait RealMapping<const N: usize, F: Float = f64>: Mapping<Loc<N, F>, Codomain = F> {}
 
-impl<F : Float, T, const N : usize> RealMapping<F, N> for T
-where T : Mapping<Loc<F, N>, Codomain = F> {}
+impl<F: Float, T, const N: usize> RealMapping<N, F> for T where T: Mapping<Loc<N, F>, Codomain = F> {}
 
-/// A helper trait alias for referring to [`Mapping`]s from [`Loc<F, N>`] to [`Loc<F, M>`].
-pub trait RealVectorField<F : Float, const N : usize, const M : usize>
-: Mapping<Loc<F, N>, Codomain = Loc<F, M>> {}
+/// A helper trait alias for referring to [`Mapping`]s from [`Loc<N, F>`] to [`Loc<M, F>`].
+pub trait RealVectorField<const N: usize, const M: usize, F: Float = f64>:
+    Mapping<Loc<N, F>, Codomain = Loc<M, F>>
+{
+}
 
-impl<F : Float, T, const N : usize, const M : usize> RealVectorField<F, N, M> for T
-where T : Mapping<Loc<F, N>, Codomain = Loc<F, M>> {}
+impl<F: Float, T, const N: usize, const M: usize> RealVectorField<N, M, F> for T where
+    T: Mapping<Loc<N, F>, Codomain = Loc<M, F>>
+{
+}
 
 /// A differentiable mapping from `Domain` to [`Mapping::Codomain`], with differentials
 /// `Differential`.
 ///
 /// This is automatically implemented when [`DifferentiableImpl`] is.
-pub trait DifferentiableMapping<Domain : Space> : Mapping<Domain> {
-    type DerivativeDomain : Space;
-    type Differential<'b> : Mapping<Domain, Codomain=Self::DerivativeDomain> where Self : 'b;
+pub trait DifferentiableMapping<Domain: Space>: Mapping<Domain> {
+    type DerivativeDomain: ClosedSpace;
+    type Differential<'b>: Mapping<Domain, Codomain = Self::DerivativeDomain>
+    where
+        Self: 'b;
 
     /// Calculate differential at `x`
-    fn differential<I : Instance<Domain>>(&self, x : I) -> Self::DerivativeDomain;
+    fn differential<I: Instance<Domain>>(&self, x: I) -> Self::DerivativeDomain;
+
+    /// Calculate differential and value at `x`
+    fn apply_and_differential<I: Instance<Domain>>(
+        &self,
+        x: I,
+    ) -> (Self::Codomain, Self::DerivativeDomain) {
+        x.eval_ref(|xo| (self.apply(xo), self.differential(xo)))
+    }
 
     /// Form the differential mapping of `self`.
     fn diff(self) -> Self::Differential<'static>;
@@ -89,51 +99,75 @@
 }
 
 /// Automatically implemented shorthand for referring to differentiable [`Mapping`]s from
-/// [`Loc<F, N>`] to `F`.
-pub trait DifferentiableRealMapping<F : Float, const N : usize>
-: DifferentiableMapping<Loc<F, N>, Codomain = F, DerivativeDomain = Loc<F, N>> {}
+/// [`Loc<N, F>`] to `F`.
+pub trait DifferentiableRealMapping<const N: usize, F: Float>:
+    DifferentiableMapping<Loc<N, F>, Codomain = F, DerivativeDomain = Loc<N, F>>
+{
+}
 
-impl<F : Float, T, const N : usize> DifferentiableRealMapping<F, N> for T
-where T : DifferentiableMapping<Loc<F, N>, Codomain = F, DerivativeDomain = Loc<F, N>> {}
+impl<F: Float, T, const N: usize> DifferentiableRealMapping<N, F> for T where
+    T: DifferentiableMapping<Loc<N, F>, Codomain = F, DerivativeDomain = Loc<N, F>>
+{
+}
 
 /// Helper trait for implementing [`DifferentiableMapping`]
-pub trait DifferentiableImpl<X : Space> : Sized {
-    type Derivative : Space;
+pub trait DifferentiableImpl<X: Space>: Sized {
+    type Derivative: ClosedSpace;
 
     /// Compute the differential of `self` at `x`, consuming the input.
-    fn differential_impl<I : Instance<X>>(&self, x : I) -> Self::Derivative;
+    fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative;
+
+    fn apply_and_differential_impl<I: Instance<X>>(
+        &self,
+        x: I,
+    ) -> (Self::Codomain, Self::Derivative)
+    where
+        Self: Mapping<X>,
+    {
+        x.eval_ref(|xo| (self.apply(xo), self.differential_impl(xo)))
+    }
 }
 
 impl<T, Domain> DifferentiableMapping<Domain> for T
 where
-    Domain : Space,
-    T : Clone + Mapping<Domain> + DifferentiableImpl<Domain>
+    Domain: Space,
+    T: Mapping<Domain> + DifferentiableImpl<Domain>,
 {
     type DerivativeDomain = T::Derivative;
-    type Differential<'b> = Differential<'b, Domain, Self> where Self : 'b;
-    
+    type Differential<'b>
+        = Differential<'b, Domain, Self>
+    where
+        Self: 'b;
+
     #[inline]
-    fn differential<I : Instance<Domain>>(&self, x : I) -> Self::DerivativeDomain {
+    fn differential<I: Instance<Domain>>(&self, x: I) -> Self::DerivativeDomain {
         self.differential_impl(x)
     }
 
+    #[inline]
+    fn apply_and_differential<I: Instance<Domain>>(
+        &self,
+        x: I,
+    ) -> (T::Codomain, Self::DerivativeDomain) {
+        self.apply_and_differential_impl(x)
+    }
+
     fn diff(self) -> Differential<'static, Domain, Self> {
-        Differential{ g : Cow::Owned(self), _space : PhantomData }
+        Differential { g: MyCow::Owned(self), _space: PhantomData }
     }
 
     fn diff_ref(&self) -> Differential<'_, Domain, Self> {
-        Differential{ g : Cow::Borrowed(self), _space : PhantomData }
+        Differential { g: MyCow::Borrowed(self), _space: PhantomData }
     }
 }
 
-
 /// Container for the differential [`Mapping`] of a [`DifferentiableMapping`].
-pub struct Differential<'a, X, G : Clone> {
-    g : Cow<'a, G>,
-    _space : PhantomData<X>
+pub struct Differential<'a, X, G> {
+    g: MyCow<'a, G>,
+    _space: PhantomData<X>,
 }
 
-impl<'a, X, G : Clone> Differential<'a, X, G> {
+impl<'a, X, G> Differential<'a, X, G> {
     pub fn base_fn(&self) -> &G {
         &self.g
     }
@@ -141,65 +175,66 @@
 
 impl<'a, X, G> Mapping<X> for Differential<'a, X, G>
 where
-    X : Space,
-    G : Clone + DifferentiableMapping<X>
+    X: Space,
+    G: DifferentiableMapping<X>,
 {
     type Codomain = G::DerivativeDomain;
 
     #[inline]
-    fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
+    fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
         (*self.g).differential(x)
     }
 }
 
 /// Container for flattening [`Loc`]`<F, 1>` codomain of a [`Mapping`] to `F`.
 pub struct FlattenedCodomain<X, F, G> {
-    g : G,
-    _phantoms : PhantomData<(X, F)>
+    g: G,
+    _phantoms: PhantomData<(X, F)>,
 }
 
-impl<F : Space, X, G> Mapping<X> for FlattenedCodomain<X, F, G>
+impl<F, X, G> Mapping<X> for FlattenedCodomain<X, F, G>
 where
-    X : Space,
-    G: Mapping<X, Codomain=Loc<F, 1>>
+    F: ClosedSpace,
+    X: Space,
+    G: Mapping<X, Codomain = Loc<1, F>>,
 {
     type Codomain = F;
 
     #[inline]
-    fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
+    fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
         self.g.apply(x).flatten1d()
     }
 }
 
 /// An auto-trait for constructing a [`FlattenCodomain`] structure for
 /// flattening the codomain of a [`Mapping`] from [`Loc`]`<F, 1>` to `F`.
-pub trait FlattenCodomain<X : Space, F> : Mapping<X, Codomain=Loc<F, 1>> + Sized {
+pub trait FlattenCodomain<X: Space, F>: Mapping<X, Codomain = Loc<1, F>> + Sized {
     /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
     fn flatten_codomain(self) -> FlattenedCodomain<X, F, Self> {
-        FlattenedCodomain{ g : self, _phantoms : PhantomData }
+        FlattenedCodomain { g: self, _phantoms: PhantomData }
     }
 }
 
-impl<X : Space, F, G : Sized + Mapping<X, Codomain=Loc<F, 1>>> FlattenCodomain<X, F> for G {}
+impl<X: Space, F, G: Sized + Mapping<X, Codomain = Loc<1, F>>> FlattenCodomain<X, F> for G {}
 
-/// Container for dimensional slicing [`Loc`]`<F, N>` codomain of a [`Mapping`] to `F`.
-pub struct SlicedCodomain<'a, X, F, G : Clone, const N : usize> {
-    g : Cow<'a, G>,
-    slice : usize,
-    _phantoms : PhantomData<(X, F)>
+/// Container for dimensional slicing [`Loc`]`<N, F>` codomain of a [`Mapping`] to `F`.
+pub struct SlicedCodomain<'a, X, F, G, const N: usize> {
+    g: MyCow<'a, G>,
+    slice: usize,
+    _phantoms: PhantomData<(X, F)>,
 }
 
-impl<'a, X, F, G, const N : usize> Mapping<X> for SlicedCodomain<'a, X, F, G, N>
+impl<'a, X, F, G, const N: usize> Mapping<X> for SlicedCodomain<'a, X, F, G, N>
 where
-    X : Space,
-    F : Copy + Space,
-    G : Mapping<X, Codomain=Loc<F, N>> + Clone,
+    X: Space,
+    F: Copy + ClosedSpace,
+    G: Mapping<X, Codomain = Loc<N, F>>,
 {
     type Codomain = F;
 
     #[inline]
-    fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
-        let tmp : [F; N] = (*self.g).apply(x).into();
+    fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
+        let tmp: [F; N] = (*self.g).apply(x).into();
         // Safety: `slice_codomain` below checks the range.
         unsafe { *tmp.get_unchecked(self.slice) }
     }
@@ -207,44 +242,106 @@
 
 /// An auto-trait for constructing a [`FlattenCodomain`] structure for
 /// flattening the codomain of a [`Mapping`] from [`Loc`]`<F, 1>` to `F`.
-pub trait SliceCodomain<X : Space, F : Copy, const N : usize>
-    : Mapping<X, Codomain=Loc<F, N>> + Clone + Sized
+pub trait SliceCodomain<X: Space, const N: usize, F: Copy = f64>:
+    Mapping<X, Codomain = Loc<N, F>> + Sized
 {
     /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
-    fn slice_codomain(self, slice : usize) -> SlicedCodomain<'static, X, F, Self, N> {
+    fn slice_codomain(self, slice: usize) -> SlicedCodomain<'static, X, F, Self, N> {
         assert!(slice < N);
-        SlicedCodomain{ g : Cow::Owned(self), slice, _phantoms : PhantomData }
+        SlicedCodomain { g: MyCow::Owned(self), slice, _phantoms: PhantomData }
     }
 
     /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
-    fn slice_codomain_ref(&self, slice : usize) -> SlicedCodomain<'_, X, F, Self, N> {
+    fn slice_codomain_ref(&self, slice: usize) -> SlicedCodomain<'_, X, F, Self, N> {
         assert!(slice < N);
-        SlicedCodomain{ g : Cow::Borrowed(self), slice, _phantoms : PhantomData }
+        SlicedCodomain { g: MyCow::Borrowed(self), slice, _phantoms: PhantomData }
     }
 }
 
-impl<X : Space, F : Copy, G : Sized + Mapping<X, Codomain=Loc<F, N>> + Clone, const N : usize>
-SliceCodomain<X, F, N>
-for G {}
-
+impl<X: Space, F: Copy, G: Sized + Mapping<X, Codomain = Loc<N, F>>, const N: usize>
+    SliceCodomain<X, N, F> for G
+{
+}
 
 /// The composition S ∘ T. `E` is for storing a `NormExponent` for the intermediate space.
 pub struct Composition<S, T, E = ()> {
-    pub outer : S,
-    pub inner : T,
-    pub intermediate_norm_exponent : E
+    pub outer: S,
+    pub inner: T,
+    pub intermediate_norm_exponent: E,
 }
 
 impl<S, T, X, E> Mapping<X> for Composition<S, T, E>
 where
-    X : Space,
-    T : Mapping<X>,
-    S : Mapping<T::Codomain>
+    X: Space,
+    T: Mapping<X>,
+    S: Mapping<T::Codomain>,
 {
     type Codomain = S::Codomain;
 
     #[inline]
-    fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
+    fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
         self.outer.apply(self.inner.apply(x))
     }
 }
+
+/// Helper trait for implementing [`DifferentiableMapping`]
+impl<S, T, X, E, Y> DifferentiableImpl<X> for Composition<S, T, E>
+where
+    X: Space,
+    T: DifferentiableImpl<X> + Mapping<X>,
+    S: DifferentiableImpl<T::Codomain>,
+    E: Copy,
+    //Composition<S::Derivative, T::Derivative, E>: Space,
+    S::Derivative: Mul<T::Derivative, Output = Y>,
+    Y: ClosedSpace,
+{
+    //type Derivative = Composition<S::Derivative, T::Derivative, E>;
+    type Derivative = Y;
+
+    /// Compute the differential of `self` at `x`, consuming the input.
+    fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative {
+        // Composition {
+        //     outer: self
+        //         .outer
+        //         .differential_impl(self.inner.apply(x.ref_instance())),
+        //     inner: self.inner.differential_impl(x),
+        //     intermediate_norm_exponent: self.intermediate_norm_exponent,
+        // }
+
+        self.outer
+            .differential_impl(x.eval_ref(|r| self.inner.apply(r)))
+            * self.inner.differential_impl(x)
+    }
+}
+
+mod dataterm;
+pub use dataterm::DataTerm;
+
+/// Trait for indicating that `Self` is Lipschitz with respect to the (semi)norm `D`.
+pub trait Lipschitz<M> {
+    /// The type of floats
+    type FloatType: Float;
+
+    /// Returns the Lipschitz factor of `self` with respect to the (semi)norm `D`.
+    fn lipschitz_factor(&self, seminorm: M) -> DynResult<Self::FloatType>;
+}
+
+/// Helper trait for implementing [`Lipschitz`] for mappings that implement [`DifferentiableImpl`].
+pub trait LipschitzDifferentiableImpl<X: Space, M>: DifferentiableImpl<X> {
+    type FloatType: Float;
+
+    /// Compute the lipschitz factor of the derivative of `f`.
+    fn diff_lipschitz_factor(&self, seminorm: M) -> DynResult<Self::FloatType>;
+}
+
+impl<'b, M, X, A> Lipschitz<M> for Differential<'b, X, A>
+where
+    X: Space,
+    A: LipschitzDifferentiableImpl<X, M>,
+{
+    type FloatType = A::FloatType;
+
+    fn lipschitz_factor(&self, seminorm: M) -> DynResult<Self::FloatType> {
+        (*self.g).diff_lipschitz_factor(seminorm)
+    }
+}

mercurial