1 |
1 |
2 /*! |
2 /*! |
3 Traits for representing the support of a [`Apply`], and analysing the mapping on a [`Cube`]. |
3 Traits for representing the support of a [`Mapping`], and analysing the mapping on a [`Cube`]. |
4 */ |
4 */ |
5 use serde::Serialize; |
5 use serde::Serialize; |
6 use std::ops::{MulAssign,DivAssign,Neg}; |
6 use std::ops::{MulAssign,DivAssign,Neg}; |
7 use crate::types::{Float, Num}; |
7 use crate::types::{Float, Num}; |
8 use crate::maputil::map2; |
8 use crate::maputil::map2; |
9 use crate::mapping::Apply; |
9 use crate::mapping::{ |
|
10 Instance, Mapping, DifferentiableImpl, DifferentiableMapping, Space |
|
11 }; |
10 use crate::sets::Cube; |
12 use crate::sets::Cube; |
11 use crate::loc::Loc; |
13 use crate::loc::Loc; |
12 use super::aggregator::Bounds; |
14 use super::aggregator::Bounds; |
13 use crate::norms::{Norm, L1, L2, Linfinity}; |
15 use crate::norms::{Norm, L1, L2, Linfinity}; |
14 |
16 pub use crate::operator_arithmetic::{Weighted, Constant}; |
15 /// A trait for encoding constant [`Float`] values |
17 |
16 pub trait Constant : Copy + Sync + Send + 'static + std::fmt::Debug + Into<Self::Type> { |
18 /// A trait for working with the supports of [`Mapping`]s. |
17 /// The type of the value |
|
18 type Type : Float; |
|
19 /// Returns the value of the constant |
|
20 fn value(&self) -> Self::Type; |
|
21 } |
|
22 |
|
23 impl<F : Float> Constant for F { |
|
24 type Type = F; |
|
25 #[inline] |
|
26 fn value(&self) -> F { *self } |
|
27 } |
|
28 |
|
29 |
|
30 /// A trait for working with the supports of [`Apply`]s. |
|
31 /// |
19 /// |
32 /// Apply is not a super-trait to allow more general use. |
20 /// `Mapping` is not a super-trait to allow more general use. |
33 pub trait Support<F : Num, const N : usize> : Sized + Sync + Send + 'static { |
21 pub trait Support<F : Num, const N : usize> : Sized + Sync + Send + 'static { |
34 /// Return a cube containing the support of the function represented by `self`. |
22 /// Return a cube containing the support of the function represented by `self`. |
35 /// |
23 /// |
36 /// The hint may be larger than the actual support, but must contain it. |
24 /// The hint may be larger than the actual support, but must contain it. |
37 fn support_hint(&self) -> Cube<F,N>; |
25 fn support_hint(&self) -> Cube<F,N>; |
60 /// Translate `self` by `x`. |
48 /// Translate `self` by `x`. |
61 #[inline] |
49 #[inline] |
62 fn shift(self, x : Loc<F, N>) -> Shift<Self, F, N> { |
50 fn shift(self, x : Loc<F, N>) -> Shift<Self, F, N> { |
63 Shift { shift : x, base_fn : self } |
51 Shift { shift : x, base_fn : self } |
64 } |
52 } |
65 |
53 } |
66 /// Multiply `self` by the scalar `a`. |
54 |
67 #[inline] |
55 /// Trait for globally analysing a property `A` of a [`Mapping`]. |
68 fn weigh<C : Constant<Type=F>>(self, a : C) -> Weighted<Self, C> { |
|
69 Weighted { weight : a, base_fn : self } |
|
70 } |
|
71 } |
|
72 |
|
73 /// Trait for globally analysing a property `A` of a [`Apply`]. |
|
74 /// |
56 /// |
75 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as |
57 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as |
76 /// [`Bounds`][super::aggregator::Bounds]. |
58 /// [`Bounds`][super::aggregator::Bounds]. |
77 pub trait GlobalAnalysis<F : Num, A> { |
59 pub trait GlobalAnalysis<F : Num, A> { |
78 /// Perform global analysis of the property `A` of `Self`. |
60 /// Perform global analysis of the property `A` of `Self`. |
89 // fn global_analysis(&self) -> Bounds<F> { |
71 // fn global_analysis(&self) -> Bounds<F> { |
90 // self.local_analysis(&self.support_hint()) |
72 // self.local_analysis(&self.support_hint()) |
91 // } |
73 // } |
92 // } |
74 // } |
93 |
75 |
94 /// Trait for locally analysing a property `A` of a [`Apply`] (implementing [`Support`]) |
76 /// Trait for locally analysing a property `A` of a [`Mapping`] (implementing [`Support`]) |
95 /// within a [`Cube`]. |
77 /// within a [`Cube`]. |
96 /// |
78 /// |
97 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as |
79 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as |
98 /// [`Bounds`][super::aggregator::Bounds]. |
80 /// [`Bounds`][super::aggregator::Bounds]. |
99 pub trait LocalAnalysis<F : Num, A, const N : usize> : GlobalAnalysis<F, A> + Support<F, N> { |
81 pub trait LocalAnalysis<F : Num, A, const N : usize> : GlobalAnalysis<F, A> + Support<F, N> { |
103 /// this function will return upper and lower bounds within `cube` for the mapping |
85 /// this function will return upper and lower bounds within `cube` for the mapping |
104 /// represented by `self`. |
86 /// represented by `self`. |
105 fn local_analysis(&self, cube : &Cube<F, N>) -> A; |
87 fn local_analysis(&self, cube : &Cube<F, N>) -> A; |
106 } |
88 } |
107 |
89 |
108 /// Trait for determining the upper and lower bounds of an float-valued [`Apply`]. |
90 /// Trait for determining the upper and lower bounds of an float-valued [`Mapping`]. |
109 /// |
91 /// |
110 /// This is a blanket-implemented alias for [`GlobalAnalysis`]`<F, Bounds<F>>` |
92 /// This is a blanket-implemented alias for [`GlobalAnalysis`]`<F, Bounds<F>>` |
111 /// [`Apply`] is not a supertrait to allow flexibility in the implementation of either |
93 /// [`Mapping`] is not a supertrait to allow flexibility in the implementation of either |
112 /// reference or non-reference arguments. |
94 /// reference or non-reference arguments. |
113 pub trait Bounded<F : Float> : GlobalAnalysis<F, Bounds<F>> { |
95 pub trait Bounded<F : Float> : GlobalAnalysis<F, Bounds<F>> { |
114 /// Return lower and upper bounds for the values of of `self`. |
96 /// Return lower and upper bounds for the values of of `self`. |
115 #[inline] |
97 #[inline] |
116 fn bounds(&self) -> Bounds<F> { |
98 fn bounds(&self) -> Bounds<F> { |
118 } |
100 } |
119 } |
101 } |
120 |
102 |
121 impl<F : Float, T : GlobalAnalysis<F, Bounds<F>>> Bounded<F> for T { } |
103 impl<F : Float, T : GlobalAnalysis<F, Bounds<F>>> Bounded<F> for T { } |
122 |
104 |
123 /// Shift of [`Support`] and [`Apply`]; output of [`Support::shift`]. |
105 /// Shift of [`Support`] and [`Mapping`]; output of [`Support::shift`]. |
124 #[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc. |
106 #[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc. |
125 pub struct Shift<T, F, const N : usize> { |
107 pub struct Shift<T, F, const N : usize> { |
126 shift : Loc<F, N>, |
108 shift : Loc<F, N>, |
127 base_fn : T, |
109 base_fn : T, |
128 } |
110 } |
129 |
111 |
130 impl<'a, T, V, F : Float, const N : usize> Apply<&'a Loc<F, N>> for Shift<T,F,N> |
112 impl<'a, T, V : Space, F : Float, const N : usize> Mapping<Loc<F, N>> for Shift<T,F,N> |
131 where T : Apply<Loc<F, N>, Output=V> { |
113 where T : Mapping<Loc<F, N>, Codomain=V> { |
132 type Output = V; |
114 type Codomain = V; |
133 #[inline] |
115 |
134 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
116 #[inline] |
135 self.base_fn.apply(x - &self.shift) |
117 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain { |
136 } |
118 self.base_fn.apply(x.own() - &self.shift) |
137 } |
119 } |
138 |
120 } |
139 impl<'a, T, V, F : Float, const N : usize> Apply<Loc<F, N>> for Shift<T,F,N> |
121 |
140 where T : Apply<Loc<F, N>, Output=V> { |
122 impl<'a, T, V : Space, F : Float, const N : usize> DifferentiableImpl<Loc<F, N>> for Shift<T,F,N> |
141 type Output = V; |
123 where T : DifferentiableMapping<Loc<F, N>, DerivativeDomain=V> { |
142 #[inline] |
124 type Derivative = V; |
143 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
125 |
144 self.base_fn.apply(x - &self.shift) |
126 #[inline] |
|
127 fn differential_impl<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Derivative { |
|
128 self.base_fn.differential(x.own() - &self.shift) |
145 } |
129 } |
146 } |
130 } |
147 |
131 |
148 impl<'a, T, F : Float, const N : usize> Support<F,N> for Shift<T,F,N> |
132 impl<'a, T, F : Float, const N : usize> Support<F,N> for Shift<T,F,N> |
149 where T : Support<F, N> { |
133 where T : Support<F, N> { |
197 } |
181 } |
198 )* } |
182 )* } |
199 } |
183 } |
200 |
184 |
201 impl_shift_norm!(L1 L2 Linfinity); |
185 impl_shift_norm!(L1 L2 Linfinity); |
202 |
|
203 /// Weighting of a [`Support`] and [`Apply`] by scalar multiplication; |
|
204 /// output of [`Support::weigh`]. |
|
205 #[derive(Copy,Clone,Debug,Serialize)] |
|
206 pub struct Weighted<T, C : Constant> { |
|
207 /// The weight |
|
208 pub weight : C, |
|
209 /// The base [`Support`] or [`Apply`] being weighted. |
|
210 pub base_fn : T, |
|
211 } |
|
212 |
|
213 impl<'a, T, V, F : Float, C, const N : usize> Apply<&'a Loc<F, N>> for Weighted<T, C> |
|
214 where T : for<'b> Apply<&'b Loc<F, N>, Output=V>, |
|
215 V : std::ops::Mul<F,Output=V>, |
|
216 C : Constant<Type=F> { |
|
217 type Output = V; |
|
218 #[inline] |
|
219 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
|
220 self.base_fn.apply(x) * self.weight.value() |
|
221 } |
|
222 } |
|
223 |
|
224 impl<'a, T, V, F : Float, C, const N : usize> Apply<Loc<F, N>> for Weighted<T, C> |
|
225 where T : Apply<Loc<F, N>, Output=V>, |
|
226 V : std::ops::Mul<F,Output=V>, |
|
227 C : Constant<Type=F> { |
|
228 type Output = V; |
|
229 #[inline] |
|
230 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
|
231 self.base_fn.apply(x) * self.weight.value() |
|
232 } |
|
233 } |
|
234 |
186 |
235 impl<'a, T, F : Float, C, const N : usize> Support<F,N> for Weighted<T, C> |
187 impl<'a, T, F : Float, C, const N : usize> Support<F,N> for Weighted<T, C> |
236 where T : Support<F, N>, |
188 where T : Support<F, N>, |
237 C : Constant<Type=F> { |
189 C : Constant<Type=F> { |
238 |
190 |
329 } |
281 } |
330 |
282 |
331 impl_weighted_norm!(L1 L2 Linfinity); |
283 impl_weighted_norm!(L1 L2 Linfinity); |
332 |
284 |
333 |
285 |
334 /// Normalisation of [`Support`] and [`Apply`] to L¹ norm 1. |
286 /// Normalisation of [`Support`] and [`Mapping`] to L¹ norm 1. |
335 /// |
287 /// |
336 /// Currently only scalar-valued functions are supported. |
288 /// Currently only scalar-valued functions are supported. |
337 #[derive(Copy, Clone, Debug, Serialize, PartialEq)] |
289 #[derive(Copy, Clone, Debug, Serialize, PartialEq)] |
338 pub struct Normalised<T>( |
290 pub struct Normalised<T>( |
339 /// The base [`Support`] or [`Apply`]. |
291 /// The base [`Support`] or [`Mapping`]. |
340 pub T |
292 pub T |
341 ); |
293 ); |
342 |
294 |
343 impl<'a, T, F : Float, const N : usize> Apply<&'a Loc<F, N>> for Normalised<T> |
295 impl<'a, T, F : Float, const N : usize> Mapping<Loc<F, N>> for Normalised<T> |
344 where T : Norm<F, L1> + for<'b> Apply<&'b Loc<F, N>, Output=F> { |
296 where T : Norm<F, L1> + Mapping<Loc<F,N>, Codomain=F> { |
345 type Output = F; |
297 type Codomain = F; |
346 #[inline] |
298 |
347 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
299 #[inline] |
348 let w = self.0.norm(L1); |
300 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain { |
349 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } |
|
350 } |
|
351 } |
|
352 |
|
353 impl<'a, T, F : Float, const N : usize> Apply<Loc<F, N>> for Normalised<T> |
|
354 where T : Norm<F, L1> + Apply<Loc<F,N>, Output=F> { |
|
355 type Output = F; |
|
356 #[inline] |
|
357 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
|
358 let w = self.0.norm(L1); |
301 let w = self.0.norm(L1); |
359 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } |
302 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } |
360 } |
303 } |
361 } |
304 } |
362 |
305 |
447 /// [ids][`Self::Id`]. |
390 /// [ids][`Self::Id`]. |
448 pub trait SupportGenerator<F : Float, const N : usize> |
391 pub trait SupportGenerator<F : Float, const N : usize> |
449 : MulAssign<F> + DivAssign<F> + Neg<Output=Self> + Clone + Sync + Send + 'static { |
392 : MulAssign<F> + DivAssign<F> + Neg<Output=Self> + Clone + Sync + Send + 'static { |
450 /// The identification type |
393 /// The identification type |
451 type Id : 'static + Copy; |
394 type Id : 'static + Copy; |
452 /// The type of the [`Support`] (often also a [`Apply`]). |
395 /// The type of the [`Support`] (often also a [`Mapping`]). |
453 type SupportType : 'static + Support<F, N>; |
396 type SupportType : 'static + Support<F, N>; |
454 /// An iterator over all the [`Support`]s of the generator. |
397 /// An iterator over all the [`Support`]s of the generator. |
455 type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a; |
398 type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a; |
456 |
399 |
457 /// Returns the component identified by `id`. |
400 /// Returns the component identified by `id`. |