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