| 2 Some convex analysis basics |
2 Some convex analysis basics |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use crate::error::DynResult; |
5 use crate::error::DynResult; |
| 6 use crate::euclidean::Euclidean; |
6 use crate::euclidean::Euclidean; |
| 7 use crate::instance::{DecompositionMut, Instance, InstanceMut}; |
7 use crate::instance::{ClosedSpace, DecompositionMut, Instance}; |
| 8 use crate::linops::{IdOp, Scaled, SimpleZeroOp, AXPY}; |
8 use crate::linops::{IdOp, Scaled, SimpleZeroOp, AXPY}; |
| 9 use crate::mapping::{DifferentiableImpl, LipschitzDifferentiableImpl, Mapping, Space}; |
9 use crate::mapping::{DifferentiableImpl, LipschitzDifferentiableImpl, Mapping, Space}; |
| 10 use crate::norms::*; |
10 use crate::norms::*; |
| 11 use crate::operator_arithmetic::{Constant, Weighted}; |
11 use crate::operator_arithmetic::{Constant, Weighted}; |
| 12 use crate::types::*; |
12 use crate::types::*; |
| 55 /// Trait for mappings with a proximap map |
55 /// Trait for mappings with a proximap map |
| 56 /// |
56 /// |
| 57 /// 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 |
| 58 /// not be convex. |
58 /// not be convex. |
| 59 pub trait Prox<Domain: Space>: Mapping<Domain> { |
59 pub trait Prox<Domain: Space>: Mapping<Domain> { |
| 60 type Prox<'a>: Mapping<Domain, Codomain = Domain> |
60 type Prox<'a>: Mapping<Domain, Codomain = Domain::OwnedSpace> |
| 61 where |
61 where |
| 62 Self: 'a; |
62 Self: 'a; |
| 63 |
63 |
| 64 /// Returns a proximal mapping with weight τ |
64 /// Returns a proximal mapping with weight τ |
| 65 fn prox_mapping(&self, τ: Self::Codomain) -> Self::Prox<'_>; |
65 fn prox_mapping(&self, τ: Self::Codomain) -> Self::Prox<'_>; |
| 66 |
66 |
| 67 /// Calculate the proximal mapping with weight τ |
67 /// Calculate the proximal mapping with weight τ |
| 68 fn prox<I: Instance<Domain>>(&self, τ: Self::Codomain, z: I) -> Domain { |
68 fn prox<I: Instance<Domain>>(&self, τ: Self::Codomain, z: I) -> Domain::OwnedSpace { |
| 69 self.prox_mapping(τ).apply(z) |
69 self.prox_mapping(τ).apply(z) |
| 70 } |
70 } |
| 71 |
71 |
| 72 /// Calculate the proximal mapping with weight τ in-place |
72 /// Calculate the proximal mapping with weight τ in-place |
| 73 fn prox_mut<'b>(&self, τ: Self::Codomain, y: &'b mut Domain) |
73 fn prox_mut<'b>(&self, τ: Self::Codomain, y: &'b mut Domain::OwnedSpace) |
| 74 where |
74 where |
| 75 &'b mut Domain: InstanceMut<Domain>, |
|
| 76 Domain::Decomp: DecompositionMut<Domain>, |
75 Domain::Decomp: DecompositionMut<Domain>, |
| 77 for<'a> &'a Domain: Instance<Domain>, |
76 for<'a> &'a Domain::OwnedSpace: Instance<Domain>, |
| 78 { |
77 { |
| 79 *y = self.prox(τ, &*y); |
78 *y = self.prox(τ, &*y); |
| 80 } |
79 } |
| 81 } |
80 } |
| 82 |
81 |
| 163 impl<Domain, E, F> Prox<Domain> for NormConstraint<F, E> |
162 impl<Domain, E, F> Prox<Domain> for NormConstraint<F, E> |
| 164 where |
163 where |
| 165 Domain: Space + Norm<E, F>, |
164 Domain: Space + Norm<E, F>, |
| 166 E: NormExponent, |
165 E: NormExponent, |
| 167 F: Float, |
166 F: Float, |
| 168 NormProjection<F, E>: Mapping<Domain, Codomain = Domain>, |
167 NormProjection<F, E>: Mapping<Domain, Codomain = Domain::OwnedSpace>, |
| 169 { |
168 { |
| 170 type Prox<'a> |
169 type Prox<'a> |
| 171 = NormProjection<F, E> |
170 = NormProjection<F, E> |
| 172 where |
171 where |
| 173 Self: 'a; |
172 Self: 'a; |
| 201 */ |
200 */ |
| 202 |
201 |
| 203 impl<F, E, Domain> Mapping<Domain> for NormProjection<F, E> |
202 impl<F, E, Domain> Mapping<Domain> for NormProjection<F, E> |
| 204 where |
203 where |
| 205 Domain: Normed<F> + Projection<F, E>, |
204 Domain: Normed<F> + Projection<F, E>, |
| |
205 Domain::OwnedSpace: ClosedSpace, |
| 206 F: Float, |
206 F: Float, |
| 207 E: NormExponent, |
207 E: NormExponent, |
| 208 { |
208 { |
| 209 type Codomain = Domain; |
209 type Codomain = Domain::OwnedSpace; |
| 210 |
210 |
| 211 fn apply<I: Instance<Domain>>(&self, d: I) -> Domain { |
211 fn apply<I: Instance<Domain>>(&self, d: I) -> Self::Codomain { |
| 212 d.own().proj_ball(self.radius, self.exponent) |
212 d.own().proj_ball(self.radius, self.exponent) |
| 213 } |
213 } |
| 214 } |
214 } |
| 215 |
215 |
| 216 /// The zero mapping |
216 /// The zero mapping |
| 408 } |
408 } |
| 409 |
409 |
| 410 impl<X, F> DifferentiableImpl<X> for Norm222<F> |
410 impl<X, F> DifferentiableImpl<X> for Norm222<F> |
| 411 where |
411 where |
| 412 F: Float, |
412 F: Float, |
| 413 X: Euclidean<F, Owned = X>, |
413 X: Euclidean<F>, |
| 414 { |
414 { |
| 415 type Derivative = X; |
415 type Derivative = X::Owned; |
| 416 |
416 |
| 417 fn differential_impl<I: Instance<X>>(&self, x: I) -> X { |
417 fn differential_impl<I: Instance<X>>(&self, x: I) -> Self::Derivative { |
| 418 x.own() |
418 x.own() |
| 419 } |
419 } |
| 420 } |
420 } |
| 421 |
421 |
| 422 impl<X, F> LipschitzDifferentiableImpl<X, L2> for Norm222<F> |
422 impl<X, F> LipschitzDifferentiableImpl<X, L2> for Norm222<F> |
| 423 where |
423 where |
| 424 F: Float, |
424 F: Float, |
| 425 X: Euclidean<F, Owned = X>, |
425 X: Euclidean<F>, |
| 426 { |
426 { |
| 427 type FloatType = F; |
427 type FloatType = F; |
| 428 |
428 |
| 429 fn diff_lipschitz_factor(&self, _: L2) -> DynResult<Self::FloatType> { |
429 fn diff_lipschitz_factor(&self, _: L2) -> DynResult<Self::FloatType> { |
| 430 Ok(F::ONE) |
430 Ok(F::ONE) |