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