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}; |
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::operator_arithmetic::{Constant, Weighted}; |
10 use crate::norms::*; |
11 use crate::norms::*; |
11 |
12 |
12 /// Trait for convex mappings. Has no features, just serves as a constraint |
13 /// Trait for convex mappings. Has no features, just serves as a constraint |
13 /// |
14 /// |
14 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
15 /// TODO: should constrain `Mapping::Codomain` to implement a partial order, |
65 *y = self.prox(τ, &*y); |
66 *y = self.prox(τ, &*y); |
66 } |
67 } |
67 } |
68 } |
68 |
69 |
69 |
70 |
70 pub struct NormConjugate<F : Float, E : NormExponent>(NormMapping<F, E>); |
71 pub struct NormConstraint<F : Float, E : NormExponent> { |
|
72 radius : F, |
|
73 norm : NormMapping<F, E>, |
|
74 } |
|
75 |
71 |
76 |
72 impl<Domain, E, F> ConvexMapping<Domain, F> for NormMapping<F, E> |
77 impl<Domain, E, F> ConvexMapping<Domain, F> for NormMapping<F, E> |
73 where |
78 where |
74 Domain : Space, |
79 Domain : Space, |
75 E : NormExponent, |
80 E : NormExponent, |
76 F : Float, |
81 F : Float, |
77 Self : Mapping<Domain, Codomain=F> |
82 Self : Mapping<Domain, Codomain=F> |
78 {} |
83 {} |
79 |
84 |
80 |
85 |
81 impl<F, E, Domain> Mapping<Domain> for NormConjugate<F, E> |
86 impl<F, E, Domain> Mapping<Domain> for NormConstraint<F, E> |
82 where |
87 where |
83 Domain : Space + Norm<F, E>, |
88 Domain : Space + Norm<F, E>, |
84 F : Float, |
89 F : Float, |
85 E : NormExponent, |
90 E : NormExponent, |
86 { |
91 { |
87 type Codomain = F; |
92 type Codomain = F; |
88 |
93 |
89 fn apply<I : Instance<Domain>>(&self, d : I) -> F { |
94 fn apply<I : Instance<Domain>>(&self, d : I) -> F { |
90 if d.eval(|x| x.norm(self.0.exponent)) <= F::ONE { |
95 if d.eval(|x| x.norm(self.norm.exponent)) <= self.radius { |
91 F::ZERO |
96 F::ZERO |
92 } else { |
97 } else { |
93 F::INFINITY |
98 F::INFINITY |
94 } |
99 } |
95 } |
100 } |
96 } |
101 } |
97 |
102 |
98 impl<Domain, E, F> ConvexMapping<Domain, F> for NormConjugate<F, E> |
103 impl<Domain, E, F> ConvexMapping<Domain, F> for NormConstraint<F, E> |
99 where |
104 where |
100 Domain : Space, |
105 Domain : Space, |
101 E : NormExponent, |
106 E : NormExponent, |
102 F : Float, |
107 F : Float, |
103 Self : Mapping<Domain, Codomain=F> |
108 Self : Mapping<Domain, Codomain=F> |
109 E : HasDualExponent, |
114 E : HasDualExponent, |
110 F : Float, |
115 F : Float, |
111 Domain : HasDual<F> + Norm<F, E> + Space, |
116 Domain : HasDual<F> + Norm<F, E> + Space, |
112 <Domain as HasDual<F>>::DualSpace : Norm<F, E::DualExp> |
117 <Domain as HasDual<F>>::DualSpace : Norm<F, E::DualExp> |
113 { |
118 { |
114 type Conjugate<'a> = NormConjugate<F, E::DualExp> where Self : 'a; |
119 type Conjugate<'a> = NormConstraint<F, E::DualExp> where Self : 'a; |
115 |
120 |
116 fn conjugate(&self) -> Self::Conjugate<'_> { |
121 fn conjugate(&self) -> Self::Conjugate<'_> { |
117 NormConjugate(self.exponent.dual_exponent().as_mapping()) |
122 NormConstraint { |
|
123 radius : F::ONE, |
|
124 norm : self.exponent.dual_exponent().as_mapping() |
|
125 } |
|
126 } |
|
127 } |
|
128 |
|
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> |
|
148 where |
|
149 Domain : Space + Norm<F, E>, |
|
150 E : NormExponent, |
|
151 F : Float, |
|
152 NormProjection<F, E> : Mapping<Domain, Codomain=Domain>, |
|
153 { |
|
154 type Prox<'a> = NormProjection<F, E> where Self : 'a; |
|
155 |
|
156 #[inline] |
|
157 fn prox_mapping(&self, _τ : Self::Codomain) -> Self::Prox<'_> { |
|
158 assert!(self.radius >= F::ZERO); |
|
159 NormProjection{ radius : self.radius, exponent : self.norm.exponent } |
|
160 } |
|
161 } |
|
162 |
|
163 pub struct NormProjection<F : Float, E : NormExponent> { |
|
164 radius : F, |
|
165 exponent : E, |
|
166 } |
|
167 |
|
168 /* |
|
169 impl<F, Domain> Mapping<Domain> for NormProjection<F, L2> |
|
170 where |
|
171 Domain : Space + Euclidean<F> + std::ops::MulAssign<F>, |
|
172 F : Float, |
|
173 { |
|
174 type Codomain = Domain; |
|
175 |
|
176 fn apply<I : Instance<Domain>>(&self, d : I) -> Domain { |
|
177 d.own().proj_ball2(self.radius) |
|
178 } |
|
179 } |
|
180 */ |
|
181 |
|
182 impl<F, E, Domain> Mapping<Domain> for NormProjection<F, E> |
|
183 where |
|
184 Domain : Space + Projection<F, E> + std::ops::MulAssign<F>, |
|
185 F : Float, |
|
186 E : NormExponent, |
|
187 { |
|
188 type Codomain = Domain; |
|
189 |
|
190 fn apply<I : Instance<Domain>>(&self, d : I) -> Domain { |
|
191 d.own().proj_ball(self.radius, self.exponent) |
118 } |
192 } |
119 } |
193 } |
120 |
194 |
121 |
195 |
122 /// The zero mapping |
196 /// The zero mapping |