diff -r 1f19c6bbf07b -r 3868555d135c src/mapping.rs --- 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 { - type Codomain : Space; +pub trait Mapping { + type Codomain: ClosedSpace; /// Compute the value of `self` at `x`. - fn apply>(&self, x : I) -> Self::Codomain; + fn apply>(&self, x: I) -> Self::Codomain; #[inline] /// Form the composition `self ∘ other` - fn compose>(self, other : T) - -> Composition + fn compose>(self, other: T) -> Composition 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( - self, other : T, norm : E - ) -> Composition + fn compose_with_norm(self, other: T, norm: E) -> Composition where - Self : Sized, - X : Space, - T : Mapping, - E : NormExponent, - Domain : Norm, - F : Num + Self: Sized, + X: Space, + T: Mapping, + E: NormExponent, + Domain: Norm, + 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(self, a : C) -> Weighted + fn weigh(self, a: C) -> Weighted where - Self : Sized, - C : Constant, - Self::Codomain : ClosedMul, + Self: Sized, + C: Constant, + Self::Codomain: ClosedMul, { - Weighted { weight : a, base_fn : self } + Weighted { weight: a, base_fn: self } } } -/// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc`] to `F`. -pub trait RealMapping -: Mapping, Codomain = F> {} +/// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc`] to `F`. +pub trait RealMapping: Mapping, Codomain = F> {} -impl RealMapping for T -where T : Mapping, Codomain = F> {} +impl RealMapping for T where T: Mapping, Codomain = F> {} -/// A helper trait alias for referring to [`Mapping`]s from [`Loc`] to [`Loc`]. -pub trait RealVectorField -: Mapping, Codomain = Loc> {} +/// A helper trait alias for referring to [`Mapping`]s from [`Loc`] to [`Loc`]. +pub trait RealVectorField: + Mapping, Codomain = Loc> +{ +} -impl RealVectorField for T -where T : Mapping, Codomain = Loc> {} +impl RealVectorField for T where + T: Mapping, Codomain = Loc> +{ +} /// A differentiable mapping from `Domain` to [`Mapping::Codomain`], with differentials /// `Differential`. /// /// This is automatically implemented when [`DifferentiableImpl`] is. -pub trait DifferentiableMapping : Mapping { - type DerivativeDomain : Space; - type Differential<'b> : Mapping where Self : 'b; +pub trait DifferentiableMapping: Mapping { + type DerivativeDomain: ClosedSpace; + type Differential<'b>: Mapping + where + Self: 'b; /// Calculate differential at `x` - fn differential>(&self, x : I) -> Self::DerivativeDomain; + fn differential>(&self, x: I) -> Self::DerivativeDomain; + + /// Calculate differential and value at `x` + fn apply_and_differential>( + &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`] to `F`. -pub trait DifferentiableRealMapping -: DifferentiableMapping, Codomain = F, DerivativeDomain = Loc> {} +/// [`Loc`] to `F`. +pub trait DifferentiableRealMapping: + DifferentiableMapping, Codomain = F, DerivativeDomain = Loc> +{ +} -impl DifferentiableRealMapping for T -where T : DifferentiableMapping, Codomain = F, DerivativeDomain = Loc> {} +impl DifferentiableRealMapping for T where + T: DifferentiableMapping, Codomain = F, DerivativeDomain = Loc> +{ +} /// Helper trait for implementing [`DifferentiableMapping`] -pub trait DifferentiableImpl : Sized { - type Derivative : Space; +pub trait DifferentiableImpl: Sized { + type Derivative: ClosedSpace; /// Compute the differential of `self` at `x`, consuming the input. - fn differential_impl>(&self, x : I) -> Self::Derivative; + fn differential_impl>(&self, x: I) -> Self::Derivative; + + fn apply_and_differential_impl>( + &self, + x: I, + ) -> (Self::Codomain, Self::Derivative) + where + Self: Mapping, + { + x.eval_ref(|xo| (self.apply(xo), self.differential_impl(xo))) + } } impl DifferentiableMapping for T where - Domain : Space, - T : Clone + Mapping + DifferentiableImpl + Domain: Space, + T: Mapping + DifferentiableImpl, { 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>(&self, x : I) -> Self::DerivativeDomain { + fn differential>(&self, x: I) -> Self::DerivativeDomain { self.differential_impl(x) } + #[inline] + fn apply_and_differential>( + &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 +pub struct Differential<'a, X, G> { + g: MyCow<'a, G>, + _space: PhantomData, } -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 for Differential<'a, X, G> where - X : Space, - G : Clone + DifferentiableMapping + X: Space, + G: DifferentiableMapping, { type Codomain = G::DerivativeDomain; #[inline] - fn apply>(&self, x : I) -> Self::Codomain { + fn apply>(&self, x: I) -> Self::Codomain { (*self.g).differential(x) } } /// Container for flattening [`Loc`]`` codomain of a [`Mapping`] to `F`. pub struct FlattenedCodomain { - g : G, - _phantoms : PhantomData<(X, F)> + g: G, + _phantoms: PhantomData<(X, F)>, } -impl Mapping for FlattenedCodomain +impl Mapping for FlattenedCodomain where - X : Space, - G: Mapping> + F: ClosedSpace, + X: Space, + G: Mapping>, { type Codomain = F; #[inline] - fn apply>(&self, x : I) -> Self::Codomain { + fn apply>(&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`]`` to `F`. -pub trait FlattenCodomain : Mapping> + Sized { +pub trait FlattenCodomain: Mapping> + Sized { /// Flatten the codomain from [`Loc`]`` to `F`. fn flatten_codomain(self) -> FlattenedCodomain { - FlattenedCodomain{ g : self, _phantoms : PhantomData } + FlattenedCodomain { g: self, _phantoms: PhantomData } } } -impl>> FlattenCodomain for G {} +impl>> FlattenCodomain for G {} -/// Container for dimensional slicing [`Loc`]`` 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`]`` 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 for SlicedCodomain<'a, X, F, G, N> +impl<'a, X, F, G, const N: usize> Mapping for SlicedCodomain<'a, X, F, G, N> where - X : Space, - F : Copy + Space, - G : Mapping> + Clone, + X: Space, + F: Copy + ClosedSpace, + G: Mapping>, { type Codomain = F; #[inline] - fn apply>(&self, x : I) -> Self::Codomain { - let tmp : [F; N] = (*self.g).apply(x).into(); + fn apply>(&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`]`` to `F`. -pub trait SliceCodomain - : Mapping> + Clone + Sized +pub trait SliceCodomain: + Mapping> + Sized { /// Flatten the codomain from [`Loc`]`` 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`]`` 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> + Clone, const N : usize> -SliceCodomain -for G {} - +impl>, const N: usize> + SliceCodomain for G +{ +} /// The composition S ∘ T. `E` is for storing a `NormExponent` for the intermediate space. pub struct Composition { - pub outer : S, - pub inner : T, - pub intermediate_norm_exponent : E + pub outer: S, + pub inner: T, + pub intermediate_norm_exponent: E, } impl Mapping for Composition where - X : Space, - T : Mapping, - S : Mapping + X: Space, + T: Mapping, + S: Mapping, { type Codomain = S::Codomain; #[inline] - fn apply>(&self, x : I) -> Self::Codomain { + fn apply>(&self, x: I) -> Self::Codomain { self.outer.apply(self.inner.apply(x)) } } + +/// Helper trait for implementing [`DifferentiableMapping`] +impl DifferentiableImpl for Composition +where + X: Space, + T: DifferentiableImpl + Mapping, + S: DifferentiableImpl, + E: Copy, + //Composition: Space, + S::Derivative: Mul, + Y: ClosedSpace, +{ + //type Derivative = Composition; + type Derivative = Y; + + /// Compute the differential of `self` at `x`, consuming the input. + fn differential_impl>(&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 { + /// 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; +} + +/// Helper trait for implementing [`Lipschitz`] for mappings that implement [`DifferentiableImpl`]. +pub trait LipschitzDifferentiableImpl: DifferentiableImpl { + type FloatType: Float; + + /// Compute the lipschitz factor of the derivative of `f`. + fn diff_lipschitz_factor(&self, seminorm: M) -> DynResult; +} + +impl<'b, M, X, A> Lipschitz for Differential<'b, X, A> +where + X: Space, + A: LipschitzDifferentiableImpl, +{ + type FloatType = A::FloatType; + + fn lipschitz_factor(&self, seminorm: M) -> DynResult { + (*self.g).diff_lipschitz_factor(seminorm) + } +}