| |
1 //! Implementation of the hat function |
| |
2 |
| |
3 use numeric_literals::replace_float_literals; |
| |
4 use serde::Serialize; |
| |
5 use alg_tools::types::*; |
| |
6 use alg_tools::norms::*; |
| |
7 use alg_tools::loc::Loc; |
| |
8 use alg_tools::sets::Cube; |
| |
9 use alg_tools::bisection_tree::{ |
| |
10 Support, |
| |
11 Constant, |
| |
12 Bounds, |
| |
13 LocalAnalysis, |
| |
14 GlobalAnalysis, |
| |
15 Bounded, |
| |
16 }; |
| |
17 use alg_tools::mapping::Apply; |
| |
18 use alg_tools::maputil::{array_init}; |
| |
19 |
| |
20 /// Representation of the hat function $f(x)=1-\\|x\\|\_1/ε$ of `width` $ε$ on $ℝ^N$. |
| |
21 #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] |
| |
22 pub struct Hat<C : Constant, const N : usize> { |
| |
23 /// The parameter $ε>0$. |
| |
24 pub width : C, |
| |
25 } |
| |
26 |
| |
27 #[replace_float_literals(C::Type::cast_from(literal))] |
| |
28 impl<'a, C : Constant, const N : usize> Apply<&'a Loc<C::Type, N>> for Hat<C, N> { |
| |
29 type Output = C::Type; |
| |
30 #[inline] |
| |
31 fn apply(&self, x : &'a Loc<C::Type, N>) -> Self::Output { |
| |
32 let ε = self.width.value(); |
| |
33 0.0.max(1.0-x.norm(L1)/ε) |
| |
34 } |
| |
35 } |
| |
36 |
| |
37 #[replace_float_literals(C::Type::cast_from(literal))] |
| |
38 impl<C : Constant, const N : usize> Apply<Loc<C::Type, N>> for Hat<C, N> { |
| |
39 type Output = C::Type; |
| |
40 #[inline] |
| |
41 fn apply(&self, x : Loc<C::Type, N>) -> Self::Output { |
| |
42 self.apply(&x) |
| |
43 } |
| |
44 } |
| |
45 |
| |
46 |
| |
47 #[replace_float_literals(C::Type::cast_from(literal))] |
| |
48 impl<'a, C : Constant, const N : usize> Support<C::Type, N> for Hat<C, N> { |
| |
49 #[inline] |
| |
50 fn support_hint(&self) -> Cube<C::Type,N> { |
| |
51 let ε = self.width.value(); |
| |
52 array_init(|| [-ε, ε]).into() |
| |
53 } |
| |
54 |
| |
55 #[inline] |
| |
56 fn in_support(&self, x : &Loc<C::Type,N>) -> bool { |
| |
57 x.norm(L1) < self.width.value() |
| |
58 } |
| |
59 |
| |
60 /*fn fully_in_support(&self, _cube : &Cube<C::Type,N>) -> bool { |
| |
61 todo!("Not implemented, but not used at the moment") |
| |
62 }*/ |
| |
63 |
| |
64 #[inline] |
| |
65 fn bisection_hint(&self, cube : &Cube<C::Type,N>) -> [Option<C::Type>; N] { |
| |
66 let ε = self.width.value(); |
| |
67 cube.map(|a, b| { |
| |
68 if a < 1.0 { |
| |
69 if 1.0 < b { |
| |
70 Some(1.0) |
| |
71 } else { |
| |
72 if a < -ε { |
| |
73 if b > -ε { Some(-ε) } else { None } |
| |
74 } else { |
| |
75 None |
| |
76 } |
| |
77 } |
| |
78 } else { |
| |
79 if b > ε { Some(ε) } else { None } |
| |
80 } |
| |
81 }); |
| |
82 todo!("also diagonals") |
| |
83 } |
| |
84 } |
| |
85 |
| |
86 |
| |
87 #[replace_float_literals(C::Type::cast_from(literal))] |
| |
88 impl<'a, C : Constant, const N : usize> |
| |
89 GlobalAnalysis<C::Type, Bounds<C::Type>> |
| |
90 for Hat<C, N> { |
| |
91 #[inline] |
| |
92 fn global_analysis(&self) -> Bounds<C::Type> { |
| |
93 Bounds(0.0, 1.0) |
| |
94 } |
| |
95 } |
| |
96 |
| |
97 impl<'a, C : Constant, const N : usize> |
| |
98 LocalAnalysis<C::Type, Bounds<C::Type>, N> |
| |
99 for Hat<C, N> { |
| |
100 #[inline] |
| |
101 fn local_analysis(&self, cube : &Cube<C::Type, N>) -> Bounds<C::Type> { |
| |
102 // The function is maximised/minimised where the 1-norm is minimised/maximised. |
| |
103 let lower = self.apply(cube.maxnorm_point()); |
| |
104 let upper = self.apply(cube.minnorm_point()); |
| |
105 Bounds(lower, upper) |
| |
106 } |
| |
107 } |
| |
108 |
| |
109 #[replace_float_literals(C::Type::cast_from(literal))] |
| |
110 impl<'a, C : Constant, const N : usize> |
| |
111 Norm<C::Type, Linfinity> |
| |
112 for Hat<C, N> { |
| |
113 #[inline] |
| |
114 fn norm(&self, _ : Linfinity) -> C::Type { |
| |
115 self.bounds().upper() |
| |
116 } |
| |
117 } |
| |
118 |