src/mapping.rs

changeset 198
3868555d135c
parent 194
a5ee4bfb0b87
equal deleted inserted replaced
94:1f19c6bbf07b 198:3868555d135c
1 /*! 1 /*!
2 Traits for mathematical functions. 2 Traits for mathematical functions.
3 */ 3 */
4 4
5 use crate::error::DynResult;
6 use crate::instance::MyCow;
7 pub use crate::instance::{BasicDecomposition, ClosedSpace, Decomposition, Instance, Space};
8 use crate::loc::Loc;
9 use crate::norms::{Norm, NormExponent};
10 use crate::operator_arithmetic::{Constant, Weighted};
11 use crate::types::{ClosedMul, Float, Num};
5 use std::marker::PhantomData; 12 use std::marker::PhantomData;
6 use std::borrow::Cow; 13 use std::ops::Mul;
7 use crate::types::{Num, Float, ClosedMul};
8 use crate::loc::Loc;
9 pub use crate::instance::{Instance, Decomposition, BasicDecomposition, Space};
10 use crate::norms::{Norm, NormExponent};
11 use crate::operator_arithmetic::{Weighted, Constant};
12 14
13 /// A mapping from `Domain` to `Self::Codomain`. 15 /// A mapping from `Domain` to `Self::Codomain`.
14 pub trait Mapping<Domain : Space> { 16 pub trait Mapping<Domain: Space> {
15 type Codomain : Space; 17 type Codomain: ClosedSpace;
16 18
17 /// Compute the value of `self` at `x`. 19 /// Compute the value of `self` at `x`.
18 fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain; 20 fn apply<I: Instance<Domain>>(&self, x: I) -> Self::Codomain;
19 21
20 #[inline] 22 #[inline]
21 /// Form the composition `self ∘ other` 23 /// Form the composition `self ∘ other`
22 fn compose<X : Space, T : Mapping<X, Codomain=Domain>>(self, other : T) 24 fn compose<X: Space, T: Mapping<X, Codomain = Domain>>(self, other: T) -> Composition<Self, T>
23 -> Composition<Self, T> 25 where
24 where 26 Self: Sized,
25 Self : Sized
26 { 27 {
27 Composition{ outer : self, inner : other, intermediate_norm_exponent : () } 28 Composition { outer: self, inner: other, intermediate_norm_exponent: () }
28 } 29 }
29
30 30
31 #[inline] 31 #[inline]
32 /// Form the composition `self ∘ other`, assigning a norm to the inermediate space 32 /// Form the composition `self ∘ other`, assigning a norm to the inermediate space
33 fn compose_with_norm<F, X, T, E>( 33 fn compose_with_norm<F, X, T, E>(self, other: T, norm: E) -> Composition<Self, T, E>
34 self, other : T, norm : E 34 where
35 ) -> Composition<Self, T, E> 35 Self: Sized,
36 where 36 X: Space,
37 Self : Sized, 37 T: Mapping<X, Codomain = Domain>,
38 X : Space, 38 E: NormExponent,
39 T : Mapping<X, Codomain=Domain>, 39 Domain: Norm<E, F>,
40 E : NormExponent, 40 F: Num,
41 Domain : Norm<F, E>,
42 F : Num
43 { 41 {
44 Composition{ outer : self, inner : other, intermediate_norm_exponent : norm } 42 Composition { outer: self, inner: other, intermediate_norm_exponent: norm }
45 } 43 }
46 44
47 /// Multiply `self` by the scalar `a`. 45 /// Multiply `self` by the scalar `a`.
48 #[inline] 46 #[inline]
49 fn weigh<C>(self, a : C) -> Weighted<Self, C> 47 fn weigh<C>(self, a: C) -> Weighted<Self, C>
50 where 48 where
51 Self : Sized, 49 Self: Sized,
52 C : Constant, 50 C: Constant,
53 Self::Codomain : ClosedMul<C::Type>, 51 Self::Codomain: ClosedMul<C::Type>,
54 { 52 {
55 Weighted { weight : a, base_fn : self } 53 Weighted { weight: a, base_fn: self }
56 } 54 }
57 } 55 }
58 56
59 /// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc<F, N>`] to `F`. 57 /// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc<N, F>`] to `F`.
60 pub trait RealMapping<F : Float, const N : usize> 58 pub trait RealMapping<const N: usize, F: Float = f64>: Mapping<Loc<N, F>, Codomain = F> {}
61 : Mapping<Loc<F, N>, Codomain = F> {} 59
62 60 impl<F: Float, T, const N: usize> RealMapping<N, F> for T where T: Mapping<Loc<N, F>, Codomain = F> {}
63 impl<F : Float, T, const N : usize> RealMapping<F, N> for T 61
64 where T : Mapping<Loc<F, N>, Codomain = F> {} 62 /// A helper trait alias for referring to [`Mapping`]s from [`Loc<N, F>`] to [`Loc<M, F>`].
65 63 pub trait RealVectorField<const N: usize, const M: usize, F: Float = f64>:
66 /// A helper trait alias for referring to [`Mapping`]s from [`Loc<F, N>`] to [`Loc<F, M>`]. 64 Mapping<Loc<N, F>, Codomain = Loc<M, F>>
67 pub trait RealVectorField<F : Float, const N : usize, const M : usize> 65 {
68 : Mapping<Loc<F, N>, Codomain = Loc<F, M>> {} 66 }
69 67
70 impl<F : Float, T, const N : usize, const M : usize> RealVectorField<F, N, M> for T 68 impl<F: Float, T, const N: usize, const M: usize> RealVectorField<N, M, F> for T where
71 where T : Mapping<Loc<F, N>, Codomain = Loc<F, M>> {} 69 T: Mapping<Loc<N, F>, Codomain = Loc<M, F>>
70 {
71 }
72 72
73 /// A differentiable mapping from `Domain` to [`Mapping::Codomain`], with differentials 73 /// A differentiable mapping from `Domain` to [`Mapping::Codomain`], with differentials
74 /// `Differential`. 74 /// `Differential`.
75 /// 75 ///
76 /// This is automatically implemented when [`DifferentiableImpl`] is. 76 /// This is automatically implemented when [`DifferentiableImpl`] is.
77 pub trait DifferentiableMapping<Domain : Space> : Mapping<Domain> { 77 pub trait DifferentiableMapping<Domain: Space>: Mapping<Domain> {
78 type DerivativeDomain : Space; 78 type DerivativeDomain: ClosedSpace;
79 type Differential<'b> : Mapping<Domain, Codomain=Self::DerivativeDomain> where Self : 'b; 79 type Differential<'b>: Mapping<Domain, Codomain = Self::DerivativeDomain>
80 where
81 Self: 'b;
80 82
81 /// Calculate differential at `x` 83 /// Calculate differential at `x`
82 fn differential<I : Instance<Domain>>(&self, x : I) -> Self::DerivativeDomain; 84 fn differential<I: Instance<Domain>>(&self, x: I) -> Self::DerivativeDomain;
85
86 /// Calculate differential and value at `x`
87 fn apply_and_differential<I: Instance<Domain>>(
88 &self,
89 x: I,
90 ) -> (Self::Codomain, Self::DerivativeDomain) {
91 x.eval_ref(|xo| (self.apply(xo), self.differential(xo)))
92 }
83 93
84 /// Form the differential mapping of `self`. 94 /// Form the differential mapping of `self`.
85 fn diff(self) -> Self::Differential<'static>; 95 fn diff(self) -> Self::Differential<'static>;
86 96
87 /// Form the differential mapping of `self`. 97 /// Form the differential mapping of `self`.
88 fn diff_ref(&self) -> Self::Differential<'_>; 98 fn diff_ref(&self) -> Self::Differential<'_>;
89 } 99 }
90 100
91 /// Automatically implemented shorthand for referring to differentiable [`Mapping`]s from 101 /// Automatically implemented shorthand for referring to differentiable [`Mapping`]s from
92 /// [`Loc<F, N>`] to `F`. 102 /// [`Loc<N, F>`] to `F`.
93 pub trait DifferentiableRealMapping<F : Float, const N : usize> 103 pub trait DifferentiableRealMapping<const N: usize, F: Float>:
94 : DifferentiableMapping<Loc<F, N>, Codomain = F, DerivativeDomain = Loc<F, N>> {} 104 DifferentiableMapping<Loc<N, F>, Codomain = F, DerivativeDomain = Loc<N, F>>
95 105 {
96 impl<F : Float, T, const N : usize> DifferentiableRealMapping<F, N> for T 106 }
97 where T : DifferentiableMapping<Loc<F, N>, Codomain = F, DerivativeDomain = Loc<F, N>> {} 107
108 impl<F: Float, T, const N: usize> DifferentiableRealMapping<N, F> for T where
109 T: DifferentiableMapping<Loc<N, F>, Codomain = F, DerivativeDomain = Loc<N, F>>
110 {
111 }
98 112
99 /// Helper trait for implementing [`DifferentiableMapping`] 113 /// Helper trait for implementing [`DifferentiableMapping`]
100 pub trait DifferentiableImpl<X : Space> : Sized { 114 pub trait DifferentiableImpl<X: Space>: Sized {
101 type Derivative : Space; 115 type Derivative: ClosedSpace;
102 116
103 /// Compute the differential of `self` at `x`, consuming the input. 117 /// Compute the differential of `self` at `x`, consuming the input.
104 fn differential_impl<I : Instance<X>>(&self, x : I) -> Self::Derivative; 118 fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative;
119
120 fn apply_and_differential_impl<I: Instance<X>>(
121 &self,
122 x: I,
123 ) -> (Self::Codomain, Self::Derivative)
124 where
125 Self: Mapping<X>,
126 {
127 x.eval_ref(|xo| (self.apply(xo), self.differential_impl(xo)))
128 }
105 } 129 }
106 130
107 impl<T, Domain> DifferentiableMapping<Domain> for T 131 impl<T, Domain> DifferentiableMapping<Domain> for T
108 where 132 where
109 Domain : Space, 133 Domain: Space,
110 T : Clone + Mapping<Domain> + DifferentiableImpl<Domain> 134 T: Mapping<Domain> + DifferentiableImpl<Domain>,
111 { 135 {
112 type DerivativeDomain = T::Derivative; 136 type DerivativeDomain = T::Derivative;
113 type Differential<'b> = Differential<'b, Domain, Self> where Self : 'b; 137 type Differential<'b>
114 138 = Differential<'b, Domain, Self>
115 #[inline] 139 where
116 fn differential<I : Instance<Domain>>(&self, x : I) -> Self::DerivativeDomain { 140 Self: 'b;
141
142 #[inline]
143 fn differential<I: Instance<Domain>>(&self, x: I) -> Self::DerivativeDomain {
117 self.differential_impl(x) 144 self.differential_impl(x)
118 } 145 }
119 146
147 #[inline]
148 fn apply_and_differential<I: Instance<Domain>>(
149 &self,
150 x: I,
151 ) -> (T::Codomain, Self::DerivativeDomain) {
152 self.apply_and_differential_impl(x)
153 }
154
120 fn diff(self) -> Differential<'static, Domain, Self> { 155 fn diff(self) -> Differential<'static, Domain, Self> {
121 Differential{ g : Cow::Owned(self), _space : PhantomData } 156 Differential { g: MyCow::Owned(self), _space: PhantomData }
122 } 157 }
123 158
124 fn diff_ref(&self) -> Differential<'_, Domain, Self> { 159 fn diff_ref(&self) -> Differential<'_, Domain, Self> {
125 Differential{ g : Cow::Borrowed(self), _space : PhantomData } 160 Differential { g: MyCow::Borrowed(self), _space: PhantomData }
126 } 161 }
127 } 162 }
128
129 163
130 /// Container for the differential [`Mapping`] of a [`DifferentiableMapping`]. 164 /// Container for the differential [`Mapping`] of a [`DifferentiableMapping`].
131 pub struct Differential<'a, X, G : Clone> { 165 pub struct Differential<'a, X, G> {
132 g : Cow<'a, G>, 166 g: MyCow<'a, G>,
133 _space : PhantomData<X> 167 _space: PhantomData<X>,
134 } 168 }
135 169
136 impl<'a, X, G : Clone> Differential<'a, X, G> { 170 impl<'a, X, G> Differential<'a, X, G> {
137 pub fn base_fn(&self) -> &G { 171 pub fn base_fn(&self) -> &G {
138 &self.g 172 &self.g
139 } 173 }
140 } 174 }
141 175
142 impl<'a, X, G> Mapping<X> for Differential<'a, X, G> 176 impl<'a, X, G> Mapping<X> for Differential<'a, X, G>
143 where 177 where
144 X : Space, 178 X: Space,
145 G : Clone + DifferentiableMapping<X> 179 G: DifferentiableMapping<X>,
146 { 180 {
147 type Codomain = G::DerivativeDomain; 181 type Codomain = G::DerivativeDomain;
148 182
149 #[inline] 183 #[inline]
150 fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain { 184 fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
151 (*self.g).differential(x) 185 (*self.g).differential(x)
152 } 186 }
153 } 187 }
154 188
155 /// Container for flattening [`Loc`]`<F, 1>` codomain of a [`Mapping`] to `F`. 189 /// Container for flattening [`Loc`]`<F, 1>` codomain of a [`Mapping`] to `F`.
156 pub struct FlattenedCodomain<X, F, G> { 190 pub struct FlattenedCodomain<X, F, G> {
157 g : G, 191 g: G,
158 _phantoms : PhantomData<(X, F)> 192 _phantoms: PhantomData<(X, F)>,
159 } 193 }
160 194
161 impl<F : Space, X, G> Mapping<X> for FlattenedCodomain<X, F, G> 195 impl<F, X, G> Mapping<X> for FlattenedCodomain<X, F, G>
162 where 196 where
163 X : Space, 197 F: ClosedSpace,
164 G: Mapping<X, Codomain=Loc<F, 1>> 198 X: Space,
199 G: Mapping<X, Codomain = Loc<1, F>>,
165 { 200 {
166 type Codomain = F; 201 type Codomain = F;
167 202
168 #[inline] 203 #[inline]
169 fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain { 204 fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
170 self.g.apply(x).flatten1d() 205 self.g.apply(x).flatten1d()
171 } 206 }
172 } 207 }
173 208
174 /// An auto-trait for constructing a [`FlattenCodomain`] structure for 209 /// An auto-trait for constructing a [`FlattenCodomain`] structure for
175 /// flattening the codomain of a [`Mapping`] from [`Loc`]`<F, 1>` to `F`. 210 /// 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 { 211 pub trait FlattenCodomain<X: Space, F>: Mapping<X, Codomain = Loc<1, F>> + Sized {
177 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`. 212 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
178 fn flatten_codomain(self) -> FlattenedCodomain<X, F, Self> { 213 fn flatten_codomain(self) -> FlattenedCodomain<X, F, Self> {
179 FlattenedCodomain{ g : self, _phantoms : PhantomData } 214 FlattenedCodomain { g: self, _phantoms: PhantomData }
180 } 215 }
181 } 216 }
182 217
183 impl<X : Space, F, G : Sized + Mapping<X, Codomain=Loc<F, 1>>> FlattenCodomain<X, F> for G {} 218 impl<X: Space, F, G: Sized + Mapping<X, Codomain = Loc<1, F>>> FlattenCodomain<X, F> for G {}
184 219
185 /// Container for dimensional slicing [`Loc`]`<F, N>` codomain of a [`Mapping`] to `F`. 220 /// Container for dimensional slicing [`Loc`]`<N, F>` codomain of a [`Mapping`] to `F`.
186 pub struct SlicedCodomain<'a, X, F, G : Clone, const N : usize> { 221 pub struct SlicedCodomain<'a, X, F, G, const N: usize> {
187 g : Cow<'a, G>, 222 g: MyCow<'a, G>,
188 slice : usize, 223 slice: usize,
189 _phantoms : PhantomData<(X, F)> 224 _phantoms: PhantomData<(X, F)>,
190 } 225 }
191 226
192 impl<'a, X, F, G, const N : usize> Mapping<X> for SlicedCodomain<'a, X, F, G, N> 227 impl<'a, X, F, G, const N: usize> Mapping<X> for SlicedCodomain<'a, X, F, G, N>
193 where 228 where
194 X : Space, 229 X: Space,
195 F : Copy + Space, 230 F: Copy + ClosedSpace,
196 G : Mapping<X, Codomain=Loc<F, N>> + Clone, 231 G: Mapping<X, Codomain = Loc<N, F>>,
197 { 232 {
198 type Codomain = F; 233 type Codomain = F;
199 234
200 #[inline] 235 #[inline]
201 fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain { 236 fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
202 let tmp : [F; N] = (*self.g).apply(x).into(); 237 let tmp: [F; N] = (*self.g).apply(x).into();
203 // Safety: `slice_codomain` below checks the range. 238 // Safety: `slice_codomain` below checks the range.
204 unsafe { *tmp.get_unchecked(self.slice) } 239 unsafe { *tmp.get_unchecked(self.slice) }
205 } 240 }
206 } 241 }
207 242
208 /// An auto-trait for constructing a [`FlattenCodomain`] structure for 243 /// An auto-trait for constructing a [`FlattenCodomain`] structure for
209 /// flattening the codomain of a [`Mapping`] from [`Loc`]`<F, 1>` to `F`. 244 /// flattening the codomain of a [`Mapping`] from [`Loc`]`<F, 1>` to `F`.
210 pub trait SliceCodomain<X : Space, F : Copy, const N : usize> 245 pub trait SliceCodomain<X: Space, const N: usize, F: Copy = f64>:
211 : Mapping<X, Codomain=Loc<F, N>> + Clone + Sized 246 Mapping<X, Codomain = Loc<N, F>> + Sized
212 { 247 {
213 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`. 248 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
214 fn slice_codomain(self, slice : usize) -> SlicedCodomain<'static, X, F, Self, N> { 249 fn slice_codomain(self, slice: usize) -> SlicedCodomain<'static, X, F, Self, N> {
215 assert!(slice < N); 250 assert!(slice < N);
216 SlicedCodomain{ g : Cow::Owned(self), slice, _phantoms : PhantomData } 251 SlicedCodomain { g: MyCow::Owned(self), slice, _phantoms: PhantomData }
217 } 252 }
218 253
219 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`. 254 /// Flatten the codomain from [`Loc`]`<F, 1>` to `F`.
220 fn slice_codomain_ref(&self, slice : usize) -> SlicedCodomain<'_, X, F, Self, N> { 255 fn slice_codomain_ref(&self, slice: usize) -> SlicedCodomain<'_, X, F, Self, N> {
221 assert!(slice < N); 256 assert!(slice < N);
222 SlicedCodomain{ g : Cow::Borrowed(self), slice, _phantoms : PhantomData } 257 SlicedCodomain { g: MyCow::Borrowed(self), slice, _phantoms: PhantomData }
223 } 258 }
224 } 259 }
225 260
226 impl<X : Space, F : Copy, G : Sized + Mapping<X, Codomain=Loc<F, N>> + Clone, const N : usize> 261 impl<X: Space, F: Copy, G: Sized + Mapping<X, Codomain = Loc<N, F>>, const N: usize>
227 SliceCodomain<X, F, N> 262 SliceCodomain<X, N, F> for G
228 for G {} 263 {
229 264 }
230 265
231 /// The composition S ∘ T. `E` is for storing a `NormExponent` for the intermediate space. 266 /// The composition S ∘ T. `E` is for storing a `NormExponent` for the intermediate space.
232 pub struct Composition<S, T, E = ()> { 267 pub struct Composition<S, T, E = ()> {
233 pub outer : S, 268 pub outer: S,
234 pub inner : T, 269 pub inner: T,
235 pub intermediate_norm_exponent : E 270 pub intermediate_norm_exponent: E,
236 } 271 }
237 272
238 impl<S, T, X, E> Mapping<X> for Composition<S, T, E> 273 impl<S, T, X, E> Mapping<X> for Composition<S, T, E>
239 where 274 where
240 X : Space, 275 X: Space,
241 T : Mapping<X>, 276 T: Mapping<X>,
242 S : Mapping<T::Codomain> 277 S: Mapping<T::Codomain>,
243 { 278 {
244 type Codomain = S::Codomain; 279 type Codomain = S::Codomain;
245 280
246 #[inline] 281 #[inline]
247 fn apply<I : Instance<X>>(&self, x : I) -> Self::Codomain { 282 fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain {
248 self.outer.apply(self.inner.apply(x)) 283 self.outer.apply(self.inner.apply(x))
249 } 284 }
250 } 285 }
286
287 /// Helper trait for implementing [`DifferentiableMapping`]
288 impl<S, T, X, E, Y> DifferentiableImpl<X> for Composition<S, T, E>
289 where
290 X: Space,
291 T: DifferentiableImpl<X> + Mapping<X>,
292 S: DifferentiableImpl<T::Codomain>,
293 E: Copy,
294 //Composition<S::Derivative, T::Derivative, E>: Space,
295 S::Derivative: Mul<T::Derivative, Output = Y>,
296 Y: ClosedSpace,
297 {
298 //type Derivative = Composition<S::Derivative, T::Derivative, E>;
299 type Derivative = Y;
300
301 /// Compute the differential of `self` at `x`, consuming the input.
302 fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative {
303 // Composition {
304 // outer: self
305 // .outer
306 // .differential_impl(self.inner.apply(x.ref_instance())),
307 // inner: self.inner.differential_impl(x),
308 // intermediate_norm_exponent: self.intermediate_norm_exponent,
309 // }
310
311 self.outer
312 .differential_impl(x.eval_ref(|r| self.inner.apply(r)))
313 * self.inner.differential_impl(x)
314 }
315 }
316
317 mod dataterm;
318 pub use dataterm::DataTerm;
319
320 /// Trait for indicating that `Self` is Lipschitz with respect to the (semi)norm `D`.
321 pub trait Lipschitz<M> {
322 /// The type of floats
323 type FloatType: Float;
324
325 /// Returns the Lipschitz factor of `self` with respect to the (semi)norm `D`.
326 fn lipschitz_factor(&self, seminorm: M) -> DynResult<Self::FloatType>;
327 }
328
329 /// Helper trait for implementing [`Lipschitz`] for mappings that implement [`DifferentiableImpl`].
330 pub trait LipschitzDifferentiableImpl<X: Space, M>: DifferentiableImpl<X> {
331 type FloatType: Float;
332
333 /// Compute the lipschitz factor of the derivative of `f`.
334 fn diff_lipschitz_factor(&self, seminorm: M) -> DynResult<Self::FloatType>;
335 }
336
337 impl<'b, M, X, A> Lipschitz<M> for Differential<'b, X, A>
338 where
339 X: Space,
340 A: LipschitzDifferentiableImpl<X, M>,
341 {
342 type FloatType = A::FloatType;
343
344 fn lipschitz_factor(&self, seminorm: M) -> DynResult<Self::FloatType> {
345 (*self.g).diff_lipschitz_factor(seminorm)
346 }
347 }

mercurial