Mon, 05 Dec 2022 23:50:22 +0200
Zenodo packaging hacks
0 | 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 |