Thu, 23 Jan 2025 23:35:28 +0100
Generic proximal penalty support
0 | 1 | /*! |
2 | Solver for the point source localisation problem using a forward-backward splitting method. | |
3 | ||
4 | This corresponds to the manuscript | |
5 | ||
13
bdc57366d4f5
arXiv links, README beautification
Tuomo Valkonen <tuomov@iki.fi>
parents:
8
diff
changeset
|
6 | * Valkonen T. - _Proximal methods for point source localisation_, |
bdc57366d4f5
arXiv links, README beautification
Tuomo Valkonen <tuomov@iki.fi>
parents:
8
diff
changeset
|
7 | [arXiv:2212.02991](https://arxiv.org/abs/2212.02991). |
0 | 8 | |
35 | 9 | The main routine is [`pointsource_fb_reg`]. |
0 | 10 | |
11 | ## Problem | |
12 | ||
13 | <p> | |
14 | Our objective is to solve | |
15 | $$ | |
16 | \min_{μ ∈ ℳ(Ω)}~ F_0(Aμ-b) + α \|μ\|_{ℳ(Ω)} + δ_{≥ 0}(μ), | |
17 | $$ | |
18 | where $F_0(y)=\frac{1}{2}\|y\|_2^2$ and the forward operator $A \in 𝕃(ℳ(Ω); ℝ^n)$. | |
19 | </p> | |
20 | ||
21 | ## Approach | |
22 | ||
23 | <p> | |
24 | As documented in more detail in the paper, on each step we approximately solve | |
25 | $$ | |
26 | \min_{μ ∈ ℳ(Ω)}~ F(x) + α \|μ\|_{ℳ(Ω)} + δ_{≥ 0}(x) + \frac{1}{2}\|μ-μ^k|_𝒟^2, | |
27 | $$ | |
28 | where $𝒟: 𝕃(ℳ(Ω); C_c(Ω))$ is typically a convolution operator. | |
29 | </p> | |
30 | ||
31 | ## Finite-dimensional subproblems. | |
32 | ||
33 | With $C$ a projection from [`DiscreteMeasure`] to the weights, and $x^k$ such that $x^k=Cμ^k$, we | |
34 | form the discretised linearised inner problem | |
35 | <p> | |
36 | $$ | |
37 | \min_{x ∈ ℝ^n}~ τ\bigl(F(Cx^k) + [C^*∇F(Cx^k)]^⊤(x-x^k) + α {\vec 1}^⊤ x\bigr) | |
38 | + δ_{≥ 0}(x) + \frac{1}{2}\|x-x^k\|_{C^*𝒟C}^2, | |
39 | $$ | |
40 | equivalently | |
41 | $$ | |
42 | \begin{aligned} | |
43 | \min_x~ & τF(Cx^k) - τ[C^*∇F(Cx^k)]^⊤x^k + \frac{1}{2} (x^k)^⊤ C^*𝒟C x^k | |
44 | \\ | |
45 | & | |
46 | - [C^*𝒟C x^k - τC^*∇F(Cx^k)]^⊤ x | |
47 | \\ | |
48 | & | |
49 | + \frac{1}{2} x^⊤ C^*𝒟C x | |
50 | + τα {\vec 1}^⊤ x + δ_{≥ 0}(x), | |
51 | \end{aligned} | |
52 | $$ | |
53 | In other words, we obtain the quadratic non-negativity constrained problem | |
54 | $$ | |
55 | \min_{x ∈ ℝ^n}~ \frac{1}{2} x^⊤ Ã x - b̃^⊤ x + c + τα {\vec 1}^⊤ x + δ_{≥ 0}(x). | |
56 | $$ | |
57 | where | |
58 | $$ | |
59 | \begin{aligned} | |
60 | Ã & = C^*𝒟C, | |
61 | \\ | |
62 | g̃ & = C^*𝒟C x^k - τ C^*∇F(Cx^k) | |
63 | = C^* 𝒟 μ^k - τ C^*A^*(Aμ^k - b) | |
64 | \\ | |
65 | c & = τ F(Cx^k) - τ[C^*∇F(Cx^k)]^⊤x^k + \frac{1}{2} (x^k)^⊤ C^*𝒟C x^k | |
66 | \\ | |
67 | & | |
68 | = \frac{τ}{2} \|Aμ^k-b\|^2 - τ[Aμ^k-b]^⊤Aμ^k + \frac{1}{2} \|μ_k\|_{𝒟}^2 | |
69 | \\ | |
70 | & | |
71 | = -\frac{τ}{2} \|Aμ^k-b\|^2 + τ[Aμ^k-b]^⊤ b + \frac{1}{2} \|μ_k\|_{𝒟}^2. | |
72 | \end{aligned} | |
73 | $$ | |
74 | </p> | |
75 | ||
35 | 76 | We solve this with either SSN or FB as determined by |
0 | 77 | [`InnerSettings`] in [`FBGenericConfig::inner`]. |
78 | */ | |
79 | ||
80 | use numeric_literals::replace_float_literals; | |
81 | use serde::{Serialize, Deserialize}; | |
82 | use colored::Colorize; | |
83 | ||
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
84 | use alg_tools::iterate::AlgIteratorFactory; |
0 | 85 | use alg_tools::euclidean::Euclidean; |
35 | 86 | use alg_tools::linops::{Mapping, GEMV}; |
0 | 87 | use alg_tools::mapping::RealMapping; |
88 | use alg_tools::nalgebra_support::ToNalgebraRealField; | |
35 | 89 | use alg_tools::instance::Instance; |
0 | 90 | |
91 | use crate::types::*; | |
92 | use crate::measures::{ | |
93 | DiscreteMeasure, | |
35 | 94 | RNDM, |
0 | 95 | }; |
96 | use crate::measures::merging::{ | |
97 | SpikeMergingMethod, | |
98 | SpikeMerging, | |
99 | }; | |
35 | 100 | use crate::forward_model::{ |
101 | ForwardModel, | |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
102 | AdjointProductBoundedBy, |
35 | 103 | }; |
0 | 104 | use crate::plot::{ |
105 | SeqPlotter, | |
106 | Plotting, | |
107 | PlotLookup | |
108 | }; | |
32 | 109 | use crate::regularisation::RegTerm; |
110 | use crate::dataterm::{ | |
111 | calculate_residual, | |
112 | L2Squared, | |
113 | DataTerm, | |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
114 | }; |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
115 | pub use crate::prox_penalty::{ |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
116 | FBGenericConfig, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
117 | ProxPenalty |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
118 | }; |
0 | 119 | |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
120 | /// Settings for [`pointsource_fb_reg`]. |
0 | 121 | #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] |
122 | #[serde(default)] | |
123 | pub struct FBConfig<F : Float> { | |
124 | /// Step length scaling | |
125 | pub τ0 : F, | |
126 | /// Generic parameters | |
34
efa60bc4f743
Radon FB + sliding improvements
Tuomo Valkonen <tuomov@iki.fi>
parents:
32
diff
changeset
|
127 | pub generic : FBGenericConfig<F>, |
0 | 128 | } |
129 | ||
130 | #[replace_float_literals(F::cast_from(literal))] | |
131 | impl<F : Float> Default for FBConfig<F> { | |
132 | fn default() -> Self { | |
133 | FBConfig { | |
134 | τ0 : 0.99, | |
34
efa60bc4f743
Radon FB + sliding improvements
Tuomo Valkonen <tuomov@iki.fi>
parents:
32
diff
changeset
|
135 | generic : Default::default(), |
0 | 136 | } |
137 | } | |
138 | } | |
139 | ||
35 | 140 | pub(crate) fn prune_with_stats<F : Float, const N : usize>( |
141 | μ : &mut RNDM<F, N>, | |
142 | ) -> usize { | |
32 | 143 | let n_before_prune = μ.len(); |
144 | μ.prune(); | |
145 | debug_assert!(μ.len() <= n_before_prune); | |
35 | 146 | n_before_prune - μ.len() |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
147 | } |
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
148 | |
32 | 149 | #[replace_float_literals(F::cast_from(literal))] |
150 | pub(crate) fn postprocess< | |
151 | F : Float, | |
152 | V : Euclidean<F> + Clone, | |
35 | 153 | A : GEMV<F, RNDM<F, N>, Codomain = V>, |
32 | 154 | D : DataTerm<F, V, N>, |
155 | const N : usize | |
156 | > ( | |
35 | 157 | mut μ : RNDM<F, N>, |
32 | 158 | config : &FBGenericConfig<F>, |
159 | dataterm : D, | |
160 | opA : &A, | |
161 | b : &V, | |
35 | 162 | ) -> RNDM<F, N> |
163 | where | |
164 | RNDM<F, N> : SpikeMerging<F>, | |
165 | for<'a> &'a RNDM<F, N> : Instance<RNDM<F, N>>, | |
166 | { | |
32 | 167 | μ.merge_spikes_fitness(config.merging, |
168 | |μ̃| dataterm.calculate_fit_op(μ̃, opA, b), | |
169 | |&v| v); | |
170 | μ.prune(); | |
171 | μ | |
172 | } | |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
173 | |
32 | 174 | /// Iteratively solve the pointsource localisation problem using forward-backward splitting. |
0 | 175 | /// |
32 | 176 | /// The settings in `config` have their [respective documentation](FBConfig). `opA` is the |
0 | 177 | /// forward operator $A$, $b$ the observable, and $\lambda$ the regularisation weight. |
178 | /// The operator `op𝒟` is used for forming the proximal term. Typically it is a convolution | |
179 | /// operator. Finally, the `iterator` is an outer loop verbosity and iteration count control | |
180 | /// as documented in [`alg_tools::iterate`]. | |
181 | /// | |
32 | 182 | /// For details on the mathematical formulation, see the [module level](self) documentation. |
183 | /// | |
0 | 184 | /// The implementation relies on [`alg_tools::bisection_tree::BTFN`] presentations of |
185 | /// sums of simple functions usign bisection trees, and the related | |
186 | /// [`alg_tools::bisection_tree::Aggregator`]s, to efficiently search for component functions | |
187 | /// active at a specific points, and to maximise their sums. Through the implementation of the | |
188 | /// [`alg_tools::bisection_tree::BT`] bisection trees, it also relies on the copy-on-write features | |
189 | /// of [`std::sync::Arc`] to only update relevant parts of the bisection tree when adding functions. | |
190 | /// | |
191 | /// Returns the final iterate. | |
192 | #[replace_float_literals(F::cast_from(literal))] | |
32 | 193 | pub fn pointsource_fb_reg< |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
194 | F, I, A, Reg, P, const N : usize |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
195 | >( |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
196 | opA : &A, |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
197 | b : &A::Observable, |
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
198 | reg : Reg, |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
199 | prox_penalty : &P, |
32 | 200 | fbconfig : &FBConfig<F>, |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
201 | iterator : I, |
32 | 202 | mut plotter : SeqPlotter<F, N>, |
35 | 203 | ) -> RNDM<F, N> |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
204 | where |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
205 | F : Float + ToNalgebraRealField, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
206 | I : AlgIteratorFactory<IterInfo<F, N>>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
207 | for<'b> &'b A::Observable : std::ops::Neg<Output=A::Observable>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
208 | A : ForwardModel<RNDM<F, N>, F> |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
209 | + AdjointProductBoundedBy<RNDM<F, N>, P, FloatType=F>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
210 | A::PreadjointCodomain : RealMapping<F, N>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
211 | PlotLookup : Plotting<N>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
212 | RNDM<F, N> : SpikeMerging<F>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
213 | Reg : RegTerm<F, N>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
214 | P : ProxPenalty<F, A::PreadjointCodomain, Reg, N>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
215 | { |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
216 | |
32 | 217 | // Set up parameters |
34
efa60bc4f743
Radon FB + sliding improvements
Tuomo Valkonen <tuomov@iki.fi>
parents:
32
diff
changeset
|
218 | let config = &fbconfig.generic; |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
219 | let τ = fbconfig.τ0/opA.adjoint_product_bound(prox_penalty).unwrap(); |
32 | 220 | // We multiply tolerance by τ for FB since our subproblems depending on tolerances are scaled |
221 | // by τ compared to the conditional gradient approach. | |
222 | let tolerance = config.tolerance * τ * reg.tolerance_scaling(); | |
223 | let mut ε = tolerance.initial(); | |
224 | ||
225 | // Initialise iterates | |
226 | let mut μ = DiscreteMeasure::new(); | |
227 | let mut residual = -b; | |
35 | 228 | |
229 | // Statistics | |
230 | let full_stats = |residual : &A::Observable, | |
231 | μ : &RNDM<F, N>, | |
232 | ε, stats| IterInfo { | |
233 | value : residual.norm2_squared_div2() + reg.apply(μ), | |
234 | n_spikes : μ.len(), | |
235 | ε, | |
236 | //postprocessing: config.postprocessing.then(|| μ.clone()), | |
237 | .. stats | |
238 | }; | |
32 | 239 | let mut stats = IterInfo::new(); |
240 | ||
241 | // Run the algorithm | |
35 | 242 | for state in iterator.iter_init(|| full_stats(&residual, &μ, ε, stats.clone())) { |
32 | 243 | // Calculate smooth part of surrogate model. |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
244 | let mut τv = opA.preadjoint().apply(residual * τ); |
32 | 245 | |
246 | // Save current base point | |
247 | let μ_base = μ.clone(); | |
248 | ||
249 | // Insert and reweigh | |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
250 | let (maybe_d, _within_tolerances) = prox_penalty.insert_and_reweigh( |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
251 | &mut μ, &mut τv, &μ_base, None, |
32 | 252 | τ, ε, |
35 | 253 | config, ®, &state, &mut stats |
32 | 254 | ); |
255 | ||
256 | // Prune and possibly merge spikes | |
35 | 257 | if config.merge_now(&state) { |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
258 | stats.merged += prox_penalty.merge_spikes(&mut μ, &mut τv, &μ_base, τ, ε, config, ®); |
35 | 259 | } |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
260 | |
35 | 261 | stats.pruned += prune_with_stats(&mut μ); |
32 | 262 | |
263 | // Update residual | |
264 | residual = calculate_residual(&μ, opA, b); | |
265 | ||
35 | 266 | let iter = state.iteration(); |
32 | 267 | stats.this_iters += 1; |
268 | ||
35 | 269 | // Give statistics if needed |
32 | 270 | state.if_verbose(|| { |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
271 | plotter.plot_spikes(iter, maybe_d.as_ref(), Some(&τv), &μ); |
35 | 272 | full_stats(&residual, &μ, ε, std::mem::replace(&mut stats, IterInfo::new())) |
273 | }); | |
274 | ||
275 | // Update main tolerance for next iteration | |
276 | ε = tolerance.update(ε, iter); | |
277 | } | |
32 | 278 | |
279 | postprocess(μ, config, L2Squared, opA, b) | |
280 | } | |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
281 | |
32 | 282 | /// Iteratively solve the pointsource localisation problem using inertial forward-backward splitting. |
283 | /// | |
284 | /// The settings in `config` have their [respective documentation](FBConfig). `opA` is the | |
285 | /// forward operator $A$, $b$ the observable, and $\lambda$ the regularisation weight. | |
286 | /// The operator `op𝒟` is used for forming the proximal term. Typically it is a convolution | |
287 | /// operator. Finally, the `iterator` is an outer loop verbosity and iteration count control | |
288 | /// as documented in [`alg_tools::iterate`]. | |
289 | /// | |
290 | /// For details on the mathematical formulation, see the [module level](self) documentation. | |
291 | /// | |
292 | /// The implementation relies on [`alg_tools::bisection_tree::BTFN`] presentations of | |
293 | /// sums of simple functions usign bisection trees, and the related | |
294 | /// [`alg_tools::bisection_tree::Aggregator`]s, to efficiently search for component functions | |
295 | /// active at a specific points, and to maximise their sums. Through the implementation of the | |
296 | /// [`alg_tools::bisection_tree::BT`] bisection trees, it also relies on the copy-on-write features | |
297 | /// of [`std::sync::Arc`] to only update relevant parts of the bisection tree when adding functions. | |
298 | /// | |
299 | /// Returns the final iterate. | |
300 | #[replace_float_literals(F::cast_from(literal))] | |
301 | pub fn pointsource_fista_reg< | |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
302 | F, I, A, Reg, P, const N : usize |
32 | 303 | >( |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
304 | opA : &A, |
32 | 305 | b : &A::Observable, |
306 | reg : Reg, | |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
307 | prox_penalty : &P, |
32 | 308 | fbconfig : &FBConfig<F>, |
309 | iterator : I, | |
310 | mut plotter : SeqPlotter<F, N>, | |
35 | 311 | ) -> RNDM<F, N> |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
312 | where |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
313 | F : Float + ToNalgebraRealField, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
314 | I : AlgIteratorFactory<IterInfo<F, N>>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
315 | for<'b> &'b A::Observable : std::ops::Neg<Output=A::Observable>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
316 | A : ForwardModel<RNDM<F, N>, F> |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
317 | + AdjointProductBoundedBy<RNDM<F, N>, P, FloatType=F>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
318 | A::PreadjointCodomain : RealMapping<F, N>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
319 | PlotLookup : Plotting<N>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
320 | RNDM<F, N> : SpikeMerging<F>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
321 | Reg : RegTerm<F, N>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
322 | P : ProxPenalty<F, A::PreadjointCodomain, Reg, N>, |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
323 | { |
32 | 324 | |
325 | // Set up parameters | |
34
efa60bc4f743
Radon FB + sliding improvements
Tuomo Valkonen <tuomov@iki.fi>
parents:
32
diff
changeset
|
326 | let config = &fbconfig.generic; |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
327 | let τ = fbconfig.τ0/opA.adjoint_product_bound(prox_penalty).unwrap(); |
32 | 328 | let mut λ = 1.0; |
329 | // We multiply tolerance by τ for FB since our subproblems depending on tolerances are scaled | |
330 | // by τ compared to the conditional gradient approach. | |
331 | let tolerance = config.tolerance * τ * reg.tolerance_scaling(); | |
332 | let mut ε = tolerance.initial(); | |
333 | ||
334 | // Initialise iterates | |
335 | let mut μ = DiscreteMeasure::new(); | |
336 | let mut μ_prev = DiscreteMeasure::new(); | |
337 | let mut residual = -b; | |
35 | 338 | let mut warned_merging = false; |
339 | ||
340 | // Statistics | |
341 | let full_stats = |ν : &RNDM<F, N>, ε, stats| IterInfo { | |
342 | value : L2Squared.calculate_fit_op(ν, opA, b) + reg.apply(ν), | |
343 | n_spikes : ν.len(), | |
344 | ε, | |
345 | // postprocessing: config.postprocessing.then(|| ν.clone()), | |
346 | .. stats | |
347 | }; | |
32 | 348 | let mut stats = IterInfo::new(); |
349 | ||
350 | // Run the algorithm | |
35 | 351 | for state in iterator.iter_init(|| full_stats(&μ, ε, stats.clone())) { |
32 | 352 | // Calculate smooth part of surrogate model. |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
353 | let mut τv = opA.preadjoint().apply(residual * τ); |
32 | 354 | |
355 | // Save current base point | |
356 | let μ_base = μ.clone(); | |
357 | ||
358 | // Insert new spikes and reweigh | |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
359 | let (maybe_d, _within_tolerances) = prox_penalty.insert_and_reweigh( |
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
360 | &mut μ, &mut τv, &μ_base, None, |
32 | 361 | τ, ε, |
35 | 362 | config, ®, &state, &mut stats |
32 | 363 | ); |
364 | ||
365 | // (Do not) merge spikes. | |
35 | 366 | if config.merge_now(&state) { |
32 | 367 | match config.merging { |
368 | SpikeMergingMethod::None => { }, | |
369 | _ => if !warned_merging { | |
370 | let err = format!("Merging not supported for μFISTA"); | |
371 | println!("{}", err.red()); | |
372 | warned_merging = true; | |
373 | } | |
374 | } | |
375 | } | |
376 | ||
377 | // Update inertial prameters | |
378 | let λ_prev = λ; | |
379 | λ = 2.0 * λ_prev / ( λ_prev + (4.0 + λ_prev * λ_prev).sqrt() ); | |
380 | let θ = λ / λ_prev - λ; | |
381 | ||
382 | // Perform inertial update on μ. | |
383 | // This computes μ ← (1 + θ) * μ - θ * μ_prev, pruning spikes where both μ | |
384 | // and μ_prev have zero weight. Since both have weights from the finite-dimensional | |
385 | // subproblem with a proximal projection step, this is likely to happen when the | |
386 | // spike is not needed. A copy of the pruned μ without artithmetic performed is | |
387 | // stored in μ_prev. | |
388 | let n_before_prune = μ.len(); | |
389 | μ.pruning_sub(1.0 + θ, θ, &mut μ_prev); | |
390 | debug_assert!(μ.len() <= n_before_prune); | |
391 | stats.pruned += n_before_prune - μ.len(); | |
392 | ||
393 | // Update residual | |
394 | residual = calculate_residual(&μ, opA, b); | |
395 | ||
35 | 396 | let iter = state.iteration(); |
32 | 397 | stats.this_iters += 1; |
398 | ||
35 | 399 | // Give statistics if needed |
32 | 400 | state.if_verbose(|| { |
37
c5d8bd1a7728
Generic proximal penalty support
Tuomo Valkonen <tuomov@iki.fi>
parents:
35
diff
changeset
|
401 | plotter.plot_spikes(iter, maybe_d.as_ref(), Some(&τv), &μ_prev); |
35 | 402 | full_stats(&μ_prev, ε, std::mem::replace(&mut stats, IterInfo::new())) |
403 | }); | |
404 | ||
405 | // Update main tolerance for next iteration | |
406 | ε = tolerance.update(ε, iter); | |
407 | } | |
32 | 408 | |
409 | postprocess(μ_prev, config, L2Squared, opA, b) | |
24
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
Tuomo Valkonen <tuomov@iki.fi>
parents:
13
diff
changeset
|
410 | } |