src/mapping.rs

changeset 90
b3c35d16affe
parent 75
e9f4550cfa18
equal deleted inserted replaced
25:d14c877e14b7 90:b3c35d16affe
1 /*! 1 /*!
2 Traits for mathematical functions. 2 Traits for mathematical functions.
3 */ 3 */
4 4
5 use std::marker::PhantomData; 5 use std::marker::PhantomData;
6 use crate::types::{Float}; 6 use std::borrow::Cow;
7 use serde::Serialize; 7 use crate::types::{Num, Float, ClosedMul};
8 use crate::loc::Loc; 8 use crate::loc::Loc;
9 9 pub use crate::instance::{Instance, Decomposition, BasicDecomposition, Space};
10 /// Trait for application of `Self` as a mathematical function or operator on `X`. 10 use crate::norms::{Norm, NormExponent};
11 pub trait Apply<X> { 11 use crate::operator_arithmetic::{Weighted, Constant};
12 type Output; 12
13 /// A mapping from `Domain` to `Self::Codomain`.
14 pub trait Mapping<Domain : Space> {
15 type Codomain : Space;
13 16
14 /// Compute the value of `self` at `x`. 17 /// Compute the value of `self` at `x`.
15 fn apply(&self, x : X) -> Self::Output; 18 fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain;
16 } 19
17 20 #[inline]
18 /// This blanket implementation is a workaround helper to Rust trait system limitations. 21 /// Form the composition `self ∘ other`
19 /// 22 fn compose<X : Space, T : Mapping<X, Codomain=Domain>>(self, other : T)
20 /// It is introduced because the trait system does not allow blanket implementations of both 23 -> Composition<Self, T>
21 /// [`Apply<X>`] and [`Apply<&'a X>`]. With this, the latter is implemented automatically for 24 where
22 /// the reference, which can be sufficient to apply the operation in another blanket implementation. 25 Self : Sized
23 impl<'a, T, X> Apply<X> for &'a T where T : Apply<X> { 26 {
24 type Output = <T as Apply<X>>::Output; 27 Composition{ outer : self, inner : other, intermediate_norm_exponent : () }
25 28 }
26 #[inline] 29
27 fn apply(&self, x : X) -> Self::Output { 30
28 (*self).apply(x) 31 #[inline]
29 } 32 /// Form the composition `self ∘ other`, assigning a norm to the inermediate space
30 } 33 fn compose_with_norm<F, X, T, E>(
31 34 self, other : T, norm : E
32 /// A mapping from `Domain` to `Codomain`. 35 ) -> Composition<Self, T, E>
33 /// 36 where
34 /// This is automatically implemented when the relevant [`Apply`] are implemented. 37 Self : Sized,
35 pub trait Mapping<Domain> : Apply<Domain, Output=Self::Codomain> 38 X : Space,
36 + for<'a> Apply<&'a Domain, Output=Self::Codomain> { 39 T : Mapping<X, Codomain=Domain>,
37 type Codomain; 40 E : NormExponent,
38 } 41 Domain : Norm<F, E>,
39 42 F : Num
40 impl<Domain, Codomain, T> Mapping<Domain> for T 43 {
41 where T : Apply<Domain, Output=Codomain> + for<'a> Apply<&'a Domain, Output=Codomain> { 44 Composition{ outer : self, inner : other, intermediate_norm_exponent : norm }
42 type Codomain = Codomain; 45 }
43 } 46
44 47 /// Multiply `self` by the scalar `a`.
45 48 #[inline]
46 /// A helper trait alias for referring to [`Mapping`]s from [`Loc<F, N>`] to `F` a [`Float`]. 49 fn weigh<C>(self, a : C) -> Weighted<Self, C>
47 pub trait RealMapping<F : Float, const N : usize> : Mapping<Loc<F, N>, Codomain = F> {} 50 where
51 Self : Sized,
52 C : Constant,
53 Self::Codomain : ClosedMul<C::Type>,
54 {
55 Weighted { weight : a, base_fn : self }
56 }
57 }
58
59 /// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc<F, N>`] to `F`.
60 pub trait RealMapping<F : Float, const N : usize>
61 : Mapping<Loc<F, N>, Codomain = F> {}
48 62
49 impl<F : Float, T, const N : usize> RealMapping<F, N> for T 63 impl<F : Float, T, const N : usize> RealMapping<F, N> for T
50 where T : Mapping<Loc<F, N>, Codomain = F> {} 64 where T : Mapping<Loc<F, N>, Codomain = F> {}
51 65
52 66 /// A helper trait alias for referring to [`Mapping`]s from [`Loc<F, N>`] to [`Loc<F, M>`].
53 /// Trait for calculation the differential of `Self` as a mathematical function on `X`. 67 pub trait RealVectorField<F : Float, const N : usize, const M : usize>
54 pub trait Differentiate<X> { 68 : Mapping<Loc<F, N>, Codomain = Loc<F, M>> {}
55 type Output; 69
56 70 impl<F : Float, T, const N : usize, const M : usize> RealVectorField<F, N, M> for T
57 /// Compute the differential of `self` at `x`. 71 where T : Mapping<Loc<F, N>, Codomain = Loc<F, M>> {}
58 fn differential(&self, x : X) -> Self::Output;
59 }
60
61 72
62 /// A differentiable mapping from `Domain` to [`Mapping::Codomain`], with differentials 73 /// A differentiable mapping from `Domain` to [`Mapping::Codomain`], with differentials
63 /// `Differential`. 74 /// `Differential`.
64 /// 75 ///
65 /// This is automatically implemented when the relevant [`Differentiate`] are implemented. 76 /// This is automatically implemented when [`DifferentiableImpl`] is.
66 pub trait DifferentiableMapping<Domain> 77 pub trait DifferentiableMapping<Domain : Space> : Mapping<Domain> {
67 : Mapping<Domain> 78 type DerivativeDomain : Space;
68 + Differentiate<Domain, Output=Self::Differential> 79 type Differential<'b> : Mapping<Domain, Codomain=Self::DerivativeDomain> where Self : 'b;
69 + for<'a> Differentiate<&'a Domain, Output=Self::Differential>{ 80
70 type Differential; 81 /// Calculate differential at `x`
71 } 82 fn differential<I : Instance<Domain>>(&self, x : I) -> Self::DerivativeDomain;
72 83
73 84 /// Form the differential mapping of `self`.
74 impl<Domain, Differential, T> DifferentiableMapping<Domain> for T 85 fn diff(self) -> Self::Differential<'static>;
75 where T : Mapping<Domain> 86
76 + Differentiate<Domain, Output=Differential> 87 /// Form the differential mapping of `self`.
77 + for<'a> Differentiate<&'a Domain, Output=Differential> { 88 fn diff_ref(&self) -> Self::Differential<'_>;
78 type Differential = Differential; 89 }
79 } 90
80 91 /// Automatically implemented shorthand for referring to differentiable [`Mapping`]s from
81 /// A sum of [`Mapping`]s. 92 /// [`Loc<F, N>`] to `F`.
82 #[derive(Serialize, Debug, Clone)] 93 pub trait DifferentiableRealMapping<F : Float, const N : usize>
83 pub struct Sum<Domain, M : Mapping<Domain>> { 94 : DifferentiableMapping<Loc<F, N>, Codomain = F, DerivativeDomain = Loc<F, N>> {}
84 components : Vec<M>, 95
85 _domain : PhantomData<Domain>, 96 impl<F : Float, T, const N : usize> DifferentiableRealMapping<F, N> for T
86 } 97 where T : DifferentiableMapping<Loc<F, N>, Codomain = F, DerivativeDomain = Loc<F, N>> {}
87 98
88 impl<Domain, M : Mapping<Domain>> Sum<Domain, M> { 99 /// Helper trait for implementing [`DifferentiableMapping`]
89 /// Construct from an iterator. 100 pub trait DifferentiableImpl<X : Space> : Sized {
90 pub fn new<I : Iterator<Item = M>>(iter : I) -> Self { 101 type Derivative : Space;
91 Sum { components : iter.collect(), _domain : PhantomData } 102
92 } 103 /// Compute the differential of `self` at `x`, consuming the input.
93 } 104 fn differential_impl<I : Instance<X>>(&self, x : I) -> Self::Derivative;
94 105 }
95 106
96 impl<Domain : Copy, M> Apply<Domain> for Sum<Domain, M> 107 impl<T, Domain> DifferentiableMapping<Domain> for T
97 where M : Mapping<Domain>, 108 where
98 M::Codomain : std::iter::Sum { 109 Domain : Space,
99 type Output = M::Codomain; 110 T : Clone + Mapping<Domain> + DifferentiableImpl<Domain>
100 111 {
101 fn apply(&self, x : Domain) -> Self::Output { 112 type DerivativeDomain = T::Derivative;
102 self.components.iter().map(|c| c.apply(x)).sum() 113 type Differential<'b> = Differential<'b, Domain, Self> where Self : 'b;
103 } 114
104 } 115 #[inline]
105 116 fn differential<I : Instance<Domain>>(&self, x : I) -> Self::DerivativeDomain {
106 impl<Domain, M> Differentiate<Domain> for Sum<Domain, M> 117 self.differential_impl(x)
107 where M : DifferentiableMapping<Domain>, 118 }
108 M :: Codomain : std::iter::Sum, 119
109 M :: Differential : std::iter::Sum, 120 fn diff(self) -> Differential<'static, Domain, Self> {
110 Domain : Copy { 121 Differential{ g : Cow::Owned(self), _space : PhantomData }
111 122 }
112 type Output = M::Differential; 123
113 124 fn diff_ref(&self) -> Differential<'_, Domain, Self> {
114 fn differential(&self, x : Domain) -> Self::Output { 125 Differential{ g : Cow::Borrowed(self), _space : PhantomData }
115 self.components.iter().map(|c| c.differential(x)).sum() 126 }
116 } 127 }
117 } 128
129
130 /// Container for the differential [`Mapping`] of a [`DifferentiableMapping`].
131 pub struct Differential<'a, X, G : Clone> {
132 g : Cow<'a, G>,
133 _space : PhantomData<X>
134 }
135
136 impl<'a, X, G : Clone> Differential<'a, X, G> {
137 pub fn base_fn(&self) -> &G {
138 &self.g
139 }
140 }
141
142 impl<'a, X, G> Mapping<X> for Differential<'a, X, G>
143 where
144 X : Space,
145 G : Clone + DifferentiableMapping<X>
146 {
147 type Codomain = G::DerivativeDomain;
148
149 #[inline]
150 fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
151 (*self.g).differential(x)
152 }
153 }
154
155 /// Container for flattening [`Loc`]`<F, 1>` codomain of a [`Mapping`] to `F`.
156 pub struct FlattenedCodomain<X, F, G> {
157 g : G,
158 _phantoms : PhantomData<(X, F)>
159 }
160
161 impl<F : Space, X, G> Mapping<X> for FlattenedCodomain<X, F, G>
162 where
163 X : Space,
164 G: Mapping<X, Codomain=Loc<F, 1>>
165 {
166 type Codomain = F;
167
168 #[inline]
169 fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
170 self.g.apply(x).flatten1d()
171 }
172 }
173
174 /// An auto-trait for constructing a [`FlattenCodomain`] structure for
175 /// flattening the codomain of a [`Mapping`] from [`Loc`]`<F, 1>` to `F`.
176 pub trait FlattenCodomain<X : Space, F> : Mapping<X, Codomain=Loc<F, 1>> + Sized {
177 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
178 fn flatten_codomain(self) -> FlattenedCodomain<X, F, Self> {
179 FlattenedCodomain{ g : self, _phantoms : PhantomData }
180 }
181 }
182
183 impl<X : Space, F, G : Sized + Mapping<X, Codomain=Loc<F, 1>>> FlattenCodomain<X, F> for G {}
184
185 /// Container for dimensional slicing [`Loc`]`<F, N>` codomain of a [`Mapping`] to `F`.
186 pub struct SlicedCodomain<'a, X, F, G : Clone, const N : usize> {
187 g : Cow<'a, G>,
188 slice : usize,
189 _phantoms : PhantomData<(X, F)>
190 }
191
192 impl<'a, X, F, G, const N : usize> Mapping<X> for SlicedCodomain<'a, X, F, G, N>
193 where
194 X : Space,
195 F : Copy + Space,
196 G : Mapping<X, Codomain=Loc<F, N>> + Clone,
197 {
198 type Codomain = F;
199
200 #[inline]
201 fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
202 let tmp : [F; N] = (*self.g).apply(x).into();
203 // Safety: `slice_codomain` below checks the range.
204 unsafe { *tmp.get_unchecked(self.slice) }
205 }
206 }
207
208 /// An auto-trait for constructing a [`FlattenCodomain`] structure for
209 /// flattening the codomain of a [`Mapping`] from [`Loc`]`<F, 1>` to `F`.
210 pub trait SliceCodomain<X : Space, F : Copy, const N : usize>
211 : Mapping<X, Codomain=Loc<F, N>> + Clone + Sized
212 {
213 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
214 fn slice_codomain(self, slice : usize) -> SlicedCodomain<'static, X, F, Self, N> {
215 assert!(slice < N);
216 SlicedCodomain{ g : Cow::Owned(self), slice, _phantoms : PhantomData }
217 }
218
219 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
220 fn slice_codomain_ref(&self, slice : usize) -> SlicedCodomain<'_, X, F, Self, N> {
221 assert!(slice < N);
222 SlicedCodomain{ g : Cow::Borrowed(self), slice, _phantoms : PhantomData }
223 }
224 }
225
226 impl<X : Space, F : Copy, G : Sized + Mapping<X, Codomain=Loc<F, N>> + Clone, const N : usize>
227 SliceCodomain<X, F, N>
228 for G {}
229
230
231 /// The composition S ∘ T. `E` is for storing a `NormExponent` for the intermediate space.
232 pub struct Composition<S, T, E = ()> {
233 pub outer : S,
234 pub inner : T,
235 pub intermediate_norm_exponent : E
236 }
237
238 impl<S, T, X, E> Mapping<X> for Composition<S, T, E>
239 where
240 X : Space,
241 T : Mapping<X>,
242 S : Mapping<T::Codomain>
243 {
244 type Codomain = S::Codomain;
245
246 #[inline]
247 fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain {
248 self.outer.apply(self.inner.apply(x))
249 }
250 }

mercurial