src/bisection_tree/support.rs

branch
dev
changeset 96
962c8e346ab9
parent 75
e9f4550cfa18
child 97
4e80fb049dca
equal deleted inserted replaced
95:9cb8225a3a41 96:962c8e346ab9
1
2 /*! 1 /*!
3 Traits for representing the support of a [`Mapping`], and analysing the mapping on a [`Cube`]. 2 Traits for representing the support of a [`Mapping`], and analysing the mapping on a [`Cube`].
4 */ 3 */
4 use super::aggregator::Bounds;
5 use crate::loc::Loc;
6 use crate::mapping::{DifferentiableImpl, DifferentiableMapping, Instance, Mapping, Space};
7 use crate::maputil::map2;
8 use crate::norms::{Linfinity, Norm, L1, L2};
9 pub use crate::operator_arithmetic::{Constant, Weighted};
10 use crate::sets::Cube;
11 use crate::types::{Float, Num};
5 use serde::Serialize; 12 use serde::Serialize;
6 use std::ops::{MulAssign,DivAssign,Neg}; 13 use std::ops::{DivAssign, MulAssign, Neg};
7 use crate::types::{Float, Num};
8 use crate::maputil::map2;
9 use crate::mapping::{
10 Instance, Mapping, DifferentiableImpl, DifferentiableMapping, Space
11 };
12 use crate::sets::Cube;
13 use crate::loc::Loc;
14 use super::aggregator::Bounds;
15 use crate::norms::{Norm, L1, L2, Linfinity};
16 pub use crate::operator_arithmetic::{Weighted, Constant};
17 14
18 /// A trait for working with the supports of [`Mapping`]s. 15 /// A trait for working with the supports of [`Mapping`]s.
19 /// 16 ///
20 /// `Mapping` is not a super-trait to allow more general use. 17 /// `Mapping` is not a super-trait to allow more general use.
21 pub trait Support<F : Num, const N : usize> : Sized + Sync + Send + 'static { 18 pub trait Support<F: Num, const N: usize>: Sized + Sync + Send + 'static {
22 /// Return a cube containing the support of the function represented by `self`. 19 /// Return a cube containing the support of the function represented by `self`.
23 /// 20 ///
24 /// The hint may be larger than the actual support, but must contain it. 21 /// The hint may be larger than the actual support, but must contain it.
25 fn support_hint(&self) -> Cube<F,N>; 22 fn support_hint(&self) -> Cube<F, N>;
26 23
27 /// Indicate whether `x` is in the support of the function represented by `self`. 24 /// Indicate whether `x` is in the support of the function represented by `self`.
28 fn in_support(&self, x : &Loc<F,N>) -> bool; 25 fn in_support(&self, x: &Loc<F, N>) -> bool;
29 26
30 // Indicate whether `cube` is fully in the support of the function represented by `self`. 27 // Indicate whether `cube` is fully in the support of the function represented by `self`.
31 //fn fully_in_support(&self, cube : &Cube<F,N>) -> bool; 28 //fn fully_in_support(&self, cube : &Cube<F,N>) -> bool;
32 29
33 /// Return an optional hint for bisecting the support. 30 /// Return an optional hint for bisecting the support.
39 /// non-differentiability. 36 /// non-differentiability.
40 /// 37 ///
41 /// The default implementation returns `[None; N]`. 38 /// The default implementation returns `[None; N]`.
42 #[inline] 39 #[inline]
43 #[allow(unused_variables)] 40 #[allow(unused_variables)]
44 fn bisection_hint(&self, cube : &Cube<F, N>) -> [Option<F>; N] { 41 fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] {
45 [None; N] 42 [None; N]
46 } 43 }
47 44
48 /// Translate `self` by `x`. 45 /// Translate `self` by `x`.
49 #[inline] 46 #[inline]
50 fn shift(self, x : Loc<F, N>) -> Shift<Self, F, N> { 47 fn shift(self, x: Loc<F, N>) -> Shift<Self, F, N> {
51 Shift { shift : x, base_fn : self } 48 Shift {
49 shift: x,
50 base_fn: self,
51 }
52 } 52 }
53 } 53 }
54 54
55 /// Trait for globally analysing a property `A` of a [`Mapping`]. 55 /// Trait for globally analysing a property `A` of a [`Mapping`].
56 /// 56 ///
57 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as 57 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as
58 /// [`Bounds`][super::aggregator::Bounds]. 58 /// [`Bounds`][super::aggregator::Bounds].
59 pub trait GlobalAnalysis<F : Num, A> { 59 pub trait GlobalAnalysis<F: Num, A> {
60 /// Perform global analysis of the property `A` of `Self`. 60 /// Perform global analysis of the property `A` of `Self`.
61 /// 61 ///
62 /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], 62 /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds],
63 /// this function will return global upper and lower bounds for the mapping 63 /// this function will return global upper and lower bounds for the mapping
64 /// represented by `self`. 64 /// represented by `self`.
76 /// Trait for locally analysing a property `A` of a [`Mapping`] (implementing [`Support`]) 76 /// Trait for locally analysing a property `A` of a [`Mapping`] (implementing [`Support`])
77 /// within a [`Cube`]. 77 /// within a [`Cube`].
78 /// 78 ///
79 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as 79 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as
80 /// [`Bounds`][super::aggregator::Bounds]. 80 /// [`Bounds`][super::aggregator::Bounds].
81 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> {
82 /// Perform local analysis of the property `A` of `Self`. 82 /// Perform local analysis of the property `A` of `Self`.
83 /// 83 ///
84 /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], 84 /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds],
85 /// 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
86 /// represented by `self`. 86 /// represented by `self`.
87 fn local_analysis(&self, cube : &Cube<F, N>) -> A; 87 fn local_analysis(&self, cube: &Cube<F, N>) -> A;
88 } 88 }
89 89
90 /// Trait for determining the upper and lower bounds of an float-valued [`Mapping`]. 90 /// Trait for determining the upper and lower bounds of an float-valued [`Mapping`].
91 /// 91 ///
92 /// This is a blanket-implemented alias for [`GlobalAnalysis`]`<F, Bounds<F>>` 92 /// This is a blanket-implemented alias for [`GlobalAnalysis`]`<F, Bounds<F>>`
93 /// [`Mapping`] 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
94 /// reference or non-reference arguments. 94 /// reference or non-reference arguments.
95 pub trait Bounded<F : Float> : GlobalAnalysis<F, Bounds<F>> { 95 pub trait Bounded<F: Float>: GlobalAnalysis<F, Bounds<F>> {
96 /// Return lower and upper bounds for the values of of `self`. 96 /// Return lower and upper bounds for the values of of `self`.
97 #[inline] 97 #[inline]
98 fn bounds(&self) -> Bounds<F> { 98 fn bounds(&self) -> Bounds<F> {
99 self.global_analysis() 99 self.global_analysis()
100 } 100 }
101 } 101 }
102 102
103 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 {}
104 104
105 /// Shift of [`Support`] and [`Mapping`]; output of [`Support::shift`]. 105 /// Shift of [`Support`] and [`Mapping`]; output of [`Support::shift`].
106 #[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc. 106 #[derive(Copy, Clone, Debug, Serialize)] // Serialize! but not implemented by Loc.
107 pub struct Shift<T, F, const N : usize> { 107 pub struct Shift<T, F, const N: usize> {
108 shift : Loc<F, N>, 108 shift: Loc<F, N>,
109 base_fn : T, 109 base_fn: T,
110 } 110 }
111 111
112 impl<'a, T, V : Space, F : Float, const N : usize> Mapping<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>
113 where T : Mapping<Loc<F, N>, Codomain=V> { 113 where
114 T: Mapping<Loc<F, N>, Codomain = V>,
115 {
114 type Codomain = V; 116 type Codomain = V;
115 117
116 #[inline] 118 #[inline]
117 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain { 119 fn apply<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Codomain {
118 self.base_fn.apply(x.own() - &self.shift) 120 self.base_fn.apply(x.own() - &self.shift)
119 } 121 }
120 } 122 }
121 123
122 impl<'a, T, V : Space, F : Float, const N : usize> DifferentiableImpl<Loc<F, N>> for Shift<T,F,N> 124 impl<'a, T, V: Space, F: Float, const N: usize> DifferentiableImpl<Loc<F, N>> for Shift<T, F, N>
123 where T : DifferentiableMapping<Loc<F, N>, DerivativeDomain=V> { 125 where
126 T: DifferentiableMapping<Loc<F, N>, DerivativeDomain = V>,
127 {
124 type Derivative = V; 128 type Derivative = V;
125 129
126 #[inline] 130 #[inline]
127 fn differential_impl<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Derivative { 131 fn differential_impl<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Derivative {
128 self.base_fn.differential(x.own() - &self.shift) 132 self.base_fn.differential(x.own() - &self.shift)
129 } 133 }
130 } 134 }
131 135
132 impl<'a, T, F : Float, const N : usize> Support<F,N> for Shift<T,F,N> 136 impl<'a, T, F: Float, const N: usize> Support<F, N> for Shift<T, F, N>
133 where T : Support<F, N> { 137 where
134 #[inline] 138 T: Support<F, N>,
135 fn support_hint(&self) -> Cube<F,N> { 139 {
140 #[inline]
141 fn support_hint(&self) -> Cube<F, N> {
136 self.base_fn.support_hint().shift(&self.shift) 142 self.base_fn.support_hint().shift(&self.shift)
137 } 143 }
138 144
139 #[inline] 145 #[inline]
140 fn in_support(&self, x : &Loc<F,N>) -> bool { 146 fn in_support(&self, x: &Loc<F, N>) -> bool {
141 self.base_fn.in_support(&(x - &self.shift)) 147 self.base_fn.in_support(&(x - &self.shift))
142 } 148 }
143 149
144 // fn fully_in_support(&self, _cube : &Cube<F,N>) -> bool { 150 // fn fully_in_support(&self, _cube : &Cube<F,N>) -> bool {
145 // //self.base_fn.fully_in_support(cube.shift(&vectorneg(self.shift))) 151 // //self.base_fn.fully_in_support(cube.shift(&vectorneg(self.shift)))
146 // todo!("Not implemented, but not used at the moment") 152 // todo!("Not implemented, but not used at the moment")
147 // } 153 // }
148 154
149 #[inline] 155 #[inline]
150 fn bisection_hint(&self, cube : &Cube<F,N>) -> [Option<F>; N] { 156 fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] {
151 let base_hint = self.base_fn.bisection_hint(cube); 157 let base_hint = self.base_fn.bisection_hint(cube);
152 map2(base_hint, &self.shift, |h, s| h.map(|z| z + *s)) 158 map2(base_hint, &self.shift, |h, s| h.map(|z| z + *s))
153 } 159 }
154 160 }
155 } 161
156 162 impl<'a, T, F: Float, const N: usize> GlobalAnalysis<F, Bounds<F>> for Shift<T, F, N>
157 impl<'a, T, F : Float, const N : usize> GlobalAnalysis<F, Bounds<F>> for Shift<T,F,N> 163 where
158 where T : LocalAnalysis<F, Bounds<F>, N> { 164 T: LocalAnalysis<F, Bounds<F>, N>,
165 {
159 #[inline] 166 #[inline]
160 fn global_analysis(&self) -> Bounds<F> { 167 fn global_analysis(&self) -> Bounds<F> {
161 self.base_fn.global_analysis() 168 self.base_fn.global_analysis()
162 } 169 }
163 } 170 }
164 171
165 impl<'a, T, F : Float, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Shift<T,F,N> 172 impl<'a, T, F: Float, const N: usize> LocalAnalysis<F, Bounds<F>, N> for Shift<T, F, N>
166 where T : LocalAnalysis<F, Bounds<F>, N> { 173 where
167 #[inline] 174 T: LocalAnalysis<F, Bounds<F>, N>,
168 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { 175 {
176 #[inline]
177 fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> {
169 self.base_fn.local_analysis(&cube.shift(&(-self.shift))) 178 self.base_fn.local_analysis(&cube.shift(&(-self.shift)))
170 } 179 }
171 } 180 }
172 181
173 macro_rules! impl_shift_norm { 182 macro_rules! impl_shift_norm {
182 )* } 191 )* }
183 } 192 }
184 193
185 impl_shift_norm!(L1 L2 Linfinity); 194 impl_shift_norm!(L1 L2 Linfinity);
186 195
187 impl<'a, T, F : Float, C, const N : usize> Support<F,N> for Weighted<T, C> 196 impl<'a, T, F: Float, C, const N: usize> Support<F, N> for Weighted<T, C>
188 where T : Support<F, N>, 197 where
189 C : Constant<Type=F> { 198 T: Support<F, N>,
190 199 C: Constant<Type = F>,
191 #[inline] 200 {
192 fn support_hint(&self) -> Cube<F,N> { 201 #[inline]
202 fn support_hint(&self) -> Cube<F, N> {
193 self.base_fn.support_hint() 203 self.base_fn.support_hint()
194 } 204 }
195 205
196 #[inline] 206 #[inline]
197 fn in_support(&self, x : &Loc<F,N>) -> bool { 207 fn in_support(&self, x: &Loc<F, N>) -> bool {
198 self.base_fn.in_support(x) 208 self.base_fn.in_support(x)
199 } 209 }
200 210
201 // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool { 211 // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool {
202 // self.base_fn.fully_in_support(cube) 212 // self.base_fn.fully_in_support(cube)
203 // } 213 // }
204 214
205 #[inline] 215 #[inline]
206 fn bisection_hint(&self, cube : &Cube<F,N>) -> [Option<F>; N] { 216 fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] {
207 self.base_fn.bisection_hint(cube) 217 self.base_fn.bisection_hint(cube)
208 } 218 }
209 } 219 }
210 220
211 impl<'a, T, F : Float, C> GlobalAnalysis<F, Bounds<F>> for Weighted<T, C> 221 impl<'a, T, F: Float, C> GlobalAnalysis<F, Bounds<F>> for Weighted<T, C>
212 where T : GlobalAnalysis<F, Bounds<F>>, 222 where
213 C : Constant<Type=F> { 223 T: GlobalAnalysis<F, Bounds<F>>,
224 C: Constant<Type = F>,
225 {
214 #[inline] 226 #[inline]
215 fn global_analysis(&self) -> Bounds<F> { 227 fn global_analysis(&self) -> Bounds<F> {
216 let Bounds(lower, upper) = self.base_fn.global_analysis(); 228 let Bounds(lower, upper) = self.base_fn.global_analysis();
217 debug_assert!(lower <= upper); 229 debug_assert!(lower <= upper);
218 match self.weight.value() { 230 match self.weight.value() {
220 w => Bounds(w * lower, w * upper), 232 w => Bounds(w * lower, w * upper),
221 } 233 }
222 } 234 }
223 } 235 }
224 236
225 impl<'a, T, F : Float, C, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Weighted<T, C> 237 impl<'a, T, F: Float, C, const N: usize> LocalAnalysis<F, Bounds<F>, N> for Weighted<T, C>
226 where T : LocalAnalysis<F, Bounds<F>, N>, 238 where
227 C : Constant<Type=F> { 239 T: LocalAnalysis<F, Bounds<F>, N>,
228 #[inline] 240 C: Constant<Type = F>,
229 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { 241 {
242 #[inline]
243 fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> {
230 let Bounds(lower, upper) = self.base_fn.local_analysis(cube); 244 let Bounds(lower, upper) = self.base_fn.local_analysis(cube);
231 debug_assert!(lower <= upper); 245 debug_assert!(lower <= upper);
232 match self.weight.value() { 246 match self.weight.value() {
233 w if w < F::ZERO => Bounds(w * upper, w * lower), 247 w if w < F::ZERO => Bounds(w * upper, w * lower),
234 w => Bounds(w * lower, w * upper), 248 w => Bounds(w * lower, w * upper),
236 } 250 }
237 } 251 }
238 252
239 macro_rules! make_weighted_scalarop_rhs { 253 macro_rules! make_weighted_scalarop_rhs {
240 ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { 254 ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => {
241 impl<F : Float, T> std::ops::$trait_assign<F> for Weighted<T, F> { 255 impl<F: Float, T> std::ops::$trait_assign<F> for Weighted<T, F> {
242 #[inline] 256 #[inline]
243 fn $fn_assign(&mut self, t : F) { 257 fn $fn_assign(&mut self, t: F) {
244 self.weight.$fn_assign(t); 258 self.weight.$fn_assign(t);
245 } 259 }
246 } 260 }
247 261
248 impl<'a, F : Float, T> std::ops::$trait<F> for Weighted<T, F> { 262 impl<'a, F: Float, T> std::ops::$trait<F> for Weighted<T, F> {
249 type Output = Self; 263 type Output = Self;
250 #[inline] 264 #[inline]
251 fn $fn(mut self, t : F) -> Self { 265 fn $fn(mut self, t: F) -> Self {
252 self.weight.$fn_assign(t); 266 self.weight.$fn_assign(t);
253 self 267 self
254 } 268 }
255 } 269 }
256 270
257 impl<'a, F : Float, T> std::ops::$trait<F> for &'a Weighted<T, F> 271 impl<'a, F: Float, T> std::ops::$trait<F> for &'a Weighted<T, F>
258 where T : Clone { 272 where
273 T: Clone,
274 {
259 type Output = Weighted<T, F>; 275 type Output = Weighted<T, F>;
260 #[inline] 276 #[inline]
261 fn $fn(self, t : F) -> Self::Output { 277 fn $fn(self, t: F) -> Self::Output {
262 Weighted { weight : self.weight.$fn(t), base_fn : self.base_fn.clone() } 278 Weighted {
263 } 279 weight: self.weight.$fn(t),
264 } 280 base_fn: self.base_fn.clone(),
265 } 281 }
282 }
283 }
284 };
266 } 285 }
267 286
268 make_weighted_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); 287 make_weighted_scalarop_rhs!(Mul, mul, MulAssign, mul_assign);
269 make_weighted_scalarop_rhs!(Div, div, DivAssign, div_assign); 288 make_weighted_scalarop_rhs!(Div, div, DivAssign, div_assign);
270 289
279 } 298 }
280 )* } 299 )* }
281 } 300 }
282 301
283 impl_weighted_norm!(L1 L2 Linfinity); 302 impl_weighted_norm!(L1 L2 Linfinity);
284
285 303
286 /// Normalisation of [`Support`] and [`Mapping`] to L¹ norm 1. 304 /// Normalisation of [`Support`] and [`Mapping`] to L¹ norm 1.
287 /// 305 ///
288 /// Currently only scalar-valued functions are supported. 306 /// Currently only scalar-valued functions are supported.
289 #[derive(Copy, Clone, Debug, Serialize, PartialEq)] 307 #[derive(Copy, Clone, Debug, Serialize, PartialEq)]
290 pub struct Normalised<T>( 308 pub struct Normalised<T>(
291 /// The base [`Support`] or [`Mapping`]. 309 /// The base [`Support`] or [`Mapping`].
292 pub T 310 pub T,
293 ); 311 );
294 312
295 impl<'a, T, F : Float, const N : usize> Mapping<Loc<F, N>> for Normalised<T> 313 impl<'a, T, F: Float, const N: usize> Mapping<Loc<F, N>> for Normalised<T>
296 where T : Norm<F, L1> + Mapping<Loc<F,N>, Codomain=F> { 314 where
315 T: Norm<F, L1> + Mapping<Loc<F, N>, Codomain = F>,
316 {
297 type Codomain = F; 317 type Codomain = F;
298 318
299 #[inline] 319 #[inline]
300 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain { 320 fn apply<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Codomain {
301 let w = self.0.norm(L1); 321 let w = self.0.norm(L1);
302 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } 322 if w == F::ZERO {
303 } 323 F::ZERO
304 } 324 } else {
305 325 self.0.apply(x) / w
306 impl<'a, T, F : Float, const N : usize> Support<F,N> for Normalised<T> 326 }
307 where T : Norm<F, L1> + Support<F, N> { 327 }
308 328 }
309 #[inline] 329
310 fn support_hint(&self) -> Cube<F,N> { 330 impl<'a, T, F: Float, const N: usize> Support<F, N> for Normalised<T>
331 where
332 T: Norm<F, L1> + Support<F, N>,
333 {
334 #[inline]
335 fn support_hint(&self) -> Cube<F, N> {
311 self.0.support_hint() 336 self.0.support_hint()
312 } 337 }
313 338
314 #[inline] 339 #[inline]
315 fn in_support(&self, x : &Loc<F,N>) -> bool { 340 fn in_support(&self, x: &Loc<F, N>) -> bool {
316 self.0.in_support(x) 341 self.0.in_support(x)
317 } 342 }
318 343
319 // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool { 344 // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool {
320 // self.0.fully_in_support(cube) 345 // self.0.fully_in_support(cube)
321 // } 346 // }
322 347
323 #[inline] 348 #[inline]
324 fn bisection_hint(&self, cube : &Cube<F,N>) -> [Option<F>; N] { 349 fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] {
325 self.0.bisection_hint(cube) 350 self.0.bisection_hint(cube)
326 } 351 }
327 } 352 }
328 353
329 impl<'a, T, F : Float> GlobalAnalysis<F, Bounds<F>> for Normalised<T> 354 impl<'a, T, F: Float> GlobalAnalysis<F, Bounds<F>> for Normalised<T>
330 where T : Norm<F, L1> + GlobalAnalysis<F, Bounds<F>> { 355 where
356 T: Norm<F, L1> + GlobalAnalysis<F, Bounds<F>>,
357 {
331 #[inline] 358 #[inline]
332 fn global_analysis(&self) -> Bounds<F> { 359 fn global_analysis(&self) -> Bounds<F> {
333 let Bounds(lower, upper) = self.0.global_analysis(); 360 let Bounds(lower, upper) = self.0.global_analysis();
334 debug_assert!(lower <= upper); 361 debug_assert!(lower <= upper);
335 let w = self.0.norm(L1); 362 let w = self.0.norm(L1);
336 debug_assert!(w >= F::ZERO); 363 debug_assert!(w >= F::ZERO);
337 Bounds(w * lower, w * upper) 364 Bounds(w * lower, w * upper)
338 } 365 }
339 } 366 }
340 367
341 impl<'a, T, F : Float, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Normalised<T> 368 impl<'a, T, F: Float, const N: usize> LocalAnalysis<F, Bounds<F>, N> for Normalised<T>
342 where T : Norm<F, L1> + LocalAnalysis<F, Bounds<F>, N> { 369 where
343 #[inline] 370 T: Norm<F, L1> + LocalAnalysis<F, Bounds<F>, N>,
344 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { 371 {
372 #[inline]
373 fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> {
345 let Bounds(lower, upper) = self.0.local_analysis(cube); 374 let Bounds(lower, upper) = self.0.local_analysis(cube);
346 debug_assert!(lower <= upper); 375 debug_assert!(lower <= upper);
347 let w = self.0.norm(L1); 376 let w = self.0.norm(L1);
348 debug_assert!(w >= F::ZERO); 377 debug_assert!(w >= F::ZERO);
349 Bounds(w * lower, w * upper) 378 Bounds(w * lower, w * upper)
350 } 379 }
351 } 380 }
352 381
353 impl<'a, T, F : Float> Norm<F, L1> for Normalised<T> 382 impl<'a, T, F: Float> Norm<F, L1> for Normalised<T>
354 where T : Norm<F, L1> { 383 where
355 #[inline] 384 T: Norm<F, L1>,
356 fn norm(&self, _ : L1) -> F { 385 {
386 #[inline]
387 fn norm(&self, _: L1) -> F {
357 let w = self.0.norm(L1); 388 let w = self.0.norm(L1);
358 if w == F::ZERO { F::ZERO } else { F::ONE } 389 if w == F::ZERO {
390 F::ZERO
391 } else {
392 F::ONE
393 }
359 } 394 }
360 } 395 }
361 396
362 macro_rules! impl_normalised_norm { 397 macro_rules! impl_normalised_norm {
363 ($($norm:ident)*) => { $( 398 ($($norm:ident)*) => { $(
386 } 421 }
387 }*/ 422 }*/
388 423
389 /// Generator of [`Support`]-implementing component functions based on low storage requirement 424 /// Generator of [`Support`]-implementing component functions based on low storage requirement
390 /// [ids][`Self::Id`]. 425 /// [ids][`Self::Id`].
391 pub trait SupportGenerator<F : Float, const N : usize> 426 pub trait SupportGenerator<F: Float, const N: usize>:
392 : MulAssign<F> + DivAssign<F> + Neg<Output=Self> + Clone + Sync + Send + 'static { 427 MulAssign<F> + DivAssign<F> + Neg<Output = Self> + Clone + Sync + Send + 'static
428 {
393 /// The identification type 429 /// The identification type
394 type Id : 'static + Copy; 430 type Id: 'static + Copy;
395 /// The type of the [`Support`] (often also a [`Mapping`]). 431 /// The type of the [`Support`] (often also a [`Mapping`]).
396 type SupportType : 'static + Support<F, N>; 432 type SupportType: 'static + Support<F, N>;
397 /// An iterator over all the [`Support`]s of the generator. 433 /// An iterator over all the [`Support`]s of the generator.
398 type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a; 434 type AllDataIter<'a>: Iterator<Item = (Self::Id, Self::SupportType)>
435 where
436 Self: 'a;
399 437
400 /// Returns the component identified by `id`. 438 /// Returns the component identified by `id`.
401 /// 439 ///
402 /// Panics if `id` is an invalid identifier. 440 /// Panics if `id` is an invalid identifier.
403 fn support_for(&self, id : Self::Id) -> Self::SupportType; 441 fn support_for(&self, id: Self::Id) -> Self::SupportType;
404 442
405 /// Returns the number of different components in this generator. 443 /// Returns the number of different components in this generator.
406 fn support_count(&self) -> usize; 444 fn support_count(&self) -> usize;
407 445
408 /// Returns an iterator over all pairs of `(id, support)`. 446 /// Returns an iterator over all pairs of `(id, support)`.
409 fn all_data(&self) -> Self::AllDataIter<'_>; 447 fn all_data(&self) -> Self::AllDataIter<'_>;
410 } 448 }
411

mercurial