src/bisection_tree/support.rs

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

mercurial