| 1 /*! |
1 /*! |
| 2 Some convex analysis basics |
2 Some convex analysis basics |
| 3 */ |
3 */ |
| 4 |
4 |
| |
5 use crate::error::DynResult; |
| |
6 use crate::euclidean::Euclidean; |
| |
7 use crate::instance::{ClosedSpace, DecompositionMut, Instance}; |
| |
8 use crate::linops::{IdOp, Scaled, SimpleZeroOp, AXPY}; |
| |
9 use crate::mapping::{DifferentiableImpl, LipschitzDifferentiableImpl, Mapping, Space}; |
| |
10 use crate::norms::*; |
| |
11 use crate::operator_arithmetic::{Constant, Weighted}; |
| |
12 use crate::types::*; |
| |
13 use serde::{Deserialize, Serialize}; |
| 5 use std::marker::PhantomData; |
14 use std::marker::PhantomData; |
| 6 use crate::types::*; |
|
| 7 use crate::mapping::{Mapping, Space}; |
|
| 8 use crate::linops::IdOp; |
|
| 9 use crate::instance::{Instance, InstanceMut, DecompositionMut}; |
|
| 10 use crate::operator_arithmetic::{Constant, Weighted}; |
|
| 11 use crate::norms::*; |
|
| 12 |
15 |
| 13 /// Trait for convex mappings. Has no features, just serves as a constraint |
16 /// Trait for convex mappings. Has no features, just serves as a constraint |
| 14 /// |
17 /// |
| 15 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
18 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
| 16 /// but this makes everything complicated with little benefit. |
19 /// but this makes everything complicated with little benefit. |
| 17 pub trait ConvexMapping<Domain : Space, F : Num = f64> : Mapping<Domain, Codomain = F> |
20 pub trait ConvexMapping<Domain: Space, F: Num = f64>: Mapping<Domain, Codomain = F> { |
| 18 {} |
21 /// Returns (a lower estimate of) the factor of strong convexity in the norm of `Domain`. |
| |
22 fn factor_of_strong_convexity(&self) -> F { |
| |
23 F::ZERO |
| |
24 } |
| |
25 } |
| 19 |
26 |
| 20 /// Trait for mappings with a Fenchel conjugate |
27 /// Trait for mappings with a Fenchel conjugate |
| 21 /// |
28 /// |
| 22 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
29 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
| 23 /// not be convex. |
30 /// not be convex. |
| 24 pub trait Conjugable<Domain : HasDual<F>, F : Num = f64> : Mapping<Domain> { |
31 pub trait Conjugable<Domain: HasDual<F>, F: Num = f64>: Mapping<Domain, Codomain = F> { |
| 25 type Conjugate<'a> : ConvexMapping<Domain::DualSpace, F> where Self : 'a; |
32 type Conjugate<'a>: ConvexMapping<Domain::DualSpace, F> |
| |
33 where |
| |
34 Self: 'a; |
| 26 |
35 |
| 27 fn conjugate(&self) -> Self::Conjugate<'_>; |
36 fn conjugate(&self) -> Self::Conjugate<'_>; |
| 28 } |
37 } |
| 29 |
38 |
| 30 /// Trait for mappings with a Fenchel preconjugate |
39 /// Trait for mappings with a Fenchel preconjugate |
| 31 /// |
40 /// |
| 32 /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], |
41 /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], |
| 33 /// but a `Preconjugable` mapping has to be convex. |
42 /// but a `Preconjugable` mapping has to be convex. |
| 34 pub trait Preconjugable<Domain, Predual, F : Num = f64> : ConvexMapping<Domain, F> |
43 pub trait Preconjugable<Domain, Predual, F: Num = f64>: ConvexMapping<Domain, F> |
| 35 where |
44 where |
| 36 Domain : Space, |
45 Domain: Space, |
| 37 Predual : HasDual<F> |
46 Predual: HasDual<F>, |
| 38 { |
47 { |
| 39 type Preconjugate<'a> : Mapping<Predual> where Self : 'a; |
48 type Preconjugate<'a>: Mapping<Predual, Codomain = F> |
| |
49 where |
| |
50 Self: 'a; |
| 40 |
51 |
| 41 fn preconjugate(&self) -> Self::Preconjugate<'_>; |
52 fn preconjugate(&self) -> Self::Preconjugate<'_>; |
| 42 } |
53 } |
| 43 |
54 |
| 44 /// Trait for mappings with a proximap map |
55 /// Trait for mappings with a proximap map |
| 45 /// |
56 /// |
| 46 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
57 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
| 47 /// not be convex. |
58 /// not be convex. |
| 48 pub trait Prox<Domain : Space> : Mapping<Domain> { |
59 pub trait Prox<Domain: Space>: Mapping<Domain> { |
| 49 type Prox<'a> : Mapping<Domain, Codomain=Domain> where Self : 'a; |
60 type Prox<'a>: Mapping<Domain, Codomain = Domain::Principal> |
| |
61 where |
| |
62 Self: 'a; |
| 50 |
63 |
| 51 /// Returns a proximal mapping with weight τ |
64 /// Returns a proximal mapping with weight τ |
| 52 fn prox_mapping(&self, τ : Self::Codomain) -> Self::Prox<'_>; |
65 fn prox_mapping(&self, τ: Self::Codomain) -> Self::Prox<'_>; |
| 53 |
66 |
| 54 /// Calculate the proximal mapping with weight τ |
67 /// Calculate the proximal mapping with weight τ |
| 55 fn prox<I : Instance<Domain>>(&self, τ : Self::Codomain, z : I) -> Domain { |
68 fn prox<I: Instance<Domain>>(&self, τ: Self::Codomain, z: I) -> Domain::Principal { |
| 56 self.prox_mapping(τ).apply(z) |
69 self.prox_mapping(τ).apply(z) |
| 57 } |
70 } |
| 58 |
71 |
| 59 /// Calculate the proximal mapping with weight τ in-place |
72 /// Calculate the proximal mapping with weight τ in-place |
| 60 fn prox_mut<'b>(&self, τ : Self::Codomain, y : &'b mut Domain) |
73 fn prox_mut<'b>(&self, τ: Self::Codomain, y: &'b mut Domain::Principal) |
| 61 where |
74 where |
| 62 &'b mut Domain : InstanceMut<Domain>, |
75 Domain::Decomp: DecompositionMut<Domain>, |
| 63 Domain:: Decomp : DecompositionMut<Domain>, |
76 for<'a> &'a Domain::Principal: Instance<Domain>, |
| 64 for<'a> &'a Domain : Instance<Domain>, |
|
| 65 { |
77 { |
| 66 *y = self.prox(τ, &*y); |
78 *y = self.prox(τ, &*y); |
| 67 } |
79 } |
| 68 } |
80 } |
| 69 |
81 |
| 70 |
|
| 71 /// Constraint to the unit ball of the norm described by `E`. |
82 /// Constraint to the unit ball of the norm described by `E`. |
| 72 pub struct NormConstraint<F : Float, E : NormExponent> { |
83 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
| 73 radius : F, |
84 pub struct NormConstraint<F: Float, E: NormExponent> { |
| 74 norm : NormMapping<F, E>, |
85 radius: F, |
| |
86 norm: NormMapping<F, E>, |
| 75 } |
87 } |
| 76 |
88 |
| 77 impl<Domain, E, F> ConvexMapping<Domain, F> for NormMapping<F, E> |
89 impl<Domain, E, F> ConvexMapping<Domain, F> for NormMapping<F, E> |
| 78 where |
90 where |
| 79 Domain : Space, |
91 Domain: Space, |
| 80 E : NormExponent, |
92 E: NormExponent, |
| 81 F : Float, |
93 F: Float, |
| 82 Self : Mapping<Domain, Codomain=F> |
94 Self: Mapping<Domain, Codomain = F>, |
| 83 {} |
95 { |
| 84 |
96 } |
| 85 |
97 |
| 86 impl<F, E, Domain> Mapping<Domain> for NormConstraint<F, E> |
98 impl<F, E, Domain> Mapping<Domain> for NormConstraint<F, E> |
| 87 where |
99 where |
| 88 Domain : Space + Norm<F, E>, |
100 Domain: Space, |
| 89 F : Float, |
101 Domain::Principal: Norm<E, F>, |
| 90 E : NormExponent, |
102 F: Float, |
| |
103 E: NormExponent, |
| 91 { |
104 { |
| 92 type Codomain = F; |
105 type Codomain = F; |
| 93 |
106 |
| 94 fn apply<I : Instance<Domain>>(&self, d : I) -> F { |
107 fn apply<I: Instance<Domain>>(&self, d: I) -> F { |
| 95 if d.eval(|x| x.norm(self.norm.exponent)) <= self.radius { |
108 if d.eval(|x| x.norm(self.norm.exponent)) <= self.radius { |
| 96 F::ZERO |
109 F::ZERO |
| 97 } else { |
110 } else { |
| 98 F::INFINITY |
111 F::INFINITY |
| 99 } |
112 } |
| 100 } |
113 } |
| 101 } |
114 } |
| 102 |
115 |
| 103 impl<Domain, E, F> ConvexMapping<Domain, F> for NormConstraint<F, E> |
116 impl<Domain, E, F> ConvexMapping<Domain, F> for NormConstraint<F, E> |
| 104 where |
117 where |
| 105 Domain : Space, |
118 Domain: Space, |
| 106 E : NormExponent, |
119 E: NormExponent, |
| 107 F : Float, |
120 F: Float, |
| 108 Self : Mapping<Domain, Codomain=F> |
121 Self: Mapping<Domain, Codomain = F>, |
| 109 {} |
122 { |
| 110 |
123 } |
| 111 |
124 |
| 112 impl<E, F, Domain> Conjugable<Domain, F> for NormMapping<F, E> |
125 impl<E, F, Domain> Conjugable<Domain, F> for NormMapping<F, E> |
| 113 where |
126 where |
| 114 E : HasDualExponent, |
127 E: HasDualExponent, |
| 115 F : Float, |
128 F: Float, |
| 116 Domain : HasDual<F> + Norm<F, E> + Space, |
129 Domain: HasDual<F>, |
| 117 <Domain as HasDual<F>>::DualSpace : Norm<F, E::DualExp> |
130 Domain::Principal: Norm<E, F>, |
| 118 { |
131 <Domain as HasDual<F>>::DualSpace: Norm<E::DualExp, F>, |
| 119 type Conjugate<'a> = NormConstraint<F, E::DualExp> where Self : 'a; |
132 { |
| |
133 type Conjugate<'a> |
| |
134 = NormConstraint<F, E::DualExp> |
| |
135 where |
| |
136 Self: 'a; |
| |
137 |
| |
138 fn conjugate(&self) -> Self::Conjugate<'_> { |
| |
139 NormConstraint { radius: F::ONE, norm: self.exponent.dual_exponent().as_mapping() } |
| |
140 } |
| |
141 } |
| |
142 |
| |
143 impl<C, E, F, Domain> Conjugable<Domain, F> for Weighted<NormMapping<F, E>, C> |
| |
144 where |
| |
145 C: Constant<Type = F>, |
| |
146 E: HasDualExponent, |
| |
147 F: Float, |
| |
148 Domain: HasDual<F>, |
| |
149 Domain::Principal: Norm<E, F>, |
| |
150 <Domain as HasDual<F>>::DualSpace: Norm<E::DualExp, F>, |
| |
151 { |
| |
152 type Conjugate<'a> |
| |
153 = NormConstraint<F, E::DualExp> |
| |
154 where |
| |
155 Self: 'a; |
| 120 |
156 |
| 121 fn conjugate(&self) -> Self::Conjugate<'_> { |
157 fn conjugate(&self) -> Self::Conjugate<'_> { |
| 122 NormConstraint { |
158 NormConstraint { |
| 123 radius : F::ONE, |
159 radius: self.weight.value(), |
| 124 norm : self.exponent.dual_exponent().as_mapping() |
160 norm: self.base_fn.exponent.dual_exponent().as_mapping(), |
| 125 } |
161 } |
| 126 } |
162 } |
| 127 } |
163 } |
| 128 |
164 |
| 129 impl<C, E, F, Domain> Conjugable<Domain, F> for Weighted<NormMapping<F, E>, C> |
|
| 130 where |
|
| 131 C : Constant<Type = F>, |
|
| 132 E : HasDualExponent, |
|
| 133 F : Float, |
|
| 134 Domain : HasDual<F> + Norm<F, E> + Space, |
|
| 135 <Domain as HasDual<F>>::DualSpace : Norm<F, E::DualExp> |
|
| 136 { |
|
| 137 type Conjugate<'a> = NormConstraint<F, E::DualExp> where Self : 'a; |
|
| 138 |
|
| 139 fn conjugate(&self) -> Self::Conjugate<'_> { |
|
| 140 NormConstraint { |
|
| 141 radius : self.weight.value(), |
|
| 142 norm : self.base_fn.exponent.dual_exponent().as_mapping() |
|
| 143 } |
|
| 144 } |
|
| 145 } |
|
| 146 |
|
| 147 impl<Domain, E, F> Prox<Domain> for NormConstraint<F, E> |
165 impl<Domain, E, F> Prox<Domain> for NormConstraint<F, E> |
| 148 where |
166 where |
| 149 Domain : Space + Norm<F, E>, |
167 Domain: Space, |
| 150 E : NormExponent, |
168 Domain::Principal: Norm<E, F>, |
| 151 F : Float, |
169 E: NormExponent, |
| 152 NormProjection<F, E> : Mapping<Domain, Codomain=Domain>, |
170 F: Float, |
| 153 { |
171 NormProjection<F, E>: Mapping<Domain, Codomain = Domain::Principal>, |
| 154 type Prox<'a> = NormProjection<F, E> where Self : 'a; |
172 { |
| 155 |
173 type Prox<'a> |
| 156 #[inline] |
174 = NormProjection<F, E> |
| 157 fn prox_mapping(&self, _τ : Self::Codomain) -> Self::Prox<'_> { |
175 where |
| |
176 Self: 'a; |
| |
177 |
| |
178 #[inline] |
| |
179 fn prox_mapping(&self, _τ: Self::Codomain) -> Self::Prox<'_> { |
| 158 assert!(self.radius >= F::ZERO); |
180 assert!(self.radius >= F::ZERO); |
| 159 NormProjection{ radius : self.radius, exponent : self.norm.exponent } |
181 NormProjection { radius: self.radius, exponent: self.norm.exponent } |
| 160 } |
182 } |
| 161 } |
183 } |
| 162 |
184 |
| 163 /// Projection to the unit ball of the norm described by `E`. |
185 /// Projection to the unit ball of the norm described by `E`. |
| 164 pub struct NormProjection<F : Float, E : NormExponent> { |
186 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
| 165 radius : F, |
187 pub struct NormProjection<F: Float, E: NormExponent> { |
| 166 exponent : E, |
188 radius: F, |
| |
189 exponent: E, |
| 167 } |
190 } |
| 168 |
191 |
| 169 /* |
192 /* |
| 170 impl<F, Domain> Mapping<Domain> for NormProjection<F, L2> |
193 impl<F, Domain> Mapping<Domain> for NormProjection<F, L2> |
| 171 where |
194 where |
| 180 } |
203 } |
| 181 */ |
204 */ |
| 182 |
205 |
| 183 impl<F, E, Domain> Mapping<Domain> for NormProjection<F, E> |
206 impl<F, E, Domain> Mapping<Domain> for NormProjection<F, E> |
| 184 where |
207 where |
| 185 Domain : Space + Projection<F, E>, |
208 Domain: Space, |
| 186 F : Float, |
209 Domain::Principal: ClosedSpace + Projection<F, E>, |
| 187 E : NormExponent, |
210 F: Float, |
| 188 { |
211 E: NormExponent, |
| 189 type Codomain = Domain; |
212 { |
| 190 |
213 type Codomain = Domain::Principal; |
| 191 fn apply<I : Instance<Domain>>(&self, d : I) -> Domain { |
214 |
| |
215 fn apply<I: Instance<Domain>>(&self, d: I) -> Self::Codomain { |
| 192 d.own().proj_ball(self.radius, self.exponent) |
216 d.own().proj_ball(self.radius, self.exponent) |
| 193 } |
217 } |
| 194 } |
218 } |
| 195 |
219 |
| 196 |
|
| 197 /// The zero mapping |
220 /// The zero mapping |
| 198 pub struct Zero<Domain : Space, F : Num>(PhantomData<(Domain, F)>); |
221 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
| 199 |
222 pub struct Zero<Domain: Space, F: Num>(PhantomData<(Domain, F)>); |
| 200 impl<Domain : Space, F : Num> Zero<Domain, F> { |
223 |
| |
224 impl<Domain: Space, F: Num> Zero<Domain, F> { |
| 201 pub fn new() -> Self { |
225 pub fn new() -> Self { |
| 202 Zero(PhantomData) |
226 Zero(PhantomData) |
| 203 } |
227 } |
| 204 } |
228 } |
| 205 |
229 |
| 206 impl<Domain : Space, F : Num> Mapping<Domain> for Zero<Domain, F> { |
230 impl<Domain: Space, F: Num> Mapping<Domain> for Zero<Domain, F> { |
| 207 type Codomain = F; |
231 type Codomain = F; |
| 208 |
232 |
| 209 /// Compute the value of `self` at `x`. |
233 /// Compute the value of `self` at `x`. |
| 210 fn apply<I : Instance<Domain>>(&self, _x : I) -> Self::Codomain { |
234 fn apply<I: Instance<Domain>>(&self, _x: I) -> Self::Codomain { |
| 211 F::ZERO |
235 F::ZERO |
| 212 } |
236 } |
| 213 } |
237 } |
| 214 |
238 |
| 215 impl<Domain : Space, F : Num> ConvexMapping<Domain, F> for Zero<Domain, F> { } |
239 impl<Domain: Space, F: Float> ConvexMapping<Domain, F> for Zero<Domain, F> {} |
| 216 |
240 |
| 217 |
241 impl<Domain: HasDual<F>, F: Float> Conjugable<Domain, F> for Zero<Domain, F> { |
| 218 impl<Domain : HasDual<F>, F : Float> Conjugable<Domain, F> for Zero<Domain, F> { |
242 type Conjugate<'a> |
| 219 type Conjugate<'a> = ZeroIndicator<Domain::DualSpace, F> where Self : 'a; |
243 = ZeroIndicator<Domain::DualSpace, F> |
| |
244 where |
| |
245 Self: 'a; |
| 220 |
246 |
| 221 #[inline] |
247 #[inline] |
| 222 fn conjugate(&self) -> Self::Conjugate<'_> { |
248 fn conjugate(&self) -> Self::Conjugate<'_> { |
| 223 ZeroIndicator::new() |
249 ZeroIndicator::new() |
| 224 } |
250 } |
| 225 } |
251 } |
| 226 |
252 |
| 227 impl<Domain, Predual, F : Float> Preconjugable<Domain, Predual, F> for Zero<Domain, F> |
253 impl<Domain, Predual, F: Float> Preconjugable<Domain, Predual, F> for Zero<Domain, F> |
| 228 where |
254 where |
| 229 Domain : Space, |
255 Domain: Normed<F>, |
| 230 Predual : HasDual<F> |
256 Predual: HasDual<F, PrincipalV = Predual>, |
| 231 { |
257 { |
| 232 type Preconjugate<'a> = ZeroIndicator<Predual, F> where Self : 'a; |
258 type Preconjugate<'a> |
| |
259 = ZeroIndicator<Predual, F> |
| |
260 where |
| |
261 Self: 'a; |
| 233 |
262 |
| 234 #[inline] |
263 #[inline] |
| 235 fn preconjugate(&self) -> Self::Preconjugate<'_> { |
264 fn preconjugate(&self) -> Self::Preconjugate<'_> { |
| 236 ZeroIndicator::new() |
265 ZeroIndicator::new() |
| 237 } |
266 } |
| 238 } |
267 } |
| 239 |
268 |
| 240 impl<Domain : Space + Clone, F : Num> Prox<Domain> for Zero<Domain, F> { |
269 impl<Domain: Space, F: Num> Prox<Domain> for Zero<Domain, F> { |
| 241 type Prox<'a> = IdOp<Domain> where Self : 'a; |
270 type Prox<'a> |
| 242 |
271 = IdOp<Domain> |
| 243 #[inline] |
272 where |
| 244 fn prox_mapping(&self, _τ : Self::Codomain) -> Self::Prox<'_> { |
273 Self: 'a; |
| |
274 |
| |
275 #[inline] |
| |
276 fn prox_mapping(&self, _τ: Self::Codomain) -> Self::Prox<'_> { |
| 245 IdOp::new() |
277 IdOp::new() |
| 246 } |
278 } |
| 247 } |
279 } |
| 248 |
280 |
| 249 |
|
| 250 /// The zero indicator |
281 /// The zero indicator |
| 251 pub struct ZeroIndicator<Domain : Space, F : Num>(PhantomData<(Domain, F)>); |
282 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
| 252 |
283 pub struct ZeroIndicator<Domain: Space, F: Num>(PhantomData<(Domain, F)>); |
| 253 impl<Domain : Space, F : Num> ZeroIndicator<Domain, F> { |
284 |
| |
285 impl<Domain: Space, F: Num> ZeroIndicator<Domain, F> { |
| 254 pub fn new() -> Self { |
286 pub fn new() -> Self { |
| 255 ZeroIndicator(PhantomData) |
287 ZeroIndicator(PhantomData) |
| 256 } |
288 } |
| 257 } |
289 } |
| 258 |
290 |
| 259 impl<Domain : Normed<F>, F : Float> Mapping<Domain> for ZeroIndicator<Domain, F> { |
291 impl<Domain, F> Mapping<Domain> for ZeroIndicator<Domain, F> |
| |
292 where |
| |
293 F: Float, |
| |
294 Domain: Space, |
| |
295 Domain::Principal: Normed<F>, |
| |
296 { |
| 260 type Codomain = F; |
297 type Codomain = F; |
| 261 |
298 |
| 262 /// Compute the value of `self` at `x`. |
299 /// Compute the value of `self` at `x`. |
| 263 fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain { |
300 fn apply<I: Instance<Domain>>(&self, x: I) -> Self::Codomain { |
| 264 x.eval(|x̃| if x̃.is_zero() { F::ZERO } else { F::INFINITY }) |
301 x.eval(|x̃| if x̃.is_zero() { F::ZERO } else { F::INFINITY }) |
| 265 } |
302 } |
| 266 } |
303 } |
| 267 |
304 |
| 268 impl<Domain : Normed<F>, F : Float> ConvexMapping<Domain, F> for ZeroIndicator<Domain, F> { } |
305 impl<Domain, F: Float> ConvexMapping<Domain, F> for ZeroIndicator<Domain, F> |
| 269 |
306 where |
| 270 impl<Domain : HasDual<F>, F : Float> Conjugable<Domain, F> for ZeroIndicator<Domain, F> { |
307 Domain: Space, |
| 271 type Conjugate<'a> = Zero<Domain::DualSpace, F> where Self : 'a; |
308 Domain::Principal: Normed<F>, |
| |
309 { |
| |
310 fn factor_of_strong_convexity(&self) -> F { |
| |
311 F::INFINITY |
| |
312 } |
| |
313 } |
| |
314 |
| |
315 impl<Domain, F: Float> Conjugable<Domain, F> for ZeroIndicator<Domain, F> |
| |
316 where |
| |
317 Domain: HasDual<F>, |
| |
318 Domain::PrincipalV: Normed<F>, |
| |
319 { |
| |
320 type Conjugate<'a> |
| |
321 = Zero<Domain::DualSpace, F> |
| |
322 where |
| |
323 Self: 'a; |
| 272 |
324 |
| 273 #[inline] |
325 #[inline] |
| 274 fn conjugate(&self) -> Self::Conjugate<'_> { |
326 fn conjugate(&self) -> Self::Conjugate<'_> { |
| 275 Zero::new() |
327 Zero::new() |
| 276 } |
328 } |
| 277 } |
329 } |
| 278 |
330 |
| 279 impl<Domain, Predual, F : Float> Preconjugable<Domain, Predual, F> for ZeroIndicator<Domain, F> |
331 impl<Domain, Predual, F: Float> Preconjugable<Domain, Predual, F> for ZeroIndicator<Domain, F> |
| 280 where |
332 where |
| 281 Domain : Normed<F>, |
333 Domain: Space, |
| 282 Predual : HasDual<F> |
334 Domain::Principal: Normed<F>, |
| 283 { |
335 Predual: HasDual<F>, |
| 284 type Preconjugate<'a> = Zero<Predual, F> where Self : 'a; |
336 { |
| |
337 type Preconjugate<'a> |
| |
338 = Zero<Predual, F> |
| |
339 where |
| |
340 Self: 'a; |
| 285 |
341 |
| 286 #[inline] |
342 #[inline] |
| 287 fn preconjugate(&self) -> Self::Preconjugate<'_> { |
343 fn preconjugate(&self) -> Self::Preconjugate<'_> { |
| 288 Zero::new() |
344 Zero::new() |
| 289 } |
345 } |
| 290 } |
346 } |
| |
347 |
| |
348 impl<Domain, F> Prox<Domain> for ZeroIndicator<Domain, F> |
| |
349 where |
| |
350 Domain: AXPY<Field = F, PrincipalV = Domain> + Normed<F>, |
| |
351 F: Float, |
| |
352 { |
| |
353 type Prox<'a> |
| |
354 = SimpleZeroOp |
| |
355 where |
| |
356 Self: 'a; |
| |
357 |
| |
358 /// Returns a proximal mapping with weight τ |
| |
359 fn prox_mapping(&self, _τ: F) -> Self::Prox<'_> { |
| |
360 return SimpleZeroOp; |
| |
361 } |
| |
362 } |
| |
363 |
| |
364 /// The squared Euclidean norm divided by two |
| |
365 #[derive(Copy, Clone, Serialize, Deserialize)] |
| |
366 pub struct Norm222<F: Float>(PhantomData<F>); |
| |
367 |
| |
368 impl</*Domain: Euclidean<F>,*/ F: Float> Norm222<F> { |
| |
369 pub fn new() -> Self { |
| |
370 Norm222(PhantomData) |
| |
371 } |
| |
372 } |
| |
373 |
| |
374 impl<X: Euclidean<F>, F: Float> Mapping<X> for Norm222<F> { |
| |
375 type Codomain = F; |
| |
376 |
| |
377 /// Compute the value of `self` at `x`. |
| |
378 fn apply<I: Instance<X>>(&self, x: I) -> Self::Codomain { |
| |
379 x.eval(|z| z.norm2_squared() / F::TWO) |
| |
380 } |
| |
381 } |
| |
382 |
| |
383 impl<X: Euclidean<F>, F: Float> ConvexMapping<X, F> for Norm222<F> { |
| |
384 fn factor_of_strong_convexity(&self) -> F { |
| |
385 F::ONE |
| |
386 } |
| |
387 } |
| |
388 |
| |
389 impl<X: Euclidean<F>, F: Float> Conjugable<X, F> for Norm222<F> { |
| |
390 type Conjugate<'a> |
| |
391 = Self |
| |
392 where |
| |
393 Self: 'a; |
| |
394 |
| |
395 #[inline] |
| |
396 fn conjugate(&self) -> Self::Conjugate<'_> { |
| |
397 Self::new() |
| |
398 } |
| |
399 } |
| |
400 |
| |
401 impl<X: Euclidean<F>, F: Float> Preconjugable<X, X, F> for Norm222<F> { |
| |
402 type Preconjugate<'a> |
| |
403 = Self |
| |
404 where |
| |
405 Self: 'a; |
| |
406 |
| |
407 #[inline] |
| |
408 fn preconjugate(&self) -> Self::Preconjugate<'_> { |
| |
409 Self::new() |
| |
410 } |
| |
411 } |
| |
412 |
| |
413 impl<X, F> Prox<X> for Norm222<F> |
| |
414 where |
| |
415 F: Float, |
| |
416 X: Euclidean<F>, |
| |
417 { |
| |
418 type Prox<'a> |
| |
419 = Scaled<F> |
| |
420 where |
| |
421 Self: 'a; |
| |
422 |
| |
423 fn prox_mapping(&self, τ: F) -> Self::Prox<'_> { |
| |
424 Scaled(F::ONE / (F::ONE + τ)) |
| |
425 } |
| |
426 } |
| |
427 |
| |
428 impl<X, F> DifferentiableImpl<X> for Norm222<F> |
| |
429 where |
| |
430 F: Float, |
| |
431 X: Euclidean<F>, |
| |
432 { |
| |
433 type Derivative = X::PrincipalV; |
| |
434 |
| |
435 fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative { |
| |
436 x.own() |
| |
437 } |
| |
438 } |
| |
439 |
| |
440 impl<X, F> LipschitzDifferentiableImpl<X, L2> for Norm222<F> |
| |
441 where |
| |
442 F: Float, |
| |
443 X: Euclidean<F>, |
| |
444 { |
| |
445 type FloatType = F; |
| |
446 |
| |
447 fn diff_lipschitz_factor(&self, _: L2) -> DynResult<Self::FloatType> { |
| |
448 Ok(F::ONE) |
| |
449 } |
| |
450 } |