| 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() { |
| 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 |
|