src/bisection_tree/support.rs

branch
dev
changeset 124
6aa955ad8122
parent 97
4e80fb049dca
child 150
c4e394a9c84c
equal deleted inserted replaced
122:495448cca603 124:6aa955ad8122
14 use std::ops::{DivAssign, MulAssign, Neg}; 14 use std::ops::{DivAssign, MulAssign, Neg};
15 15
16 /// A trait for working with the supports of [`Mapping`]s. 16 /// A trait for working with the supports of [`Mapping`]s.
17 /// 17 ///
18 /// `Mapping` is not a super-trait to allow more general use. 18 /// `Mapping` is not a super-trait to allow more general use.
19 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 {
20 /// 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`.
21 /// 21 ///
22 /// 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.
23 fn support_hint(&self) -> Cube<F, N>; 23 fn support_hint(&self) -> Cube<N, F>;
24 24
25 /// 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`.
26 fn in_support(&self, x: &Loc<F, N>) -> bool; 26 fn in_support(&self, x: &Loc<N, F>) -> bool;
27 27
28 // 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`.
29 //fn fully_in_support(&self, cube : &Cube<F,N>) -> bool; 29 //fn fully_in_support(&self, cube : &Cube<F,N>) -> bool;
30 30
31 /// Return an optional hint for bisecting the support. 31 /// Return an optional hint for bisecting the support.
37 /// non-differentiability. 37 /// non-differentiability.
38 /// 38 ///
39 /// The default implementation returns `[None; N]`. 39 /// The default implementation returns `[None; N]`.
40 #[inline] 40 #[inline]
41 #[allow(unused_variables)] 41 #[allow(unused_variables)]
42 fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] { 42 fn bisection_hint(&self, cube: &Cube<N, F>) -> [Option<F>; N] {
43 [None; N] 43 [None; N]
44 } 44 }
45 45
46 /// Translate `self` by `x`. 46 /// Translate `self` by `x`.
47 #[inline] 47 #[inline]
48 fn shift(self, x: Loc<F, N>) -> Shift<Self, F, N> { 48 fn shift(self, x: Loc<N, F>) -> Shift<Self, N, F> {
49 Shift { 49 Shift {
50 shift: x, 50 shift: x,
51 base_fn: self, 51 base_fn: self,
52 } 52 }
53 } 53 }
54 } 54 }
55 55
56 /// Shift of [`Support`] and [`Mapping`]; output of [`Support::shift`]. 56 /// Shift of [`Support`] and [`Mapping`]; output of [`Support::shift`].
57 #[derive(Copy, Clone, Debug, Serialize)] // Serialize! but not implemented by Loc. 57 #[derive(Copy, Clone, Debug, Serialize)] // Serialize! but not implemented by Loc.
58 pub struct Shift<T, F, const N: usize> { 58 pub struct Shift<T, const N: usize, F = f64> {
59 shift: Loc<F, N>, 59 shift: Loc<N, F>,
60 base_fn: T, 60 base_fn: T,
61 } 61 }
62 62
63 impl<'a, T, V: Space, F: Float, const N: usize> Mapping<Loc<F, N>> for Shift<T, F, N> 63 impl<'a, T, V: Space, F: Float, const N: usize> Mapping<Loc<N, F>> for Shift<T, N, F>
64 where 64 where
65 T: Mapping<Loc<F, N>, Codomain = V>, 65 T: Mapping<Loc<N, F>, Codomain = V>,
66 { 66 {
67 type Codomain = V; 67 type Codomain = V;
68 68
69 #[inline] 69 #[inline]
70 fn apply<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Codomain { 70 fn apply<I: Instance<Loc<N, F>>>(&self, x: I) -> Self::Codomain {
71 self.base_fn.apply(x.own() - &self.shift) 71 self.base_fn.apply(x.own() - &self.shift)
72 } 72 }
73 } 73 }
74 74
75 impl<'a, T, V: Space, F: Float, const N: usize> DifferentiableImpl<Loc<F, N>> for Shift<T, F, N> 75 impl<'a, T, V: Space, F: Float, const N: usize> DifferentiableImpl<Loc<N, F>> for Shift<T, N, F>
76 where 76 where
77 T: DifferentiableMapping<Loc<F, N>, DerivativeDomain = V>, 77 T: DifferentiableMapping<Loc<N, F>, DerivativeDomain = V>,
78 { 78 {
79 type Derivative = V; 79 type Derivative = V;
80 80
81 #[inline] 81 #[inline]
82 fn differential_impl<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Derivative { 82 fn differential_impl<I: Instance<Loc<N, F>>>(&self, x: I) -> Self::Derivative {
83 self.base_fn.differential(x.own() - &self.shift) 83 self.base_fn.differential(x.own() - &self.shift)
84 } 84 }
85 } 85 }
86 86
87 impl<'a, T, F: Float, const N: usize> Support<F, N> for Shift<T, F, N> 87 impl<'a, T, F: Float, const N: usize> Support<N, F> for Shift<T, N, F>
88 where 88 where
89 T: Support<F, N>, 89 T: Support<N, F>,
90 { 90 {
91 #[inline] 91 #[inline]
92 fn support_hint(&self) -> Cube<F, N> { 92 fn support_hint(&self) -> Cube<N, F> {
93 self.base_fn.support_hint().shift(&self.shift) 93 self.base_fn.support_hint().shift(&self.shift)
94 } 94 }
95 95
96 #[inline] 96 #[inline]
97 fn in_support(&self, x: &Loc<F, N>) -> bool { 97 fn in_support(&self, x: &Loc<N, F>) -> bool {
98 self.base_fn.in_support(&(x - &self.shift)) 98 self.base_fn.in_support(&(x - &self.shift))
99 } 99 }
100 100
101 // fn fully_in_support(&self, _cube : &Cube<F,N>) -> bool { 101 // fn fully_in_support(&self, _cube : &Cube<F,N>) -> bool {
102 // //self.base_fn.fully_in_support(cube.shift(&vectorneg(self.shift))) 102 // //self.base_fn.fully_in_support(cube.shift(&vectorneg(self.shift)))
103 // todo!("Not implemented, but not used at the moment") 103 // todo!("Not implemented, but not used at the moment")
104 // } 104 // }
105 105
106 #[inline] 106 #[inline]
107 fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] { 107 fn bisection_hint(&self, cube: &Cube<N, F>) -> [Option<F>; N] {
108 let base_hint = self.base_fn.bisection_hint(cube); 108 let base_hint = self.base_fn.bisection_hint(cube);
109 map2(base_hint, &self.shift, |h, s| h.map(|z| z + *s)) 109 map2(base_hint, &self.shift, |h, s| h.map(|z| z + *s))
110 } 110 }
111 } 111 }
112 112
113 impl<'a, T, F: Float, const N: usize> GlobalAnalysis<F, Bounds<F>> for Shift<T, F, N> 113 impl<'a, T, F: Float, const N: usize> GlobalAnalysis<F, Bounds<F>> for Shift<T, N, F>
114 where 114 where
115 T: LocalAnalysis<F, Bounds<F>, N>, 115 T: LocalAnalysis<F, Bounds<F>, N>,
116 { 116 {
117 #[inline] 117 #[inline]
118 fn global_analysis(&self) -> Bounds<F> { 118 fn global_analysis(&self) -> Bounds<F> {
119 self.base_fn.global_analysis() 119 self.base_fn.global_analysis()
120 } 120 }
121 } 121 }
122 122
123 impl<'a, T, F: Float, const N: usize> LocalAnalysis<F, Bounds<F>, N> for Shift<T, F, N> 123 impl<'a, T, F: Float, const N: usize> LocalAnalysis<F, Bounds<F>, N> for Shift<T, N, F>
124 where 124 where
125 T: LocalAnalysis<F, Bounds<F>, N>, 125 T: LocalAnalysis<F, Bounds<F>, N>,
126 { 126 {
127 #[inline] 127 #[inline]
128 fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> { 128 fn local_analysis(&self, cube: &Cube<N, F>) -> Bounds<F> {
129 self.base_fn.local_analysis(&cube.shift(&(-self.shift))) 129 self.base_fn.local_analysis(&cube.shift(&(-self.shift)))
130 } 130 }
131 } 131 }
132 132
133 macro_rules! impl_shift_norm { 133 macro_rules! impl_shift_norm {
134 ($($norm:ident)*) => { $( 134 ($($norm:ident)*) => { $(
135 impl<'a, T, F : Float, const N : usize> Norm<F, $norm> for Shift<T,F,N> 135 impl<'a, T, F : Float, const N : usize> Norm<$norm, F> for Shift<T, N, F>
136 where T : Norm<F, $norm> { 136 where T : Norm<$norm, F> {
137 #[inline] 137 #[inline]
138 fn norm(&self, n : $norm) -> F { 138 fn norm(&self, n : $norm) -> F {
139 self.base_fn.norm(n) 139 self.base_fn.norm(n)
140 } 140 }
141 } 141 }
142 )* } 142 )* }
143 } 143 }
144 144
145 impl_shift_norm!(L1 L2 Linfinity); 145 impl_shift_norm!(L1 L2 Linfinity);
146 146
147 impl<'a, T, F: Float, C, const N: usize> Support<F, N> for Weighted<T, C> 147 impl<'a, T, F: Float, C, const N: usize> Support<N, F> for Weighted<T, C>
148 where 148 where
149 T: Support<F, N>, 149 T: Support<N, F>,
150 C: Constant<Type = F>, 150 C: Constant<Type = F>,
151 { 151 {
152 #[inline] 152 #[inline]
153 fn support_hint(&self) -> Cube<F, N> { 153 fn support_hint(&self) -> Cube<N, F> {
154 self.base_fn.support_hint() 154 self.base_fn.support_hint()
155 } 155 }
156 156
157 #[inline] 157 #[inline]
158 fn in_support(&self, x: &Loc<F, N>) -> bool { 158 fn in_support(&self, x: &Loc<N, F>) -> bool {
159 self.base_fn.in_support(x) 159 self.base_fn.in_support(x)
160 } 160 }
161 161
162 // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool { 162 // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool {
163 // self.base_fn.fully_in_support(cube) 163 // self.base_fn.fully_in_support(cube)
164 // } 164 // }
165 165
166 #[inline] 166 #[inline]
167 fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] { 167 fn bisection_hint(&self, cube: &Cube<N, F>) -> [Option<F>; N] {
168 self.base_fn.bisection_hint(cube) 168 self.base_fn.bisection_hint(cube)
169 } 169 }
170 } 170 }
171 171
172 impl<'a, T, F: Float, C> GlobalAnalysis<F, Bounds<F>> for Weighted<T, C> 172 impl<'a, T, F: Float, C> GlobalAnalysis<F, Bounds<F>> for Weighted<T, C>
189 where 189 where
190 T: LocalAnalysis<F, Bounds<F>, N>, 190 T: LocalAnalysis<F, Bounds<F>, N>,
191 C: Constant<Type = F>, 191 C: Constant<Type = F>,
192 { 192 {
193 #[inline] 193 #[inline]
194 fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> { 194 fn local_analysis(&self, cube: &Cube<N, F>) -> Bounds<F> {
195 let Bounds(lower, upper) = self.base_fn.local_analysis(cube); 195 let Bounds(lower, upper) = self.base_fn.local_analysis(cube);
196 debug_assert!(lower <= upper); 196 debug_assert!(lower <= upper);
197 match self.weight.value() { 197 match self.weight.value() {
198 w if w < F::ZERO => Bounds(w * upper, w * lower), 198 w if w < F::ZERO => Bounds(w * upper, w * lower),
199 w => Bounds(w * lower, w * upper), 199 w => Bounds(w * lower, w * upper),
238 make_weighted_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); 238 make_weighted_scalarop_rhs!(Mul, mul, MulAssign, mul_assign);
239 make_weighted_scalarop_rhs!(Div, div, DivAssign, div_assign); 239 make_weighted_scalarop_rhs!(Div, div, DivAssign, div_assign);
240 240
241 macro_rules! impl_weighted_norm { 241 macro_rules! impl_weighted_norm {
242 ($($norm:ident)*) => { $( 242 ($($norm:ident)*) => { $(
243 impl<'a, T, F : Float> Norm<F, $norm> for Weighted<T,F> 243 impl<'a, T, F : Float> Norm<$norm, F> for Weighted<T,F>
244 where T : Norm<F, $norm> { 244 where T : Norm<$norm, F> {
245 #[inline] 245 #[inline]
246 fn norm(&self, n : $norm) -> F { 246 fn norm(&self, n : $norm) -> F {
247 self.base_fn.norm(n) * self.weight.abs() 247 self.base_fn.norm(n) * self.weight.abs()
248 } 248 }
249 } 249 }
259 pub struct Normalised<T>( 259 pub struct Normalised<T>(
260 /// The base [`Support`] or [`Mapping`]. 260 /// The base [`Support`] or [`Mapping`].
261 pub T, 261 pub T,
262 ); 262 );
263 263
264 impl<'a, T, F: Float, const N: usize> Mapping<Loc<F, N>> for Normalised<T> 264 impl<'a, T, F: Float, const N: usize> Mapping<Loc<N, F>> for Normalised<T>
265 where 265 where
266 T: Norm<F, L1> + Mapping<Loc<F, N>, Codomain = F>, 266 T: Norm<L1, F> + Mapping<Loc<N, F>, Codomain = F>,
267 { 267 {
268 type Codomain = F; 268 type Codomain = F;
269 269
270 #[inline] 270 #[inline]
271 fn apply<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Codomain { 271 fn apply<I: Instance<Loc<N, F>>>(&self, x: I) -> Self::Codomain {
272 let w = self.0.norm(L1); 272 let w = self.0.norm(L1);
273 if w == F::ZERO { 273 if w == F::ZERO {
274 F::ZERO 274 F::ZERO
275 } else { 275 } else {
276 self.0.apply(x) / w 276 self.0.apply(x) / w
277 } 277 }
278 } 278 }
279 } 279 }
280 280
281 impl<'a, T, F: Float, const N: usize> Support<F, N> for Normalised<T> 281 impl<'a, T, F: Float, const N: usize> Support<N, F> for Normalised<T>
282 where 282 where
283 T: Norm<F, L1> + Support<F, N>, 283 T: Norm<L1, F> + Support<N, F>,
284 { 284 {
285 #[inline] 285 #[inline]
286 fn support_hint(&self) -> Cube<F, N> { 286 fn support_hint(&self) -> Cube<N, F> {
287 self.0.support_hint() 287 self.0.support_hint()
288 } 288 }
289 289
290 #[inline] 290 #[inline]
291 fn in_support(&self, x: &Loc<F, N>) -> bool { 291 fn in_support(&self, x: &Loc<N, F>) -> bool {
292 self.0.in_support(x) 292 self.0.in_support(x)
293 } 293 }
294 294
295 // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool { 295 // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool {
296 // self.0.fully_in_support(cube) 296 // self.0.fully_in_support(cube)
297 // } 297 // }
298 298
299 #[inline] 299 #[inline]
300 fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] { 300 fn bisection_hint(&self, cube: &Cube<N, F>) -> [Option<F>; N] {
301 self.0.bisection_hint(cube) 301 self.0.bisection_hint(cube)
302 } 302 }
303 } 303 }
304 304
305 impl<'a, T, F: Float> GlobalAnalysis<F, Bounds<F>> for Normalised<T> 305 impl<'a, T, F: Float> GlobalAnalysis<F, Bounds<F>> for Normalised<T>
306 where 306 where
307 T: Norm<F, L1> + GlobalAnalysis<F, Bounds<F>>, 307 T: Norm<L1, F> + GlobalAnalysis<F, Bounds<F>>,
308 { 308 {
309 #[inline] 309 #[inline]
310 fn global_analysis(&self) -> Bounds<F> { 310 fn global_analysis(&self) -> Bounds<F> {
311 let Bounds(lower, upper) = self.0.global_analysis(); 311 let Bounds(lower, upper) = self.0.global_analysis();
312 debug_assert!(lower <= upper); 312 debug_assert!(lower <= upper);
316 } 316 }
317 } 317 }
318 318
319 impl<'a, T, F: Float, const N: usize> LocalAnalysis<F, Bounds<F>, N> for Normalised<T> 319 impl<'a, T, F: Float, const N: usize> LocalAnalysis<F, Bounds<F>, N> for Normalised<T>
320 where 320 where
321 T: Norm<F, L1> + LocalAnalysis<F, Bounds<F>, N>, 321 T: Norm<L1, F> + LocalAnalysis<F, Bounds<F>, N>,
322 { 322 {
323 #[inline] 323 #[inline]
324 fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> { 324 fn local_analysis(&self, cube: &Cube<N, F>) -> Bounds<F> {
325 let Bounds(lower, upper) = self.0.local_analysis(cube); 325 let Bounds(lower, upper) = self.0.local_analysis(cube);
326 debug_assert!(lower <= upper); 326 debug_assert!(lower <= upper);
327 let w = self.0.norm(L1); 327 let w = self.0.norm(L1);
328 debug_assert!(w >= F::ZERO); 328 debug_assert!(w >= F::ZERO);
329 Bounds(w * lower, w * upper) 329 Bounds(w * lower, w * upper)
330 } 330 }
331 } 331 }
332 332
333 impl<'a, T, F: Float> Norm<F, L1> for Normalised<T> 333 impl<'a, T, F: Float> Norm<L1, F> for Normalised<T>
334 where 334 where
335 T: Norm<F, L1>, 335 T: Norm<L1, F>,
336 { 336 {
337 #[inline] 337 #[inline]
338 fn norm(&self, _: L1) -> F { 338 fn norm(&self, _: L1) -> F {
339 let w = self.0.norm(L1); 339 let w = self.0.norm(L1);
340 if w == F::ZERO { 340 if w == F::ZERO {
345 } 345 }
346 } 346 }
347 347
348 macro_rules! impl_normalised_norm { 348 macro_rules! impl_normalised_norm {
349 ($($norm:ident)*) => { $( 349 ($($norm:ident)*) => { $(
350 impl<'a, T, F : Float> Norm<F, $norm> for Normalised<T> 350 impl<'a, T, F : Float> Norm<$norm, F> for Normalised<T>
351 where T : Norm<F, $norm> + Norm<F, L1> { 351 where T : Norm<$norm, F> + Norm<L1, F> {
352 #[inline] 352 #[inline]
353 fn norm(&self, n : $norm) -> F { 353 fn norm(&self, n : $norm) -> F {
354 let w = self.0.norm(L1); 354 let w = self.0.norm(L1);
355 if w == F::ZERO { F::ZERO } else { self.0.norm(n) / w } 355 if w == F::ZERO { F::ZERO } else { self.0.norm(n) / w }
356 } 356 }
359 } 359 }
360 360
361 impl_normalised_norm!(L2 Linfinity); 361 impl_normalised_norm!(L2 Linfinity);
362 362
363 /* 363 /*
364 impl<F : Num, S : Support<F, N>, const N : usize> LocalAnalysis<F, NullAggregator, N> for S { 364 impl<F : Num, S : Support< N, F>, const N : usize> LocalAnalysis<F, NullAggregator, N> for S {
365 fn local_analysis(&self, _cube : &Cube<F, N>) -> NullAggregator { NullAggregator } 365 fn local_analysis(&self, _cube : &Cube<N, F>) -> NullAggregator { NullAggregator }
366 } 366 }
367 367
368 impl<F : Float, S : Bounded<F>, const N : usize> LocalAnalysis<F, Bounds<F>, N> for S { 368 impl<F : Float, S : Bounded<F>, const N : usize> LocalAnalysis<F, Bounds<F>, N> for S {
369 #[inline] 369 #[inline]
370 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { 370 fn local_analysis(&self, cube : &Cube<N, F>) -> Bounds<F> {
371 self.bounds(cube) 371 self.bounds(cube)
372 } 372 }
373 }*/ 373 }*/
374 374
375 /// Generator of [`Support`]-implementing component functions based on low storage requirement 375 /// Generator of [`Support`]-implementing component functions based on low storage requirement
376 /// [ids][`Self::Id`]. 376 /// [ids][`Self::Id`].
377 pub trait SupportGenerator<F: Float, const N: usize>: 377 pub trait SupportGenerator<const N: usize, F: Float = f64>:
378 MulAssign<F> + DivAssign<F> + Neg<Output = Self> + Clone + Sync + Send + 'static 378 MulAssign<F> + DivAssign<F> + Neg<Output = Self> + Clone + Sync + Send + 'static
379 { 379 {
380 /// The identification type 380 /// The identification type
381 type Id: 'static + Copy; 381 type Id: 'static + Copy;
382 /// The type of the [`Support`] (often also a [`Mapping`]). 382 /// The type of the [`Support`] (often also a [`Mapping`]).
383 type SupportType: 'static + Support<F, N>; 383 type SupportType: 'static + Support<N, F>;
384 /// An iterator over all the [`Support`]s of the generator. 384 /// An iterator over all the [`Support`]s of the generator.
385 type AllDataIter<'a>: Iterator<Item = (Self::Id, Self::SupportType)> 385 type AllDataIter<'a>: Iterator<Item = (Self::Id, Self::SupportType)>
386 where 386 where
387 Self: 'a; 387 Self: 'a;
388 388

mercurial