| 2 Some convex analysis basics |
2 Some convex analysis basics |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use std::marker::PhantomData; |
5 use std::marker::PhantomData; |
| 6 use crate::types::*; |
6 use crate::types::*; |
| 7 use crate::mapping::{Mapping, Space}; |
7 use crate::mapping::{Mapping, Space, ArithmeticTrue}; |
| 8 use crate::linops::IdOp; |
8 use crate::linops::IdOp; |
| 9 use crate::instance::{Instance, InstanceMut, DecompositionMut}; |
9 use crate::instance::{Instance, InstanceMut, DecompositionMut,}; |
| 10 use crate::norms::*; |
10 use crate::norms::*; |
| 11 |
11 |
| 12 /// Trait for convex mappings. Has no features, just serves as a constraint |
12 /// Trait for convex mappings. Has no features, just serves as a constraint |
| 13 /// |
13 /// |
| 14 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
14 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
| 83 Domain : Space + Norm<F, E>, |
83 Domain : Space + Norm<F, E>, |
| 84 F : Float, |
84 F : Float, |
| 85 E : NormExponent, |
85 E : NormExponent, |
| 86 { |
86 { |
| 87 type Codomain = F; |
87 type Codomain = F; |
| |
88 type ArithmeticOptIn = ArithmeticTrue; |
| 88 |
89 |
| 89 fn apply<I : Instance<Domain>>(&self, d : I) -> F { |
90 fn apply<I : Instance<Domain>>(&self, d : I) -> F { |
| 90 if d.eval(|x| x.norm(self.0.exponent)) <= F::ONE { |
91 if d.eval(|x| x.norm(self.0.exponent)) <= F::ONE { |
| 91 F::ZERO |
92 F::ZERO |
| 92 } else { |
93 } else { |
| 116 fn conjugate(&self) -> Self::Conjugate<'_> { |
117 fn conjugate(&self) -> Self::Conjugate<'_> { |
| 117 NormConjugate(self.exponent.dual_exponent().as_mapping()) |
118 NormConjugate(self.exponent.dual_exponent().as_mapping()) |
| 118 } |
119 } |
| 119 } |
120 } |
| 120 |
121 |
| |
122 impl<Domain, E, F> Prox<Domain> for NormConjugate<F, E> |
| |
123 where |
| |
124 Domain : Space + Norm<F, E>, |
| |
125 E : NormExponent, |
| |
126 F : Float, |
| |
127 NormProjection<F, E> : Mapping<Domain, Codomain=Domain>, |
| |
128 { |
| |
129 type Prox<'a> = NormProjection<F, E> where Self : 'a; |
| |
130 |
| |
131 #[inline] |
| |
132 fn prox_mapping(&self, τ : Self::Codomain) -> Self::Prox<'_> { |
| |
133 NormProjection{ α : τ, exponent : self.0.exponent } |
| |
134 } |
| |
135 } |
| |
136 |
| |
137 pub struct NormProjection<F : Float, E : NormExponent> { |
| |
138 α : F, |
| |
139 exponent : E, |
| |
140 } |
| |
141 |
| |
142 /* |
| |
143 impl<F, Domain> Mapping<Domain> for NormProjection<F, L2> |
| |
144 where |
| |
145 Domain : Space + Euclidean<F> + std::ops::MulAssign<F>, |
| |
146 F : Float, |
| |
147 { |
| |
148 type Codomain = Domain; |
| |
149 |
| |
150 fn apply<I : Instance<Domain>>(&self, d : I) -> Domain { |
| |
151 d.own().proj_ball2(self.α) |
| |
152 } |
| |
153 } |
| |
154 */ |
| |
155 |
| |
156 impl<F, E, Domain> Mapping<Domain> for NormProjection<F, E> |
| |
157 where |
| |
158 Domain : Space + Projection<F, E> + std::ops::MulAssign<F>, |
| |
159 F : Float, |
| |
160 E : NormExponent, |
| |
161 { |
| |
162 type Codomain = Domain; |
| |
163 type ArithmeticOptIn = ArithmeticTrue; |
| |
164 |
| |
165 fn apply<I : Instance<Domain>>(&self, d : I) -> Domain { |
| |
166 d.own().proj_ball(self.α, self.exponent) |
| |
167 } |
| |
168 } |
| 121 |
169 |
| 122 /// The zero mapping |
170 /// The zero mapping |
| 123 pub struct Zero<Domain : Space, F : Num>(PhantomData<(Domain, F)>); |
171 pub struct Zero<Domain : Space, F : Num>(PhantomData<(Domain, F)>); |
| 124 |
172 |
| 125 impl<Domain : Space, F : Num> Zero<Domain, F> { |
173 impl<Domain : Space, F : Num> Zero<Domain, F> { |
| 128 } |
176 } |
| 129 } |
177 } |
| 130 |
178 |
| 131 impl<Domain : Space, F : Num> Mapping<Domain> for Zero<Domain, F> { |
179 impl<Domain : Space, F : Num> Mapping<Domain> for Zero<Domain, F> { |
| 132 type Codomain = F; |
180 type Codomain = F; |
| |
181 type ArithmeticOptIn = ArithmeticTrue; |
| 133 |
182 |
| 134 /// Compute the value of `self` at `x`. |
183 /// Compute the value of `self` at `x`. |
| 135 fn apply<I : Instance<Domain>>(&self, _x : I) -> Self::Codomain { |
184 fn apply<I : Instance<Domain>>(&self, _x : I) -> Self::Codomain { |
| 136 F::ZERO |
185 F::ZERO |
| 137 } |
186 } |
| 181 } |
230 } |
| 182 } |
231 } |
| 183 |
232 |
| 184 impl<Domain : Normed<F>, F : Float> Mapping<Domain> for ZeroIndicator<Domain, F> { |
233 impl<Domain : Normed<F>, F : Float> Mapping<Domain> for ZeroIndicator<Domain, F> { |
| 185 type Codomain = F; |
234 type Codomain = F; |
| |
235 type ArithmeticOptIn = ArithmeticTrue; |
| 186 |
236 |
| 187 /// Compute the value of `self` at `x`. |
237 /// Compute the value of `self` at `x`. |
| 188 fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain { |
238 fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain { |
| 189 x.eval(|x̃| if x̃.is_zero() { F::ZERO } else { F::INFINITY }) |
239 x.eval(|x̃| if x̃.is_zero() { F::ZERO } else { F::INFINITY }) |
| 190 } |
240 } |