| 1 /*! |
1 /*! |
| 2 Some convex analysis basics |
2 Some convex analysis basics |
| 3 */ |
3 */ |
| 4 |
4 |
| |
5 use std::marker::PhantomData; |
| 5 use crate::types::*; |
6 use crate::types::*; |
| 6 use crate::mapping::{Mapping, Space}; |
7 use crate::mapping::{Mapping, Space}; |
| |
8 use crate::linops::IdOp; |
| 7 use crate::instance::{Instance, InstanceMut, DecompositionMut}; |
9 use crate::instance::{Instance, InstanceMut, DecompositionMut}; |
| 8 use crate::norms::*; |
10 use crate::norms::*; |
| 9 |
11 |
| 10 /// 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 |
| 11 /// |
13 /// |
| 12 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
14 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
| 13 /// but this makes everything complicated with little benefit. |
15 /// but this makes everything complicated with little benefit. |
| 14 pub trait ConvexMapping<Domain : Space> : Mapping<Domain> |
16 pub trait ConvexMapping<Domain : Space, F : Num = f64> : Mapping<Domain, Codomain = F> |
| 15 {} |
17 {} |
| 16 |
18 |
| 17 /// Trait for mappings with a Fenchel conjugate |
19 /// Trait for mappings with a Fenchel conjugate |
| 18 /// |
20 /// |
| 19 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
21 /// The conjugate type has to implement [`ConvexMapping`], but a `Conjugable` mapping need |
| 20 /// not be convex. |
22 /// not be convex. |
| 21 pub trait Conjugable<Domain : Space> : Mapping<Domain> { |
23 pub trait Conjugable<Domain : HasDual<F>, F : Num = f64> : Mapping<Domain> { |
| 22 type DualDomain : Space; |
24 type Conjugate<'a> : ConvexMapping<Domain::DualSpace, F> where Self : 'a; |
| 23 type Conjugate<'a> : ConvexMapping<Self::DualDomain> where Self : 'a; |
|
| 24 |
25 |
| 25 fn conjugate(&self) -> Self::Conjugate<'_>; |
26 fn conjugate(&self) -> Self::Conjugate<'_>; |
| 26 } |
27 } |
| 27 |
28 |
| 28 /// Trait for mappings with a Fenchel preconjugate |
29 /// Trait for mappings with a Fenchel preconjugate |
| 29 /// |
30 /// |
| 30 /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], |
31 /// In contrast to [`Conjugable`], the preconjugate need not implement [`ConvexMapping`], |
| 31 /// but a `Preconjugable` mapping has be convex. |
32 /// but a `Preconjugable` mapping has to be convex. |
| 32 pub trait Preconjugable<Domain : Space> : ConvexMapping<Domain> { |
33 pub trait Preconjugable<Domain, Predual, F : Num = f64> : ConvexMapping<Domain, F> |
| 33 type PredualDomain : Space; |
34 where |
| 34 type Preconjugate<'a> : Mapping<Self::PredualDomain> where Self : 'a; |
35 Domain : Space, |
| |
36 Predual : HasDual<F> |
| |
37 { |
| |
38 type Preconjugate<'a> : Mapping<Predual> where Self : 'a; |
| 35 |
39 |
| 36 fn preconjugate(&self) -> Self::Preconjugate<'_>; |
40 fn preconjugate(&self) -> Self::Preconjugate<'_>; |
| 37 } |
41 } |
| 38 |
42 |
| 39 /// Trait for mappings with a proximap map |
43 /// Trait for mappings with a proximap map |
| 63 } |
67 } |
| 64 |
68 |
| 65 |
69 |
| 66 pub struct NormConjugate<F : Float, E : NormExponent>(NormMapping<F, E>); |
70 pub struct NormConjugate<F : Float, E : NormExponent>(NormMapping<F, E>); |
| 67 |
71 |
| 68 impl<Domain, E, F> ConvexMapping<Domain> for NormMapping<F, E> |
72 impl<Domain, E, F> ConvexMapping<Domain, F> for NormMapping<F, E> |
| 69 where |
73 where |
| 70 Domain : Space, |
74 Domain : Space, |
| 71 E : NormExponent, |
75 E : NormExponent, |
| 72 F : Float, |
76 F : Float, |
| 73 Self : Mapping<Domain, Codomain=F> {} |
77 Self : Mapping<Domain, Codomain=F> |
| 74 |
78 {} |
| 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 |
79 |
| 83 |
80 |
| 84 impl<F, E, Domain> Mapping<Domain> for NormConjugate<F, E> |
81 impl<F, E, Domain> Mapping<Domain> for NormConjugate<F, E> |
| 85 where |
82 where |
| 86 Domain : Space + Norm<F, E>, |
83 Domain : Space + Norm<F, E>, |
| 96 F::INFINITY |
93 F::INFINITY |
| 97 } |
94 } |
| 98 } |
95 } |
| 99 } |
96 } |
| 100 |
97 |
| 101 |
98 impl<Domain, E, F> ConvexMapping<Domain, F> for NormConjugate<F, E> |
| 102 |
99 where |
| 103 impl<E, F, Domain> Conjugable<Domain> for NormMapping<F, E> |
100 Domain : Space, |
| 104 where |
101 E : NormExponent, |
| 105 E : NormExponent + Clone, |
102 F : Float, |
| 106 F : Float, |
103 Self : Mapping<Domain, Codomain=F> |
| 107 Domain : Norm<F, E> + Space, |
104 {} |
| 108 { |
105 |
| 109 |
106 |
| 110 type DualDomain = Domain; |
107 impl<E, F, Domain> Conjugable<Domain, F> for NormMapping<F, E> |
| 111 type Conjugate<'a> = NormConjugate<F, E> where Self : 'a; |
108 where |
| |
109 E : HasDualExponent, |
| |
110 F : Float, |
| |
111 Domain : HasDual<F> + Norm<F, E> + Space, |
| |
112 <Domain as HasDual<F>>::DualSpace : Norm<F, E::DualExp> |
| |
113 { |
| |
114 type Conjugate<'a> = NormConjugate<F, E::DualExp> where Self : 'a; |
| 112 |
115 |
| 113 fn conjugate(&self) -> Self::Conjugate<'_> { |
116 fn conjugate(&self) -> Self::Conjugate<'_> { |
| 114 NormConjugate(self.clone()) |
117 NormConjugate(self.exponent.dual_exponent().as_mapping()) |
| 115 } |
118 } |
| 116 } |
119 } |
| 117 |
120 |
| |
121 |
| |
122 /// The zero mapping |
| |
123 pub struct Zero<Domain : Space, F : Num>(PhantomData<(Domain, F)>); |
| |
124 |
| |
125 impl<Domain : Space, F : Num> Zero<Domain, F> { |
| |
126 pub fn new() -> Self { |
| |
127 Zero(PhantomData) |
| |
128 } |
| |
129 } |
| |
130 |
| |
131 impl<Domain : Space, F : Num> Mapping<Domain> for Zero<Domain, F> { |
| |
132 type Codomain = F; |
| |
133 |
| |
134 /// Compute the value of `self` at `x`. |
| |
135 fn apply<I : Instance<Domain>>(&self, _x : I) -> Self::Codomain { |
| |
136 F::ZERO |
| |
137 } |
| |
138 } |
| |
139 |
| |
140 impl<Domain : Space, F : Num> ConvexMapping<Domain, F> for Zero<Domain, F> { } |
| |
141 |
| |
142 |
| |
143 impl<Domain : HasDual<F>, F : Float> Conjugable<Domain, F> for Zero<Domain, F> { |
| |
144 type Conjugate<'a> = ZeroIndicator<Domain::DualSpace, F> where Self : 'a; |
| |
145 |
| |
146 #[inline] |
| |
147 fn conjugate(&self) -> Self::Conjugate<'_> { |
| |
148 ZeroIndicator::new() |
| |
149 } |
| |
150 } |
| |
151 |
| |
152 impl<Domain, Predual, F : Float> Preconjugable<Domain, Predual, F> for Zero<Domain, F> |
| |
153 where |
| |
154 Domain : Space, |
| |
155 Predual : HasDual<F> |
| |
156 { |
| |
157 type Preconjugate<'a> = ZeroIndicator<Predual, F> where Self : 'a; |
| |
158 |
| |
159 #[inline] |
| |
160 fn preconjugate(&self) -> Self::Preconjugate<'_> { |
| |
161 ZeroIndicator::new() |
| |
162 } |
| |
163 } |
| |
164 |
| |
165 impl<Domain : Space + Clone, F : Num> Prox<Domain> for Zero<Domain, F> { |
| |
166 type Prox<'a> = IdOp<Domain> where Self : 'a; |
| |
167 |
| |
168 #[inline] |
| |
169 fn prox_mapping(&self, _τ : Self::Codomain) -> Self::Prox<'_> { |
| |
170 IdOp::new() |
| |
171 } |
| |
172 } |
| |
173 |
| |
174 |
| |
175 /// The zero indicator |
| |
176 pub struct ZeroIndicator<Domain : Space, F : Num>(PhantomData<(Domain, F)>); |
| |
177 |
| |
178 impl<Domain : Space, F : Num> ZeroIndicator<Domain, F> { |
| |
179 pub fn new() -> Self { |
| |
180 ZeroIndicator(PhantomData) |
| |
181 } |
| |
182 } |
| |
183 |
| |
184 impl<Domain : Normed<F>, F : Float> Mapping<Domain> for ZeroIndicator<Domain, F> { |
| |
185 type Codomain = F; |
| |
186 |
| |
187 /// Compute the value of `self` at `x`. |
| |
188 fn apply<I : Instance<Domain>>(&self, x : I) -> Self::Codomain { |
| |
189 x.eval(|x̃| if x̃.is_zero() { F::ZERO } else { F::INFINITY }) |
| |
190 } |
| |
191 } |
| |
192 |
| |
193 impl<Domain : Normed<F>, F : Float> ConvexMapping<Domain, F> for ZeroIndicator<Domain, F> { } |
| |
194 |
| |
195 impl<Domain : HasDual<F>, F : Float> Conjugable<Domain, F> for ZeroIndicator<Domain, F> { |
| |
196 type Conjugate<'a> = Zero<Domain::DualSpace, F> where Self : 'a; |
| |
197 |
| |
198 #[inline] |
| |
199 fn conjugate(&self) -> Self::Conjugate<'_> { |
| |
200 Zero::new() |
| |
201 } |
| |
202 } |
| |
203 |
| |
204 impl<Domain, Predual, F : Float> Preconjugable<Domain, Predual, F> for ZeroIndicator<Domain, F> |
| |
205 where |
| |
206 Domain : Normed<F>, |
| |
207 Predual : HasDual<F> |
| |
208 { |
| |
209 type Preconjugate<'a> = Zero<Predual, F> where Self : 'a; |
| |
210 |
| |
211 #[inline] |
| |
212 fn preconjugate(&self) -> Self::Preconjugate<'_> { |
| |
213 Zero::new() |
| |
214 } |
| |
215 } |