src/mapping.rs

branch
dev
changeset 59
9226980e45a7
parent 53
08db78e3a654
child 61
05089fbc0310
--- a/src/mapping.rs	Sat Dec 14 09:31:27 2024 -0500
+++ b/src/mapping.rs	Tue Dec 31 08:30:02 2024 -0500
@@ -3,43 +3,20 @@
 */
 
 use std::marker::PhantomData;
+use std::borrow::Cow;
 use crate::types::Float;
 use serde::Serialize;
 use crate::loc::Loc;
-
-/// Trait for application of `Self` as a mathematical function or operator on `X`.
-pub trait Apply<X> {
-    type Output;
-
-    /// Compute the value of `self` at `x`.
-    fn apply(&self, x : X) -> Self::Output;
-}
-
-/// 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<X>`] 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<X> for &'a T where T : Apply<X> {
-    type Output = <T as Apply<X>>::Output;
-
-    #[inline]
-    fn apply(&self, x : X) -> Self::Output {
-        (*self).apply(x)
-    }
-}
+pub use crate::instance::{Instance, Decomposition, BasicDecomposition, Space};
 
 /// A mapping from `Domain` to `Codomain`.
 ///
 /// This is automatically implemented when the relevant [`Apply`] are implemented.
-pub trait Mapping<Domain> : Apply<Domain, Output=Self::Codomain>
-                            + for<'a> Apply<&'a Domain, Output=Self::Codomain> {
-    type Codomain;
-}
+pub trait Mapping<Domain : Space> {
+    type Codomain : Space;
 
-impl<Domain, Codomain, T> Mapping<Domain> for T
-where T : Apply<Domain, Output=Codomain> + for<'a> Apply<&'a Domain, Output=Codomain> {
-    type Codomain = Codomain;
+    /// Compute the value of `self` at `x`.
+    fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain;
 }
 
 /// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc<F, N>`] to `F`.
@@ -49,15 +26,6 @@
 impl<F : Float, T, const N : usize> RealMapping<F, N> for T
 where T : Mapping<Loc<F, N>, Codomain = F> {}
 
-/// 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>> {}
-
-impl<F : Float, T, const N : usize> DifferentiableRealMapping<F, N> for T
-where T : DifferentiableMapping<Loc<F, N>, Codomain = F, DerivativeDomain=Loc<F, N>> {}
-
-
 /// 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>> {}
@@ -65,69 +33,70 @@
 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>> {}
 
-
-/// Trait for calculation the differential of `Self` as a mathematical function on `X`.
-pub trait Differentiable<X> : Sized {
-    type Derivative;
-
-    /// Compute the differential of `self` at `x`.
-    fn differential(&self, x : X) -> Self::Derivative;
-}
-
-impl<'g, X, G : Differentiable<X>> Differentiable<X> for &'g G {
-    type Derivative = G::Derivative;
-    #[inline]
-    fn differential(&self, x : X) -> Self::Derivative {
-        (*self).differential(x)
-    }
-}
-
 /// A differentiable mapping from `Domain` to [`Mapping::Codomain`], with differentials
 /// `Differential`.
 ///
-/// This is automatically implemented when the relevant [`Differentiable`] are implemented.
-pub trait DifferentiableMapping<Domain>
-: Mapping<Domain>
-  + Differentiable<Domain, Derivative=Self::DerivativeDomain>
-  + for<'a> Differentiable<&'a Domain, Derivative=Self::DerivativeDomain> {
-    type DerivativeDomain;
-    type Differential : Mapping<Domain, Codomain=Self::DerivativeDomain>;
-    type DifferentialRef<'b> : Mapping<Domain, Codomain=Self::DerivativeDomain> where Self : 'b;
+/// 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;
+
+    /// Calculate differential at `x`
+    fn differential<I : Instance<Domain>>(&self, x : I) -> Self::DerivativeDomain;
 
     /// Form the differential mapping of `self`.
-    fn diff(self) -> Self::Differential;
+    fn diff(self) -> Self::Differential<'static>;
+
     /// Form the differential mapping of `self`.
-    fn diff_ref(&self) -> Self::DifferentialRef<'_>;
+    fn diff_ref(&self) -> Self::Differential<'_>;
 }
 
+/// 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>> {}
 
-impl<Domain, Derivative, T> DifferentiableMapping<Domain> for T
-where T : Mapping<Domain>
-          + Differentiable<Domain, Derivative=Derivative>
-          + for<'a> Differentiable<&'a Domain,Derivative=Derivative> {
-    type DerivativeDomain = Derivative;
-    type Differential = Differential<Domain, Self>;
-    type DifferentialRef<'b> = Differential<Domain, &'b Self> where Self : 'b;
+impl<F : Float, T, const N : usize> DifferentiableRealMapping<F, N> for T
+where T : DifferentiableMapping<Loc<F, N>, Codomain = F, DerivativeDomain = Loc<F, N>> {}
+
+/// Helper trait for implementing [`DifferentiableMapping`]
+pub trait DifferentiableImpl<X : Space> : Sized {
+    type Derivative : Space;
+
+    /// Compute the differential of `self` at `x`, consuming the input.
+    fn differential_impl<I : Instance<X>>(&self, x : I) -> Self::Derivative;
+}
+
+impl<T, Domain> DifferentiableMapping<Domain> for T
+where
+    Domain : Space,
+    T : Clone + Mapping<Domain> + DifferentiableImpl<Domain>
+{
+    type DerivativeDomain = T::Derivative;
+    type Differential<'b> = Differential<'b, Domain, Self> where Self : 'b;
     
-    /// Form the differential mapping of `self`.
-    fn diff(self) -> Self::Differential {
-        Differential{ g : self, _space : PhantomData }
+    #[inline]
+    fn differential<I : Instance<Domain>>(&self, x : I) -> Self::DerivativeDomain {
+        self.differential_impl(x)
     }
 
-    /// Form the differential mapping of `self`.
-    fn diff_ref(&self) -> Self::DifferentialRef<'_> {
-        Differential{ g : self, _space : 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 }
     }
 }
 
 /// A sum of [`Mapping`]s.
 #[derive(Serialize, Debug, Clone)]
-pub struct Sum<Domain, M : Mapping<Domain>> {
+pub struct Sum<Domain, M> {
     components : Vec<M>,
     _domain : PhantomData<Domain>,
 }
 
-impl<Domain, M : Mapping<Domain>> Sum<Domain, M> {
+impl<Domain, M> Sum<Domain, M> {
     /// Construct from an iterator.
     pub fn new<I : Iterator<Item = M>>(iter : I) -> Self {
         Sum { components : iter.collect(), _domain : PhantomData }
@@ -140,123 +109,107 @@
 }
 
 
-impl<Domain, M> Apply<Domain> for Sum<Domain, M>
-where M : Mapping<Domain>,
-      M::Codomain : std::iter::Sum {
-    type Output = M::Codomain;
+impl<Domain, M> Mapping<Domain> for Sum<Domain, M>
+where
+    Domain : Space + Clone,
+    M : Mapping<Domain>,
+    M::Codomain : std::iter::Sum + Clone
+{
+    type Codomain = M::Codomain;
 
-    fn apply(&self, x : Domain) -> Self::Output {
-        self.components.iter().map(|c| c.apply(&x)).sum()
+    fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain {
+        let xr = x.ref_instance();
+        self.components.iter().map(|c| c.apply(xr)).sum()
     }
 }
 
-impl<'a, Domain, M> Apply<&'a Domain> for Sum<Domain, M>
-where M : Mapping<Domain>,
-      M::Codomain : std::iter::Sum {
-    type Output = M::Codomain;
-
-    fn apply(&self, x : &'a Domain) -> Self::Output {
-        self.components.iter().map(|c| c.apply(x)).sum()
-    }
-}
-
-impl<Domain, M> Differentiable<Domain> for Sum<Domain, M>
-where M : DifferentiableMapping<Domain>,
-      M :: Codomain : std::iter::Sum,
-      M :: DerivativeDomain : std::iter::Sum,
-      Domain : Copy {
-
+impl<Domain, M> DifferentiableImpl<Domain> for Sum<Domain, M>
+where
+    Domain : Space + Clone,
+    M : DifferentiableMapping<Domain>,
+    M :: DerivativeDomain : std::iter::Sum
+{
     type Derivative = M::DerivativeDomain;
 
-    fn differential(&self, x : Domain) -> Self::Derivative {
-        self.components.iter().map(|c| c.differential(x)).sum()
+    fn differential_impl<I : Instance<Domain>>(&self, x : I) -> Self::Derivative {
+        let xr = x.ref_instance();
+        self.components.iter().map(|c| c.differential(xr)).sum()
     }
 }
 
 /// Container for the differential [`Mapping`] of a [`Differentiable`] mapping.
-pub struct Differential<X, G : DifferentiableMapping<X>> {
-    g : G,
+pub struct Differential<'a, X, G : Clone> {
+    g : Cow<'a, G>,
     _space : PhantomData<X>
 }
 
-impl<X, G : DifferentiableMapping<X>> Differential<X, G> {
+impl<'a, X, G : Clone> Differential<'a, X, G> {
     pub fn base_fn(&self) -> &G {
         &self.g
     }
 }
 
-impl<X, G : DifferentiableMapping<X>> Apply<X> for Differential<X, G> {
-    type Output = G::DerivativeDomain;
+impl<'a, X, G> Mapping<X> for Differential<'a, X, G>
+where
+    X : Space,
+    G : Clone + DifferentiableMapping<X>
+{
+    type Codomain = G::DerivativeDomain;
 
     #[inline]
-    fn apply(&self, x : X) -> Self::Output {
-        self.g.differential(x)
+    fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
+        (*self.g).differential(x)
     }
 }
 
-impl<'a, X, G : DifferentiableMapping<X>> Apply<&'a X> for Differential<X, G> {
-    type Output = G::DerivativeDomain;
-
-    #[inline]
-    fn apply(&self, x : &'a X) -> Self::Output {
-        self.g.differential(x)
-    }
-}
-
-
 /// Container for flattening [`Loc`]`<F, 1>` codomain of a [`Mapping`] to `F`.
-pub struct FlattenedCodomain<X, F, G : Mapping<X, Codomain=Loc<F, 1>>> {
+pub struct FlattenedCodomain<X, F, G> {
     g : G,
     _phantoms : PhantomData<(X, F)>
 }
 
-impl<X, F, G : Mapping<X, Codomain=Loc<F, 1>>> Apply<X> for FlattenedCodomain<X, F, G> {
-    type Output = F;
+impl<F : Space, X, G> Mapping<X> for FlattenedCodomain<X, F, G>
+where
+    X : Space,
+    G: Mapping<X, Codomain=Loc<F, 1>>
+{
+    type Codomain = F;
 
     #[inline]
-    fn apply(&self, x : X) -> Self::Output {
+    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, F> : Mapping<X, Codomain=Loc<F, 1>> + Sized {
+pub trait FlattenCodomain<X : Space, F> : Mapping<X, Codomain=Loc<F, 1>> + Sized {
     /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
     fn flatten_codomain(self) -> FlattenedCodomain<X, F, Self> {
         FlattenedCodomain{ g : self, _phantoms : PhantomData }
     }
 }
 
-impl<X, F, G : Sized + Mapping<X, Codomain=Loc<F, 1>>> FlattenCodomain<X, F> for G {}
-
+impl<X : Space, F, G : Sized + Mapping<X, Codomain=Loc<F, 1>>> FlattenCodomain<X, F> for G {}
 
 /// Container for dimensional slicing [`Loc`]`<F, N>` codomain of a [`Mapping`] to `F`.
-pub struct SlicedCodomain<X, F, G : Mapping<X, Codomain=Loc<F, N>>, const N : usize> {
-    g : G,
+pub struct SlicedCodomain<'a, X, F, G : Clone, const N : usize> {
+    g : Cow<'a, G>,
     slice : usize,
     _phantoms : PhantomData<(X, F)>
 }
 
-impl<X, F : Copy, G : Mapping<X, Codomain=Loc<F, N>>, const N : usize> Apply<X>
-for SlicedCodomain<X, F, G, N> {
-    type Output = F;
+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,
+{
+    type Codomain = F;
 
     #[inline]
-    fn apply(&self, x : X) -> Self::Output {
-        let tmp : [F; N] = self.g.apply(x).into();
-        // Safety: `slice_codomain` below checks the range.
-        unsafe { *tmp.get_unchecked(self.slice) }
-    }
-}
-
-impl<'a, X, F : Copy, G : Mapping<X, Codomain=Loc<F, N>>, const N : usize> Apply<&'a X>
-for SlicedCodomain<X, F, G, N> {
-    type Output = F;
-
-    #[inline]
-    fn apply(&self, x : &'a X) -> Self::Output {
-        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) }
     }
@@ -264,21 +217,22 @@
 
 /// 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, F : Copy, const N : usize> : Mapping<X, Codomain=Loc<F, N>> + Sized {
+pub trait SliceCodomain<X : Space, F : Copy, const N : usize>
+    : Mapping<X, Codomain=Loc<F, N>> + Clone + Sized
+{
     /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
-    fn slice_codomain(self, slice : usize) -> SlicedCodomain<X, F, Self, N> {
+    fn slice_codomain(self, slice : usize) -> SlicedCodomain<'static, X, F, Self, N> {
         assert!(slice < N);
-        SlicedCodomain{ g : self, slice, _phantoms : PhantomData }
+        SlicedCodomain{ g : Cow::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 : self, slice, _phantoms : PhantomData }
+        SlicedCodomain{ g : Cow::Borrowed(self), slice, _phantoms : PhantomData }
     }
 }
 
-impl<X, F : Copy, G : Sized + Mapping<X, Codomain=Loc<F, N>>, const N : usize>
+impl<X : Space, F : Copy, G : Sized + Mapping<X, Codomain=Loc<F, N>> + Clone, const N : usize>
 SliceCodomain<X, F, N>
 for G {}
-

mercurial