src/bisection_tree/support.rs

changeset 90
b3c35d16affe
parent 75
e9f4550cfa18
child 86
d5b0e496b72f
equal deleted inserted replaced
25:d14c877e14b7 90:b3c35d16affe
1 1
2 /*! 2 /*!
3 Traits for representing the support of a [`Apply`], and analysing the mapping on a [`Cube`]. 3 Traits for representing the support of a [`Mapping`], and analysing the mapping on a [`Cube`].
4 */ 4 */
5 use serde::Serialize; 5 use serde::Serialize;
6 use std::ops::{MulAssign,DivAssign,Neg}; 6 use std::ops::{MulAssign,DivAssign,Neg};
7 use crate::types::{Float, Num}; 7 use crate::types::{Float, Num};
8 use crate::maputil::map2; 8 use crate::maputil::map2;
9 use crate::mapping::Apply; 9 use crate::mapping::{
10 Instance, Mapping, DifferentiableImpl, DifferentiableMapping, Space
11 };
10 use crate::sets::Cube; 12 use crate::sets::Cube;
11 use crate::loc::Loc; 13 use crate::loc::Loc;
12 use super::aggregator::Bounds; 14 use super::aggregator::Bounds;
13 use crate::norms::{Norm, L1, L2, Linfinity}; 15 use crate::norms::{Norm, L1, L2, Linfinity};
14 16 pub use crate::operator_arithmetic::{Weighted, Constant};
15 /// A trait for encoding constant [`Float`] values 17
16 pub trait Constant : Copy + Sync + Send + 'static + std::fmt::Debug + Into<Self::Type> { 18 /// A trait for working with the supports of [`Mapping`]s.
17 /// The type of the value
18 type Type : Float;
19 /// Returns the value of the constant
20 fn value(&self) -> Self::Type;
21 }
22
23 impl<F : Float> Constant for F {
24 type Type = F;
25 #[inline]
26 fn value(&self) -> F { *self }
27 }
28
29
30 /// A trait for working with the supports of [`Apply`]s.
31 /// 19 ///
32 /// Apply is not a super-trait to allow more general use. 20 /// `Mapping` is not a super-trait to allow more general use.
33 pub trait Support<F : Num, const N : usize> : Sized + Sync + Send + 'static { 21 pub trait Support<F : Num, const N : usize> : Sized + Sync + Send + 'static {
34 /// Return a cube containing the support of the function represented by `self`. 22 /// Return a cube containing the support of the function represented by `self`.
35 /// 23 ///
36 /// The hint may be larger than the actual support, but must contain it. 24 /// The hint may be larger than the actual support, but must contain it.
37 fn support_hint(&self) -> Cube<F,N>; 25 fn support_hint(&self) -> Cube<F,N>;
60 /// Translate `self` by `x`. 48 /// Translate `self` by `x`.
61 #[inline] 49 #[inline]
62 fn shift(self, x : Loc<F, N>) -> Shift<Self, F, N> { 50 fn shift(self, x : Loc<F, N>) -> Shift<Self, F, N> {
63 Shift { shift : x, base_fn : self } 51 Shift { shift : x, base_fn : self }
64 } 52 }
65 53 }
66 /// Multiply `self` by the scalar `a`. 54
67 #[inline] 55 /// Trait for globally analysing a property `A` of a [`Mapping`].
68 fn weigh<C : Constant<Type=F>>(self, a : C) -> Weighted<Self, C> {
69 Weighted { weight : a, base_fn : self }
70 }
71 }
72
73 /// Trait for globally analysing a property `A` of a [`Apply`].
74 /// 56 ///
75 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as 57 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as
76 /// [`Bounds`][super::aggregator::Bounds]. 58 /// [`Bounds`][super::aggregator::Bounds].
77 pub trait GlobalAnalysis<F : Num, A> { 59 pub trait GlobalAnalysis<F : Num, A> {
78 /// Perform global analysis of the property `A` of `Self`. 60 /// Perform global analysis of the property `A` of `Self`.
89 // fn global_analysis(&self) -> Bounds<F> { 71 // fn global_analysis(&self) -> Bounds<F> {
90 // self.local_analysis(&self.support_hint()) 72 // self.local_analysis(&self.support_hint())
91 // } 73 // }
92 // } 74 // }
93 75
94 /// Trait for locally analysing a property `A` of a [`Apply`] (implementing [`Support`]) 76 /// Trait for locally analysing a property `A` of a [`Mapping`] (implementing [`Support`])
95 /// within a [`Cube`]. 77 /// within a [`Cube`].
96 /// 78 ///
97 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as 79 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as
98 /// [`Bounds`][super::aggregator::Bounds]. 80 /// [`Bounds`][super::aggregator::Bounds].
99 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> {
103 /// 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
104 /// represented by `self`. 86 /// represented by `self`.
105 fn local_analysis(&self, cube : &Cube<F, N>) -> A; 87 fn local_analysis(&self, cube : &Cube<F, N>) -> A;
106 } 88 }
107 89
108 /// Trait for determining the upper and lower bounds of an float-valued [`Apply`]. 90 /// Trait for determining the upper and lower bounds of an float-valued [`Mapping`].
109 /// 91 ///
110 /// This is a blanket-implemented alias for [`GlobalAnalysis`]`<F, Bounds<F>>` 92 /// This is a blanket-implemented alias for [`GlobalAnalysis`]`<F, Bounds<F>>`
111 /// [`Apply`] 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
112 /// reference or non-reference arguments. 94 /// reference or non-reference arguments.
113 pub trait Bounded<F : Float> : GlobalAnalysis<F, Bounds<F>> { 95 pub trait Bounded<F : Float> : GlobalAnalysis<F, Bounds<F>> {
114 /// Return lower and upper bounds for the values of of `self`. 96 /// Return lower and upper bounds for the values of of `self`.
115 #[inline] 97 #[inline]
116 fn bounds(&self) -> Bounds<F> { 98 fn bounds(&self) -> Bounds<F> {
118 } 100 }
119 } 101 }
120 102
121 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 { }
122 104
123 /// Shift of [`Support`] and [`Apply`]; output of [`Support::shift`]. 105 /// Shift of [`Support`] and [`Mapping`]; output of [`Support::shift`].
124 #[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc. 106 #[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc.
125 pub struct Shift<T, F, const N : usize> { 107 pub struct Shift<T, F, const N : usize> {
126 shift : Loc<F, N>, 108 shift : Loc<F, N>,
127 base_fn : T, 109 base_fn : T,
128 } 110 }
129 111
130 impl<'a, T, V, F : Float, const N : usize> Apply<&'a 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>
131 where T : Apply<Loc<F, N>, Output=V> { 113 where T : Mapping<Loc<F, N>, Codomain=V> {
132 type Output = V; 114 type Codomain = V;
133 #[inline] 115
134 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { 116 #[inline]
135 self.base_fn.apply(x - &self.shift) 117 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain {
136 } 118 self.base_fn.apply(x.own() - &self.shift)
137 } 119 }
138 120 }
139 impl<'a, T, V, F : Float, const N : usize> Apply<Loc<F, N>> for Shift<T,F,N> 121
140 where T : Apply<Loc<F, N>, Output=V> { 122 impl<'a, T, V : Space, F : Float, const N : usize> DifferentiableImpl<Loc<F, N>> for Shift<T,F,N>
141 type Output = V; 123 where T : DifferentiableMapping<Loc<F, N>, DerivativeDomain=V> {
142 #[inline] 124 type Derivative = V;
143 fn apply(&self, x : Loc<F, N>) -> Self::Output { 125
144 self.base_fn.apply(x - &self.shift) 126 #[inline]
127 fn differential_impl<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Derivative {
128 self.base_fn.differential(x.own() - &self.shift)
145 } 129 }
146 } 130 }
147 131
148 impl<'a, T, F : Float, const N : usize> Support<F,N> for Shift<T,F,N> 132 impl<'a, T, F : Float, const N : usize> Support<F,N> for Shift<T,F,N>
149 where T : Support<F, N> { 133 where T : Support<F, N> {
197 } 181 }
198 )* } 182 )* }
199 } 183 }
200 184
201 impl_shift_norm!(L1 L2 Linfinity); 185 impl_shift_norm!(L1 L2 Linfinity);
202
203 /// Weighting of a [`Support`] and [`Apply`] by scalar multiplication;
204 /// output of [`Support::weigh`].
205 #[derive(Copy,Clone,Debug,Serialize)]
206 pub struct Weighted<T, C : Constant> {
207 /// The weight
208 pub weight : C,
209 /// The base [`Support`] or [`Apply`] being weighted.
210 pub base_fn : T,
211 }
212
213 impl<'a, T, V, F : Float, C, const N : usize> Apply<&'a Loc<F, N>> for Weighted<T, C>
214 where T : for<'b> Apply<&'b Loc<F, N>, Output=V>,
215 V : std::ops::Mul<F,Output=V>,
216 C : Constant<Type=F> {
217 type Output = V;
218 #[inline]
219 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output {
220 self.base_fn.apply(x) * self.weight.value()
221 }
222 }
223
224 impl<'a, T, V, F : Float, C, const N : usize> Apply<Loc<F, N>> for Weighted<T, C>
225 where T : Apply<Loc<F, N>, Output=V>,
226 V : std::ops::Mul<F,Output=V>,
227 C : Constant<Type=F> {
228 type Output = V;
229 #[inline]
230 fn apply(&self, x : Loc<F, N>) -> Self::Output {
231 self.base_fn.apply(x) * self.weight.value()
232 }
233 }
234 186
235 impl<'a, T, F : Float, C, const N : usize> Support<F,N> for Weighted<T, C> 187 impl<'a, T, F : Float, C, const N : usize> Support<F,N> for Weighted<T, C>
236 where T : Support<F, N>, 188 where T : Support<F, N>,
237 C : Constant<Type=F> { 189 C : Constant<Type=F> {
238 190
329 } 281 }
330 282
331 impl_weighted_norm!(L1 L2 Linfinity); 283 impl_weighted_norm!(L1 L2 Linfinity);
332 284
333 285
334 /// Normalisation of [`Support`] and [`Apply`] to L¹ norm 1. 286 /// Normalisation of [`Support`] and [`Mapping`] to L¹ norm 1.
335 /// 287 ///
336 /// Currently only scalar-valued functions are supported. 288 /// Currently only scalar-valued functions are supported.
337 #[derive(Copy, Clone, Debug, Serialize, PartialEq)] 289 #[derive(Copy, Clone, Debug, Serialize, PartialEq)]
338 pub struct Normalised<T>( 290 pub struct Normalised<T>(
339 /// The base [`Support`] or [`Apply`]. 291 /// The base [`Support`] or [`Mapping`].
340 pub T 292 pub T
341 ); 293 );
342 294
343 impl<'a, T, F : Float, const N : usize> Apply<&'a Loc<F, N>> for Normalised<T> 295 impl<'a, T, F : Float, const N : usize> Mapping<Loc<F, N>> for Normalised<T>
344 where T : Norm<F, L1> + for<'b> Apply<&'b Loc<F, N>, Output=F> { 296 where T : Norm<F, L1> + Mapping<Loc<F,N>, Codomain=F> {
345 type Output = F; 297 type Codomain = F;
346 #[inline] 298
347 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { 299 #[inline]
348 let w = self.0.norm(L1); 300 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain {
349 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w }
350 }
351 }
352
353 impl<'a, T, F : Float, const N : usize> Apply<Loc<F, N>> for Normalised<T>
354 where T : Norm<F, L1> + Apply<Loc<F,N>, Output=F> {
355 type Output = F;
356 #[inline]
357 fn apply(&self, x : Loc<F, N>) -> Self::Output {
358 let w = self.0.norm(L1); 301 let w = self.0.norm(L1);
359 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w } 302 if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w }
360 } 303 }
361 } 304 }
362 305
447 /// [ids][`Self::Id`]. 390 /// [ids][`Self::Id`].
448 pub trait SupportGenerator<F : Float, const N : usize> 391 pub trait SupportGenerator<F : Float, const N : usize>
449 : MulAssign<F> + DivAssign<F> + Neg<Output=Self> + Clone + Sync + Send + 'static { 392 : MulAssign<F> + DivAssign<F> + Neg<Output=Self> + Clone + Sync + Send + 'static {
450 /// The identification type 393 /// The identification type
451 type Id : 'static + Copy; 394 type Id : 'static + Copy;
452 /// The type of the [`Support`] (often also a [`Apply`]). 395 /// The type of the [`Support`] (often also a [`Mapping`]).
453 type SupportType : 'static + Support<F, N>; 396 type SupportType : 'static + Support<F, N>;
454 /// An iterator over all the [`Support`]s of the generator. 397 /// An iterator over all the [`Support`]s of the generator.
455 type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a; 398 type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a;
456 399
457 /// Returns the component identified by `id`. 400 /// Returns the component identified by `id`.

mercurial