8 use crate::maputil::map2; |
8 use crate::maputil::map2; |
9 use crate::mapping::{Apply, Differentiable}; |
9 use crate::mapping::{Apply, Differentiable}; |
10 use crate::sets::Cube; |
10 use crate::sets::Cube; |
11 use crate::loc::Loc; |
11 use crate::loc::Loc; |
12 use super::aggregator::Bounds; |
12 use super::aggregator::Bounds; |
13 use crate::norms::{Norm, L1, L2, Linfinity}; |
13 use crate::norms::{Norm, L1, L2, Linfinity, HasScalarField, HasRealField}; |
14 |
14 |
15 /// A trait for encoding constant [`Float`] values |
15 /// A trait for encoding constant [`Float`] values |
16 pub trait Constant : Copy + Sync + Send + 'static + std::fmt::Debug + Into<Self::Type> { |
16 pub trait Constant : Copy + Sync + Send + 'static |
17 /// The type of the value |
17 + std::fmt::Debug + HasRealField |
18 type Type : Float; |
18 + Into<Self::Field> { |
19 /// Returns the value of the constant |
19 /// Returns the value of the constant |
20 fn value(&self) -> Self::Type; |
20 fn value(&self) -> Self::Field; |
21 } |
21 } |
22 |
22 |
23 impl<F : Float> Constant for F { |
23 impl<F : Float> Constant for F { |
24 type Type = F; |
|
25 #[inline] |
24 #[inline] |
26 fn value(&self) -> F { *self } |
25 fn value(&self) -> F { *self } |
27 } |
26 } |
28 |
27 |
29 |
28 |
30 /// A trait for working with the supports of [`Apply`]s. |
29 /// A trait for working with the supports of [`Apply`]s. |
31 /// |
30 /// |
32 /// Apply is not a super-trait to allow more general use. |
31 /// Apply is not a super-trait to allow more general use. |
33 pub trait Support<F : Num, const N : usize> : Sized + Sync + Send + 'static { |
32 pub trait Support<const N : usize> : Sized + Sync + Send + 'static + HasRealField { |
34 /// Return a cube containing the support of the function represented by `self`. |
33 /// Return a cube containing the support of the function represented by `self`. |
35 /// |
34 /// |
36 /// The hint may be larger than the actual support, but must contain it. |
35 /// The hint may be larger than the actual support, but must contain it. |
37 fn support_hint(&self) -> Cube<F,N>; |
36 fn support_hint(&self) -> Cube<Self::Field,N>; |
38 |
37 |
39 /// Indicate whether `x` is in the support of the function represented by `self`. |
38 /// Indicate whether `x` is in the support of the function represented by `self`. |
40 fn in_support(&self, x : &Loc<F,N>) -> bool; |
39 fn in_support(&self, x : &Loc<Self::Field,N>) -> bool; |
41 |
40 |
42 // Indicate whether `cube` is fully in the support of the function represented by `self`. |
41 // Indicate whether `cube` is fully in the support of the function represented by `self`. |
43 //fn fully_in_support(&self, cube : &Cube<F,N>) -> bool; |
42 //fn fully_in_support(&self, cube : &Cube<Self::Field,N>) -> bool; |
44 |
43 |
45 /// Return an optional hint for bisecting the support. |
44 /// Return an optional hint for bisecting the support. |
46 /// |
45 /// |
47 /// The output along each axis a possible coordinate at which to bisect `cube`. |
46 /// The output along each axis a possible coordinate at which to bisect `cube`. |
48 /// |
47 /// |
51 /// non-differentiability. |
50 /// non-differentiability. |
52 /// |
51 /// |
53 /// The default implementation returns `[None; N]`. |
52 /// The default implementation returns `[None; N]`. |
54 #[inline] |
53 #[inline] |
55 #[allow(unused_variables)] |
54 #[allow(unused_variables)] |
56 fn bisection_hint(&self, cube : &Cube<F, N>) -> [Option<F>; N] { |
55 fn bisection_hint(&self, cube : &Cube<Self::Field, N>) -> [Option<Self::Field>; N] { |
57 [None; N] |
56 [None; N] |
58 } |
57 } |
59 |
58 |
60 /// Translate `self` by `x`. |
59 /// Translate `self` by `x`. |
61 #[inline] |
60 #[inline] |
62 fn shift(self, x : Loc<F, N>) -> Shift<Self, F, N> { |
61 fn shift(self, x : Loc<Self::Field, N>) -> Shift<Self, Self::Field, N> { |
63 Shift { shift : x, base_fn : self } |
62 Shift { shift : x, base_fn : self } |
64 } |
63 } |
65 |
64 |
66 /// Multiply `self` by the scalar `a`. |
65 /// Multiply `self` by the scalar `a`. |
67 #[inline] |
66 #[inline] |
68 fn weigh<C : Constant<Type=F>>(self, a : C) -> Weighted<Self, C> { |
67 fn weigh<C : Constant<RealField=Self::RealField>>(self, a : C) -> Weighted<Self, C> { |
69 Weighted { weight : a, base_fn : self } |
68 Weighted { weight : a, base_fn : self } |
70 } |
69 } |
71 } |
70 } |
72 |
71 |
73 /// Trait for globally analysing a property `A` of a [`Apply`]. |
72 /// Trait for globally analysing a property `A` of a [`Apply`]. |
74 /// |
73 /// |
75 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as |
74 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as |
76 /// [`Bounds`][super::aggregator::Bounds]. |
75 /// [`Bounds`][super::aggregator::Bounds]. |
77 pub trait GlobalAnalysis<F : Num, A> { |
76 pub trait GlobalAnalysis<A> { |
78 /// Perform global analysis of the property `A` of `Self`. |
77 /// Perform global analysis of the property `A` of `Self`. |
79 /// |
78 /// |
80 /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], |
79 /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], |
81 /// this function will return global upper and lower bounds for the mapping |
80 /// this function will return global upper and lower bounds for the mapping |
82 /// represented by `self`. |
81 /// represented by `self`. |
83 fn global_analysis(&self) -> A; |
82 fn global_analysis(&self) -> A; |
84 } |
83 } |
85 |
|
86 // default impl<F, A, N, L> GlobalAnalysis<F, A, N> for L |
|
87 // where L : LocalAnalysis<F, A, N> { |
|
88 // #[inline] |
|
89 // fn global_analysis(&self) -> Bounds<F> { |
|
90 // self.local_analysis(&self.support_hint()) |
|
91 // } |
|
92 // } |
|
93 |
84 |
94 /// Trait for locally analysing a property `A` of a [`Apply`] (implementing [`Support`]) |
85 /// Trait for locally analysing a property `A` of a [`Apply`] (implementing [`Support`]) |
95 /// within a [`Cube`]. |
86 /// within a [`Cube`]. |
96 /// |
87 /// |
97 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as |
88 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as |
98 /// [`Bounds`][super::aggregator::Bounds]. |
89 /// [`Bounds`][super::aggregator::Bounds]. |
99 pub trait LocalAnalysis<F : Num, A, const N : usize> : GlobalAnalysis<F, A> + Support<F, N> { |
90 pub trait LocalAnalysis<A, LocalSet> : GlobalAnalysis<A> { |
100 /// Perform local analysis of the property `A` of `Self`. |
91 /// Perform local analysis of the property `A` of `Self`. |
101 /// |
92 /// |
102 /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], |
93 /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], |
103 /// this function will return upper and lower bounds within `cube` for the mapping |
94 /// this function will return upper and lower bounds within `cube` for the mapping |
104 /// represented by `self`. |
95 /// represented by `self`. |
105 fn local_analysis(&self, cube : &Cube<F, N>) -> A; |
96 fn local_analysis(&self, cube : &LocalSet) -> A; |
106 } |
97 } |
107 |
98 |
108 /// Trait for determining the upper and lower bounds of an float-valued [`Apply`]. |
99 /// Trait for determining the upper and lower bounds of an float-valued [`Apply`]. |
109 /// |
100 /// |
110 /// This is a blanket-implemented alias for [`GlobalAnalysis`]`<F, Bounds<F>>` |
101 /// 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 |
102 /// [`Apply`] is not a supertrait to allow flexibility in the implementation of either |
112 /// reference or non-reference arguments. |
103 /// reference or non-reference arguments. |
113 pub trait Bounded<F : Float> : GlobalAnalysis<F, Bounds<F>> { |
104 pub trait Bounded : GlobalAnalysis<Bounds<Self::Field>> + HasScalarField { |
114 /// Return lower and upper bounds for the values of of `self`. |
105 /// Return lower and upper bounds for the values of of `self`. |
115 #[inline] |
106 #[inline] |
116 fn bounds(&self) -> Bounds<F> { |
107 fn bounds(&self) -> Bounds<Self::Field> { |
117 self.global_analysis() |
108 self.global_analysis() |
118 } |
109 } |
119 } |
110 } |
120 |
111 |
121 impl<F : Float, T : GlobalAnalysis<F, Bounds<F>>> Bounded<F> for T { } |
112 impl<T : GlobalAnalysis<Bounds<Self::Field>> + HasScalarField> Bounded for T { } |
122 |
113 |
123 /// Shift of [`Support`] and [`Apply`]; output of [`Support::shift`]. |
114 /// Shift of [`Support`] and [`Apply`]; output of [`Support::shift`]. |
124 #[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc. |
115 #[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc. |
125 pub struct Shift<T, F, const N : usize> { |
116 pub struct Shift<T, F, const N : usize> { |
126 shift : Loc<F, N>, |
117 shift : Loc<F, N>, |
127 base_fn : T, |
118 base_fn : T, |
128 } |
119 } |
129 |
120 |
|
121 impl<T, F : Num, const N : usize> HasScalarField for Shift<T, F, N> { |
|
122 type Field = F; |
|
123 } |
|
124 |
130 impl<'a, T, V, F : Float, const N : usize> Apply<&'a Loc<F, N>> for Shift<T,F,N> |
125 impl<'a, T, V, F : Float, const N : usize> Apply<&'a Loc<F, N>> for Shift<T,F,N> |
131 where T : Apply<Loc<F, N>, Output=V> { |
126 where T : Apply<Loc<F, N>, Output=V> { |
132 type Output = V; |
127 type Output = V; |
133 #[inline] |
128 #[inline] |
134 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
129 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
143 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
138 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
144 self.base_fn.apply(x - &self.shift) |
139 self.base_fn.apply(x - &self.shift) |
145 } |
140 } |
146 } |
141 } |
147 |
142 |
148 impl<'a, T, V, F : Float, const N : usize> Differentiable<&'a Loc<F, N>> for Shift<T,F,N> |
143 impl<'a, T, V : HasRealField<RealField=F>, F : Float, const N : usize> |
|
144 Differentiable<&'a Loc<F, N>> for Shift<T,F,N> |
149 where T : Differentiable<Loc<F, N>, Derivative=V> { |
145 where T : Differentiable<Loc<F, N>, Derivative=V> { |
150 type Derivative = V; |
146 type Derivative = V; |
151 #[inline] |
147 #[inline] |
152 fn differential(&self, x : &'a Loc<F, N>) -> Self::Derivative { |
148 fn differential(&self, x : &'a Loc<F, N>) -> Self::Derivative { |
153 self.base_fn.differential(x - &self.shift) |
149 self.base_fn.differential(x - &self.shift) |
154 } |
150 } |
155 } |
151 } |
156 |
152 |
157 impl<'a, T, V, F : Float, const N : usize> Differentiable<Loc<F, N>> for Shift<T,F,N> |
153 impl<'a, T, V : HasRealField<RealField=F>, F : Float, const N : usize> |
|
154 Differentiable<Loc<F, N>> for Shift<T,F,N> |
158 where T : Differentiable<Loc<F, N>, Derivative=V> { |
155 where T : Differentiable<Loc<F, N>, Derivative=V> { |
159 type Derivative = V; |
156 type Derivative = V; |
160 #[inline] |
157 #[inline] |
161 fn differential(&self, x : Loc<F, N>) -> Self::Derivative { |
158 fn differential(&self, x : Loc<F, N>) -> Self::Derivative { |
162 self.base_fn.differential(x - &self.shift) |
159 self.base_fn.differential(x - &self.shift) |
163 } |
160 } |
164 } |
161 } |
165 |
162 |
166 impl<'a, T, F : Float, const N : usize> Support<F,N> for Shift<T,F,N> |
163 impl<'a, T, F : Float, const N : usize> Support<N> for Shift<T,F,N> |
167 where T : Support<F, N> { |
164 where T : Support<N, RealField = F> { |
168 #[inline] |
165 #[inline] |
169 fn support_hint(&self) -> Cube<F,N> { |
166 fn support_hint(&self) -> Cube<F,N> { |
170 self.base_fn.support_hint().shift(&self.shift) |
167 self.base_fn.support_hint().shift(&self.shift) |
171 } |
168 } |
172 |
169 |
186 map2(base_hint, &self.shift, |h, s| h.map(|z| z + *s)) |
183 map2(base_hint, &self.shift, |h, s| h.map(|z| z + *s)) |
187 } |
184 } |
188 |
185 |
189 } |
186 } |
190 |
187 |
191 impl<'a, T, F : Float, const N : usize> GlobalAnalysis<F, Bounds<F>> for Shift<T,F,N> |
188 impl<'a, T, F : Float, const N : usize> GlobalAnalysis<Bounds<F>> for Shift<T,F,N> |
192 where T : LocalAnalysis<F, Bounds<F>, N> { |
189 where T : GlobalAnalysis<Bounds<F>> { |
193 #[inline] |
190 #[inline] |
194 fn global_analysis(&self) -> Bounds<F> { |
191 fn global_analysis(&self) -> Bounds<F> { |
195 self.base_fn.global_analysis() |
192 self.base_fn.global_analysis() |
196 } |
193 } |
197 } |
194 } |
198 |
195 |
199 impl<'a, T, F : Float, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Shift<T,F,N> |
196 impl<'a, T, F : Float, const N : usize> LocalAnalysis<Bounds<F>, Cube<F, N>> |
200 where T : LocalAnalysis<F, Bounds<F>, N> { |
197 for Shift<T,F,N> |
|
198 where T : LocalAnalysis<Bounds<F>, Cube<F, N>> { |
201 #[inline] |
199 #[inline] |
202 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
200 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
203 self.base_fn.local_analysis(&cube.shift(&(-self.shift))) |
201 self.base_fn.local_analysis(&cube.shift(&(-self.shift))) |
204 } |
202 } |
205 } |
203 } |
206 |
204 |
207 macro_rules! impl_shift_norm { |
205 macro_rules! impl_shift_norm { |
208 ($($norm:ident)*) => { $( |
206 ($($norm:ident)*) => { $( |
209 impl<'a, T, F : Float, const N : usize> Norm<F, $norm> for Shift<T,F,N> |
207 impl<'a, T, const N : usize> Norm<$norm> for Shift<T,T::Field,N> |
210 where T : Norm<F, $norm> { |
208 where T : Norm<$norm> { |
211 #[inline] |
209 #[inline] |
212 fn norm(&self, n : $norm) -> F { |
210 fn norm(&self, n : $norm) -> T::Field { |
213 self.base_fn.norm(n) |
211 self.base_fn.norm(n) |
214 } |
212 } |
215 } |
213 } |
216 )* } |
214 )* } |
217 } |
215 } |
226 pub weight : C, |
224 pub weight : C, |
227 /// The base [`Support`] or [`Apply`] being weighted. |
225 /// The base [`Support`] or [`Apply`] being weighted. |
228 pub base_fn : T, |
226 pub base_fn : T, |
229 } |
227 } |
230 |
228 |
|
229 impl<T, C, F : Float> HasScalarField for Weighted<T, C> |
|
230 where T : HasRealField<RealField = F>, |
|
231 C : Constant<RealField = F> { |
|
232 type Field = F; |
|
233 } |
|
234 |
231 impl<'a, T, V, F : Float, C, const N : usize> Apply<&'a Loc<F, N>> for Weighted<T, C> |
235 impl<'a, T, V, F : Float, C, const N : usize> Apply<&'a Loc<F, N>> for Weighted<T, C> |
232 where T : for<'b> Apply<&'b Loc<F, N>, Output=V>, |
236 where T : for<'b> Apply<&'b Loc<F, N>, Output=V>, |
233 V : std::ops::Mul<F,Output=V>, |
237 V : std::ops::Mul<F,Output=V>, |
234 C : Constant<Type=F> { |
238 C : Constant<RealField=F> { |
235 type Output = V; |
239 type Output = V; |
236 #[inline] |
240 #[inline] |
237 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
241 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
238 self.base_fn.apply(x) * self.weight.value() |
242 self.base_fn.apply(x) * self.weight.value() |
239 } |
243 } |
240 } |
244 } |
241 |
245 |
242 impl<'a, T, V, F : Float, C, const N : usize> Apply<Loc<F, N>> for Weighted<T, C> |
246 impl<'a, T, V, F : Float, C, const N : usize> Apply<Loc<F, N>> for Weighted<T, C> |
243 where T : Apply<Loc<F, N>, Output=V>, |
247 where T : Apply<Loc<F, N>, Output=V>, |
244 V : std::ops::Mul<F,Output=V>, |
248 V : std::ops::Mul<F,Output=V>, |
245 C : Constant<Type=F> { |
249 C : Constant<RealField=F> { |
246 type Output = V; |
250 type Output = V; |
247 #[inline] |
251 #[inline] |
248 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
252 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
249 self.base_fn.apply(x) * self.weight.value() |
253 self.base_fn.apply(x) * self.weight.value() |
250 } |
254 } |
251 } |
255 } |
252 |
256 |
253 impl<'a, T, V, F : Float, C, const N : usize> Differentiable<&'a Loc<F, N>> for Weighted<T, C> |
257 impl<'a, T, V : HasRealField<RealField=F>, F : Float, C, const N : usize> |
254 where T : for<'b> Differentiable<&'b Loc<F, N>, Derivative=V>, |
258 Differentiable<&'a Loc<F, N>> for Weighted<T, C> |
|
259 where T : for<'b> Differentiable<&'b Loc<F, N>, Derivative=V, RealField=F>, |
255 V : std::ops::Mul<F, Output=V>, |
260 V : std::ops::Mul<F, Output=V>, |
256 C : Constant<Type=F> { |
261 C : Constant<RealField=F> { |
257 type Derivative = V; |
262 type Derivative = V; |
258 #[inline] |
263 #[inline] |
259 fn differential(&self, x : &'a Loc<F, N>) -> Self::Derivative { |
264 fn differential(&self, x : &'a Loc<F, N>) -> Self::Derivative { |
260 self.base_fn.differential(x) * self.weight.value() |
265 self.base_fn.differential(x) * self.weight.value() |
261 } |
266 } |
262 } |
267 } |
263 |
268 |
264 impl<'a, T, V, F : Float, C, const N : usize> Differentiable<Loc<F, N>> for Weighted<T, C> |
269 impl<'a, T, V : HasRealField<RealField = F>, F : Float, C, const N : usize> |
265 where T : Differentiable<Loc<F, N>, Derivative=V>, |
270 Differentiable<Loc<F, N>> for Weighted<T, C> |
|
271 where T : Differentiable<Loc<F, N>, Derivative=V, RealField = F>, |
266 V : std::ops::Mul<F, Output=V>, |
272 V : std::ops::Mul<F, Output=V>, |
267 C : Constant<Type=F> { |
273 C : Constant<RealField=F> { |
268 type Derivative = V; |
274 type Derivative = V; |
269 #[inline] |
275 #[inline] |
270 fn differential(&self, x : Loc<F, N>) -> Self::Derivative { |
276 fn differential(&self, x : Loc<F, N>) -> Self::Derivative { |
271 self.base_fn.differential(x) * self.weight.value() |
277 self.base_fn.differential(x) * self.weight.value() |
272 } |
278 } |
273 } |
279 } |
274 |
280 |
275 impl<'a, T, F : Float, C, const N : usize> Support<F,N> for Weighted<T, C> |
281 impl<'a, T, F : Float, C, const N : usize> Support<N> for Weighted<T, C> |
276 where T : Support<F, N>, |
282 where T : Support<N, RealField = F>, |
277 C : Constant<Type=F> { |
283 C : Constant<RealField=F> { |
278 |
284 |
279 #[inline] |
285 #[inline] |
280 fn support_hint(&self) -> Cube<F,N> { |
286 fn support_hint(&self) -> Cube<F,N> { |
281 self.base_fn.support_hint() |
287 self.base_fn.support_hint() |
282 } |
288 } |
308 w => Bounds(w * lower, w * upper), |
314 w => Bounds(w * lower, w * upper), |
309 } |
315 } |
310 } |
316 } |
311 } |
317 } |
312 |
318 |
313 impl<'a, T, F : Float, C, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Weighted<T, C> |
319 impl<'a, T, F : Float, C, const N : usize> LocalAnalysis<Bounds<F>, Cube<F, N>> |
314 where T : LocalAnalysis<F, Bounds<F>, N>, |
320 for Weighted<T, C> |
315 C : Constant<Type=F> { |
321 where T : LocalAnalysis<Bounds<F>, Cube<F, N>>, |
|
322 C : Constant<RealField=F> { |
316 #[inline] |
323 #[inline] |
317 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
324 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
318 let Bounds(lower, upper) = self.base_fn.local_analysis(cube); |
325 let Bounds(lower, upper) = self.base_fn.local_analysis(cube); |
319 debug_assert!(lower <= upper); |
326 debug_assert!(lower <= upper); |
320 match self.weight.value() { |
327 match self.weight.value() { |
379 /// The base [`Support`] or [`Apply`]. |
387 /// The base [`Support`] or [`Apply`]. |
380 pub T |
388 pub T |
381 ); |
389 ); |
382 |
390 |
383 impl<'a, T, F : Float, const N : usize> Apply<&'a Loc<F, N>> for Normalised<T> |
391 impl<'a, T, F : Float, const N : usize> Apply<&'a Loc<F, N>> for Normalised<T> |
384 where T : Norm<F, L1> + for<'b> Apply<&'b Loc<F, N>, Output=F> { |
392 where T : Norm<L1, Field=F> + for<'b> Apply<&'b Loc<F, N>, Output=F> { |
385 type Output = F; |
393 type Output = F; |
386 #[inline] |
394 #[inline] |
387 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
395 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
388 let w = self.0.norm(L1); |
396 let w = self.0.norm(L1); |
389 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } |
397 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } |
390 } |
398 } |
391 } |
399 } |
392 |
400 |
393 impl<'a, T, F : Float, const N : usize> Apply<Loc<F, N>> for Normalised<T> |
401 impl<'a, T, F : Float, const N : usize> Apply<Loc<F, N>> for Normalised<T> |
394 where T : Norm<F, L1> + Apply<Loc<F,N>, Output=F> { |
402 where T : Norm<L1, Field = F> + Apply<Loc<F,N>, Output=F> { |
395 type Output = F; |
403 type Output = F; |
396 #[inline] |
404 #[inline] |
397 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
405 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
398 let w = self.0.norm(L1); |
406 let w = self.0.norm(L1); |
399 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } |
407 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } |
400 } |
408 } |
401 } |
409 } |
402 |
410 |
403 impl<'a, T, F : Float, const N : usize> Support<F,N> for Normalised<T> |
411 impl<'a, T, F : Float, const N : usize> Support<N> for Normalised<T> |
404 where T : Norm<F, L1> + Support<F, N> { |
412 where T : Norm<L1> + Support<N, RealField = F> { |
405 |
413 |
406 #[inline] |
414 #[inline] |
407 fn support_hint(&self) -> Cube<F,N> { |
415 fn support_hint(&self) -> Cube<F,N> { |
408 self.0.support_hint() |
416 self.0.support_hint() |
409 } |
417 } |
421 fn bisection_hint(&self, cube : &Cube<F,N>) -> [Option<F>; N] { |
429 fn bisection_hint(&self, cube : &Cube<F,N>) -> [Option<F>; N] { |
422 self.0.bisection_hint(cube) |
430 self.0.bisection_hint(cube) |
423 } |
431 } |
424 } |
432 } |
425 |
433 |
426 impl<'a, T, F : Float> GlobalAnalysis<F, Bounds<F>> for Normalised<T> |
434 impl<'a, T, F : Float> GlobalAnalysis<Bounds<F>> for Normalised<T> |
427 where T : Norm<F, L1> + GlobalAnalysis<F, Bounds<F>> { |
435 where T : Norm<L1, Field = F> + GlobalAnalysis<Bounds<F>> { |
428 #[inline] |
436 #[inline] |
429 fn global_analysis(&self) -> Bounds<F> { |
437 fn global_analysis(&self) -> Bounds<F> { |
430 let Bounds(lower, upper) = self.0.global_analysis(); |
438 let Bounds(lower, upper) = self.0.global_analysis(); |
431 debug_assert!(lower <= upper); |
439 debug_assert!(lower <= upper); |
432 let w = self.0.norm(L1); |
440 let w = self.0.norm(L1); |
433 debug_assert!(w >= F::ZERO); |
441 debug_assert!(w >= F::ZERO); |
434 Bounds(w * lower, w * upper) |
442 Bounds(w * lower, w * upper) |
435 } |
443 } |
436 } |
444 } |
437 |
445 |
438 impl<'a, T, F : Float, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Normalised<T> |
446 impl<'a, T, F : Float, const N : usize> LocalAnalysis<Bounds<F>, Cube<F, N>> |
439 where T : Norm<F, L1> + LocalAnalysis<F, Bounds<F>, N> { |
447 for Normalised<T> |
|
448 where T : Norm<L1, Field = F> + LocalAnalysis<Bounds<F>, Cube<F, N>> { |
440 #[inline] |
449 #[inline] |
441 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
450 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
442 let Bounds(lower, upper) = self.0.local_analysis(cube); |
451 let Bounds(lower, upper) = self.0.local_analysis(cube); |
443 debug_assert!(lower <= upper); |
452 debug_assert!(lower <= upper); |
444 let w = self.0.norm(L1); |
453 let w = self.0.norm(L1); |
445 debug_assert!(w >= F::ZERO); |
454 debug_assert!(w >= F::ZERO); |
446 Bounds(w * lower, w * upper) |
455 Bounds(w * lower, w * upper) |
447 } |
456 } |
448 } |
457 } |
449 |
458 |
450 impl<'a, T, F : Float> Norm<F, L1> for Normalised<T> |
459 impl<'a, T> HasScalarField for Normalised<T> where T : HasScalarField { |
451 where T : Norm<F, L1> { |
460 type Field = T::Field; |
452 #[inline] |
461 } |
453 fn norm(&self, _ : L1) -> F { |
462 |
|
463 impl<'a, T> Norm<L1> for Normalised<T> where T : Norm<L1> { |
|
464 #[inline] |
|
465 fn norm(&self, _ : L1) -> Self::Field { |
454 let w = self.0.norm(L1); |
466 let w = self.0.norm(L1); |
455 if w == F::ZERO { F::ZERO } else { F::ONE } |
467 if w == Self::Field::ZERO { Self::Field::ZERO } else { Self::Field::ONE } |
456 } |
468 } |
457 } |
469 } |
458 |
470 |
459 macro_rules! impl_normalised_norm { |
471 macro_rules! impl_normalised_norm { |
460 ($($norm:ident)*) => { $( |
472 ($($norm:ident)*) => { $( |
461 impl<'a, T, F : Float> Norm<F, $norm> for Normalised<T> |
473 impl<'a, T> Norm<$norm> for Normalised<T> where T : Norm<$norm> + Norm<L1> { |
462 where T : Norm<F, $norm> + Norm<F, L1> { |
474 |
463 #[inline] |
475 #[inline] |
464 fn norm(&self, n : $norm) -> F { |
476 fn norm(&self, n : $norm) -> Self::Field { |
465 let w = self.0.norm(L1); |
477 let w = self.0.norm(L1); |
466 if w == F::ZERO { F::ZERO } else { self.0.norm(n) / w } |
478 if w == Self::Field::ZERO { Self::Field::ZERO } else { self.0.norm(n) / w } |
467 } |
479 } |
468 } |
480 } |
469 )* } |
481 )* } |
470 } |
482 } |
471 |
483 |
472 impl_normalised_norm!(L2 Linfinity); |
484 impl_normalised_norm!(L2 Linfinity); |
473 |
485 |
474 /* |
|
475 impl<F : Num, S : Support<F, N>, const N : usize> LocalAnalysis<F, NullAggregator, N> for S { |
|
476 fn local_analysis(&self, _cube : &Cube<F, N>) -> NullAggregator { NullAggregator } |
|
477 } |
|
478 |
|
479 impl<F : Float, S : Bounded<F>, const N : usize> LocalAnalysis<F, Bounds<F>, N> for S { |
|
480 #[inline] |
|
481 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
|
482 self.bounds(cube) |
|
483 } |
|
484 }*/ |
|
485 |
486 |
486 /// Generator of [`Support`]-implementing component functions based on low storage requirement |
487 /// Generator of [`Support`]-implementing component functions based on low storage requirement |
487 /// [ids][`Self::Id`]. |
488 /// [ids][`Self::Id`]. |
488 pub trait SupportGenerator<F : Float, const N : usize> |
489 pub trait SupportGenerator<const N : usize> |
489 : MulAssign<F> + DivAssign<F> + Neg<Output=Self> + Clone + Sync + Send + 'static { |
490 : MulAssign<Self::Field> + DivAssign<Self::Field> + Neg<Output=Self> + HasRealField |
|
491 + Clone + Sync + Send + 'static { |
490 /// The identification type |
492 /// The identification type |
491 type Id : 'static + Copy; |
493 type Id : 'static + Copy; |
492 /// The type of the [`Support`] (often also a [`Apply`]). |
494 /// The type of the [`Support`] (often also a [`Apply`]). |
493 type SupportType : 'static + Support<F, N>; |
495 type SupportType : 'static + Support<N, RealField=Self::RealField>; |
494 /// An iterator over all the [`Support`]s of the generator. |
496 /// An iterator over all the [`Support`]s of the generator. |
495 type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a; |
497 type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a; |
496 |
498 |
497 /// Returns the component identified by `id`. |
499 /// Returns the component identified by `id`. |
498 /// |
500 /// |