diff -r d14c877e14b7 -r b3c35d16affe src/mapping.rs --- a/src/mapping.rs Tue Feb 20 12:33:16 2024 -0500 +++ b/src/mapping.rs Mon Feb 03 19:22:16 2025 -0500 @@ -3,115 +3,248 @@ */ use std::marker::PhantomData; -use crate::types::{Float}; -use serde::Serialize; +use std::borrow::Cow; +use crate::types::{Num, Float, ClosedMul}; use crate::loc::Loc; +pub use crate::instance::{Instance, Decomposition, BasicDecomposition, Space}; +use crate::norms::{Norm, NormExponent}; +use crate::operator_arithmetic::{Weighted, Constant}; -/// Trait for application of `Self` as a mathematical function or operator on `X`. -pub trait Apply { - type Output; +/// A mapping from `Domain` to `Self::Codomain`. +pub trait Mapping { + type Codomain : Space; /// Compute the value of `self` at `x`. - fn apply(&self, x : X) -> Self::Output; -} + fn apply>(&self, x : I) -> Self::Codomain; -/// This blanket implementation is a workaround helper to Rust trait system limitations. -/// -/// It is introduced because the trait system does not allow blanket implementations of both -/// [`Apply`] and [`Apply<&'a X>`]. With this, the latter is implemented automatically for -/// the reference, which can be sufficient to apply the operation in another blanket implementation. -impl<'a, T, X> Apply for &'a T where T : Apply { - type Output = >::Output; + #[inline] + /// Form the composition `self ∘ other` + fn compose>(self, other : T) + -> Composition + where + Self : Sized + { + Composition{ outer : self, inner : other, intermediate_norm_exponent : () } + } + #[inline] - fn apply(&self, x : X) -> Self::Output { - (*self).apply(x) + /// Form the composition `self ∘ other`, assigning a norm to the inermediate space + fn compose_with_norm( + self, other : T, norm : E + ) -> Composition + where + Self : Sized, + X : Space, + T : Mapping, + E : NormExponent, + Domain : Norm, + F : Num + { + Composition{ outer : self, inner : other, intermediate_norm_exponent : norm } + } + + /// Multiply `self` by the scalar `a`. + #[inline] + fn weigh(self, a : C) -> Weighted + where + Self : Sized, + C : Constant, + Self::Codomain : ClosedMul, + { + Weighted { weight : a, base_fn : self } } } -/// A mapping from `Domain` to `Codomain`. -/// -/// This is automatically implemented when the relevant [`Apply`] are implemented. -pub trait Mapping : Apply - + for<'a> Apply<&'a Domain, Output=Self::Codomain> { - type Codomain; -} - -impl Mapping for T -where T : Apply + for<'a> Apply<&'a Domain, Output=Codomain> { - type Codomain = Codomain; -} - - -/// A helper trait alias for referring to [`Mapping`]s from [`Loc`] to `F` a [`Float`]. -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> {} - -/// Trait for calculation the differential of `Self` as a mathematical function on `X`. -pub trait Differentiate { - type Output; +/// A helper trait alias for referring to [`Mapping`]s from [`Loc`] to [`Loc`]. +pub trait RealVectorField +: Mapping, Codomain = Loc> {} - /// Compute the differential of `self` at `x`. - fn differential(&self, x : X) -> Self::Output; -} - +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 the relevant [`Differentiate`] are implemented. -pub trait DifferentiableMapping -: Mapping - + Differentiate - + for<'a> Differentiate<&'a Domain, Output=Self::Differential>{ - type Differential; +/// This is automatically implemented when [`DifferentiableImpl`] is. +pub trait DifferentiableMapping : Mapping { + type DerivativeDomain : Space; + type Differential<'b> : Mapping where Self : 'b; + + /// Calculate differential at `x` + fn differential>(&self, x : I) -> Self::DerivativeDomain; + + /// Form the differential mapping of `self`. + fn diff(self) -> Self::Differential<'static>; + + /// Form the differential mapping of `self`. + fn diff_ref(&self) -> Self::Differential<'_>; } +/// Automatically implemented shorthand for referring to differentiable [`Mapping`]s from +/// [`Loc`] to `F`. +pub trait DifferentiableRealMapping +: DifferentiableMapping, Codomain = F, DerivativeDomain = Loc> {} -impl DifferentiableMapping for T -where T : Mapping - + Differentiate - + for<'a> Differentiate<&'a Domain, Output=Differential> { - type Differential = Differential; +impl DifferentiableRealMapping for T +where T : DifferentiableMapping, Codomain = F, DerivativeDomain = Loc> {} + +/// Helper trait for implementing [`DifferentiableMapping`] +pub trait DifferentiableImpl : Sized { + type Derivative : Space; + + /// Compute the differential of `self` at `x`, consuming the input. + fn differential_impl>(&self, x : I) -> Self::Derivative; } -/// A sum of [`Mapping`]s. -#[derive(Serialize, Debug, Clone)] -pub struct Sum> { - components : Vec, - _domain : PhantomData, -} +impl DifferentiableMapping for T +where + Domain : Space, + T : Clone + Mapping + DifferentiableImpl +{ + type DerivativeDomain = T::Derivative; + type Differential<'b> = Differential<'b, Domain, Self> where Self : 'b; + + #[inline] + fn differential>(&self, x : I) -> Self::DerivativeDomain { + self.differential_impl(x) + } -impl> Sum { - /// Construct from an iterator. - pub fn new>(iter : I) -> Self { - Sum { components : iter.collect(), _domain : PhantomData } + fn diff(self) -> Differential<'static, Domain, Self> { + Differential{ g : Cow::Owned(self), _space : PhantomData } + } + + fn diff_ref(&self) -> Differential<'_, Domain, Self> { + Differential{ g : Cow::Borrowed(self), _space : PhantomData } } } -impl Apply for Sum -where M : Mapping, - M::Codomain : std::iter::Sum { - type Output = M::Codomain; +/// Container for the differential [`Mapping`] of a [`DifferentiableMapping`]. +pub struct Differential<'a, X, G : Clone> { + g : Cow<'a, G>, + _space : PhantomData +} + +impl<'a, X, G : Clone> Differential<'a, X, G> { + pub fn base_fn(&self) -> &G { + &self.g + } +} + +impl<'a, X, G> Mapping for Differential<'a, X, G> +where + X : Space, + G : Clone + DifferentiableMapping +{ + type Codomain = G::DerivativeDomain; + + #[inline] + fn apply>(&self, x : I) -> Self::Codomain { + (*self.g).differential(x) + } +} - fn apply(&self, x : Domain) -> Self::Output { - self.components.iter().map(|c| c.apply(x)).sum() +/// Container for flattening [`Loc`]`` codomain of a [`Mapping`] to `F`. +pub struct FlattenedCodomain { + g : G, + _phantoms : PhantomData<(X, F)> +} + +impl Mapping for FlattenedCodomain +where + X : Space, + G: Mapping> +{ + type Codomain = F; + + #[inline] + 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 { + /// Flatten the codomain from [`Loc`]`` to `F`. + fn flatten_codomain(self) -> FlattenedCodomain { + FlattenedCodomain{ g : self, _phantoms : PhantomData } } } -impl Differentiate for Sum -where M : DifferentiableMapping, - M :: Codomain : std::iter::Sum, - M :: Differential : std::iter::Sum, - Domain : Copy { +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)> +} - type Output = M::Differential; +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, +{ + type Codomain = F; - fn differential(&self, x : Domain) -> Self::Output { - self.components.iter().map(|c| c.differential(x)).sum() + #[inline] + 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) } } } + +/// 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 +{ + /// Flatten the codomain from [`Loc`]`` to `F`. + fn slice_codomain(self, slice : usize) -> SlicedCodomain<'static, X, F, Self, N> { + assert!(slice < N); + SlicedCodomain{ g : Cow::Owned(self), slice, _phantoms : PhantomData } + } + + /// Flatten the codomain from [`Loc`]`` to `F`. + fn slice_codomain_ref(&self, slice : usize) -> SlicedCodomain<'_, X, F, Self, N> { + assert!(slice < N); + SlicedCodomain{ g : Cow::Borrowed(self), slice, _phantoms : PhantomData } + } +} + +impl> + Clone, 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 +} + +impl Mapping for Composition +where + X : Space, + T : Mapping, + S : Mapping +{ + type Codomain = S::Codomain; + + #[inline] + fn apply>(&self, x : I) -> Self::Codomain { + self.outer.apply(self.inner.apply(x)) + } +}