| 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 |
|