src/mapping.rs

branch
dev
changeset 59
9226980e45a7
parent 53
08db78e3a654
child 61
05089fbc0310
equal deleted inserted replaced
58:1a38447a89fa 59:9226980e45a7
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

mercurial