1 /*! |
1 /*! |
2 Some convex analysis basics |
2 Some convex analysis basics |
3 */ |
3 */ |
4 |
4 |
5 use crate::mapping::{Apply, Mapping}; |
5 use crate::types::*; |
|
6 use crate::mapping::{Mapping, Space}; |
|
7 use crate::instance::{Instance, InstanceMut, DecompositionMut}; |
|
8 use crate::norms::*; |
6 |
9 |
7 /// Trait for convex mappings. Has no features, just serves as a constraint |
10 /// Trait for convex mappings. Has no features, just serves as a constraint |
8 /// |
11 /// |
9 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
12 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
10 /// but this makes everything complicated with little benefit. |
13 /// but this makes everything complicated with little benefit. |
11 pub trait ConvexMapping<Domain> : Mapping<Domain> {} |
14 pub trait ConvexMapping<Domain : Space> : Mapping<Domain> |
|
15 {} |
12 |
16 |
13 /// Trait for mappings with a Fenchel conjugate |
17 /// Trait for mappings with a Fenchel conjugate |
14 /// |
18 /// |
15 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
19 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
16 /// not be convex. |
20 /// not be convex. |
17 pub trait Conjugable<Domain> : Mapping<Domain> { |
21 pub trait Conjugable<Domain : Space> : Mapping<Domain> { |
18 type DualDomain; |
22 type DualDomain : Space; |
19 type Conjugate<'a> : ConvexMapping<Self::DualDomain> where Self : 'a; |
23 type Conjugate<'a> : ConvexMapping<Self::DualDomain> where Self : 'a; |
20 |
24 |
21 fn conjugate(&self) -> Self::Conjugate<'_>; |
25 fn conjugate(&self) -> Self::Conjugate<'_>; |
22 } |
26 } |
23 |
27 |
24 /// Trait for mappings with a Fenchel preconjugate |
28 /// Trait for mappings with a Fenchel preconjugate |
25 /// |
29 /// |
26 /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], |
30 /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], |
27 /// but a `Preconjugable` mapping has be convex. |
31 /// but a `Preconjugable` mapping has be convex. |
28 pub trait Preconjugable<Domain> : ConvexMapping<Domain> { |
32 pub trait Preconjugable<Domain : Space> : ConvexMapping<Domain> { |
29 type PredualDomain; |
33 type PredualDomain : Space; |
30 type Preconjugate<'a> : Mapping<Self::PredualDomain> where Self : 'a; |
34 type Preconjugate<'a> : Mapping<Self::PredualDomain> where Self : 'a; |
31 |
35 |
32 fn preconjugate(&self) -> Self::Preconjugate<'_>; |
36 fn preconjugate(&self) -> Self::Preconjugate<'_>; |
33 } |
37 } |
34 |
38 |
35 /// Trait for mappings with a proximap map |
39 /// Trait for mappings with a proximap map |
36 /// |
40 /// |
37 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
41 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
38 /// not be convex. |
42 /// not be convex. |
39 pub trait HasProx<Domain> : Mapping<Domain> { |
43 pub trait Prox<Domain : Space> : Mapping<Domain> { |
40 type Prox<'a> : Mapping<Domain, Codomain=Domain> where Self : 'a; |
44 type Prox<'a> : Mapping<Domain, Codomain=Domain> where Self : 'a; |
41 |
45 |
42 /// Returns a proximal mapping with weight τ |
46 /// Returns a proximal mapping with weight τ |
43 fn prox_mapping(&self, τ : Self::Codomain) -> Self::Prox<'_>; |
47 fn prox_mapping(&self, τ : Self::Codomain) -> Self::Prox<'_>; |
44 |
48 |
45 /// Calculate the proximal mapping with weight τ |
49 /// Calculate the proximal mapping with weight τ |
46 fn prox(&self, z : Domain, τ : Self::Codomain) -> Domain { |
50 fn prox<I : Instance<Domain>>(&self, τ : Self::Codomain, z : I) -> Domain { |
47 self.prox_mapping(τ).apply(z) |
51 self.prox_mapping(τ).apply(z) |
|
52 } |
|
53 |
|
54 /// Calculate the proximal mapping with weight τ in-place |
|
55 fn prox_mut<'b>(&self, τ : Self::Codomain, y : &'b mut Domain) |
|
56 where |
|
57 &'b mut Domain : InstanceMut<Domain>, |
|
58 Domain:: Decomp : DecompositionMut<Domain>, |
|
59 for<'a> &'a Domain : Instance<Domain>, |
|
60 { |
|
61 *y = self.prox(τ, &*y); |
48 } |
62 } |
49 } |
63 } |
50 |
64 |
|
65 |
|
66 pub struct NormConjugate<F : Float, E : NormExponent>(NormMapping<F, E>); |
|
67 |
|
68 impl<Domain, E, F> ConvexMapping<Domain> for NormMapping<F, E> |
|
69 where |
|
70 Domain : Space, |
|
71 E : NormExponent, |
|
72 F : Float, |
|
73 Self : Mapping<Domain, Codomain=F> {} |
|
74 |
|
75 |
|
76 impl<Domain, E, F> ConvexMapping<Domain> for NormConjugate<F, E> |
|
77 where |
|
78 Domain : Space, |
|
79 E : NormExponent, |
|
80 F : Float, |
|
81 Self : Mapping<Domain, Codomain=F> {} |
|
82 |
|
83 |
|
84 impl<F, E, Domain> Mapping<Domain> for NormConjugate<F, E> |
|
85 where |
|
86 Domain : Space + Norm<F, E>, |
|
87 F : Float, |
|
88 E : NormExponent, |
|
89 { |
|
90 type Codomain = F; |
|
91 |
|
92 fn apply<I : Instance<Domain>>(&self, d : I) -> F { |
|
93 if d.eval(|x| x.norm(self.0.exponent)) <= F::ONE { |
|
94 F::ZERO |
|
95 } else { |
|
96 F::INFINITY |
|
97 } |
|
98 } |
|
99 } |
|
100 |
|
101 |
|
102 |
|
103 impl<E, F, Domain> Conjugable<Domain> for NormMapping<F, E> |
|
104 where |
|
105 E : NormExponent + Clone, |
|
106 F : Float, |
|
107 Domain : Norm<F, E> + Space, |
|
108 { |
|
109 |
|
110 type DualDomain = Domain; |
|
111 type Conjugate<'a> = NormConjugate<F, E> where Self : 'a; |
|
112 |
|
113 fn conjugate(&self) -> Self::Conjugate<'_> { |
|
114 NormConjugate(self.clone()) |
|
115 } |
|
116 } |
|
117 |