Mon, 05 Dec 2022 23:50:22 +0200
Zenodo packaging hacks
| 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: 
8diff
changeset | 6 | * Valkonen T. - _Proximal methods for point source localisation_, | 
| 
bdc57366d4f5
arXiv links, README beautification
 Tuomo Valkonen <tuomov@iki.fi> parents: 
8diff
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 | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 77 | [`crate::subproblem::InnerSettings`] in [`FBGenericConfig::inner`]. | 
| 0 | 78 | */ | 
| 79 | ||
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 80 | use colored::Colorize; | 
| 0 | 81 | use numeric_literals::replace_float_literals; | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 82 | use serde::{Deserialize, Serialize}; | 
| 0 | 83 | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 84 | use alg_tools::euclidean::Euclidean; | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 85 | use alg_tools::instance::Instance; | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 86 | use alg_tools::iterate::AlgIteratorFactory; | 
| 35 | 87 | use alg_tools::linops::{Mapping, GEMV}; | 
| 0 | 88 | use alg_tools::mapping::RealMapping; | 
| 89 | use alg_tools::nalgebra_support::ToNalgebraRealField; | |
| 90 | ||
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 91 | use crate::dataterm::{calculate_residual, DataTerm, L2Squared}; | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 92 | use crate::forward_model::{AdjointProductBoundedBy, ForwardModel}; | 
| 39 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 93 | use crate::measures::merging::SpikeMerging; | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 94 | use crate::measures::{DiscreteMeasure, RNDM}; | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 95 | use crate::plot::{PlotLookup, Plotting, SeqPlotter}; | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 96 | pub use crate::prox_penalty::{FBGenericConfig, ProxPenalty}; | 
| 32 | 97 | use crate::regularisation::RegTerm; | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 98 | use crate::types::*; | 
| 0 | 99 | |
| 24 
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
13diff
changeset | 100 | /// Settings for [`pointsource_fb_reg`]. | 
| 0 | 101 | #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] | 
| 102 | #[serde(default)] | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 103 | pub struct FBConfig<F: Float> { | 
| 0 | 104 | /// Step length scaling | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 105 | pub τ0: F, | 
| 0 | 106 | /// Generic parameters | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 107 | pub generic: FBGenericConfig<F>, | 
| 0 | 108 | } | 
| 109 | ||
| 110 | #[replace_float_literals(F::cast_from(literal))] | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 111 | impl<F: Float> Default for FBConfig<F> { | 
| 0 | 112 | fn default() -> Self { | 
| 113 | FBConfig { | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 114 | τ0: 0.99, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 115 | generic: Default::default(), | 
| 0 | 116 | } | 
| 117 | } | |
| 118 | } | |
| 119 | ||
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 120 | pub(crate) fn prune_with_stats<F: Float, const N: usize>(μ: &mut RNDM<F, N>) -> usize { | 
| 32 | 121 | let n_before_prune = μ.len(); | 
| 122 | μ.prune(); | |
| 123 | debug_assert!(μ.len() <= n_before_prune); | |
| 35 | 124 | n_before_prune - μ.len() | 
| 24 
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
13diff
changeset | 125 | } | 
| 
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
13diff
changeset | 126 | |
| 32 | 127 | #[replace_float_literals(F::cast_from(literal))] | 
| 128 | pub(crate) fn postprocess< | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 129 | F: Float, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 130 | V: Euclidean<F> + Clone, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 131 | A: GEMV<F, RNDM<F, N>, Codomain = V>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 132 | D: DataTerm<F, V, N>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 133 | const N: usize, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 134 | >( | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 135 | mut μ: RNDM<F, N>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 136 | config: &FBGenericConfig<F>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 137 | dataterm: D, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 138 | opA: &A, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 139 | b: &V, | 
| 35 | 140 | ) -> RNDM<F, N> | 
| 141 | where | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 142 | RNDM<F, N>: SpikeMerging<F>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 143 | for<'a> &'a RNDM<F, N>: Instance<RNDM<F, N>>, | 
| 35 | 144 | { | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 145 | μ.merge_spikes_fitness( | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 146 | config.final_merging_method(), | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 147 | |μ̃| dataterm.calculate_fit_op(μ̃, opA, b), | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 148 | |&v| v, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 149 | ); | 
| 32 | 150 | μ.prune(); | 
| 151 | μ | |
| 152 | } | |
| 24 
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
13diff
changeset | 153 | |
| 32 | 154 | /// Iteratively solve the pointsource localisation problem using forward-backward splitting. | 
| 0 | 155 | /// | 
| 32 | 156 | /// The settings in `config` have their [respective documentation](FBConfig). `opA` is the | 
| 0 | 157 | /// forward operator $A$, $b$ the observable, and $\lambda$ the regularisation weight. | 
| 158 | /// The operator `op𝒟` is used for forming the proximal term. Typically it is a convolution | |
| 159 | /// operator. Finally, the `iterator` is an outer loop verbosity and iteration count control | |
| 160 | /// as documented in [`alg_tools::iterate`]. | |
| 161 | /// | |
| 32 | 162 | /// For details on the mathematical formulation, see the [module level](self) documentation. | 
| 163 | /// | |
| 0 | 164 | /// The implementation relies on [`alg_tools::bisection_tree::BTFN`] presentations of | 
| 165 | /// sums of simple functions usign bisection trees, and the related | |
| 166 | /// [`alg_tools::bisection_tree::Aggregator`]s, to efficiently search for component functions | |
| 167 | /// active at a specific points, and to maximise their sums. Through the implementation of the | |
| 168 | /// [`alg_tools::bisection_tree::BT`] bisection trees, it also relies on the copy-on-write features | |
| 169 | /// of [`std::sync::Arc`] to only update relevant parts of the bisection tree when adding functions. | |
| 170 | /// | |
| 171 | /// Returns the final iterate. | |
| 172 | #[replace_float_literals(F::cast_from(literal))] | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 173 | pub fn pointsource_fb_reg<F, I, A, Reg, P, const N: usize>( | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 174 | opA: &A, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 175 | b: &A::Observable, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 176 | reg: Reg, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 177 | prox_penalty: &P, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 178 | fbconfig: &FBConfig<F>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 179 | iterator: I, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 180 | mut plotter: SeqPlotter<F, N>, | 
| 35 | 181 | ) -> RNDM<F, N> | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 182 | where | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 183 | F: Float + ToNalgebraRealField, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 184 | I: AlgIteratorFactory<IterInfo<F, N>>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 185 | for<'b> &'b A::Observable: std::ops::Neg<Output = A::Observable>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 186 | A: ForwardModel<RNDM<F, N>, F> + AdjointProductBoundedBy<RNDM<F, N>, P, FloatType = F>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 187 | A::PreadjointCodomain: RealMapping<F, N>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 188 | PlotLookup: Plotting<N>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 189 | RNDM<F, N>: SpikeMerging<F>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 190 | Reg: RegTerm<F, N>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 191 | P: ProxPenalty<F, A::PreadjointCodomain, Reg, N>, | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 192 | { | 
| 32 | 193 | // Set up parameters | 
| 34 
efa60bc4f743
Radon FB + sliding improvements
 Tuomo Valkonen <tuomov@iki.fi> parents: 
32diff
changeset | 194 | let config = &fbconfig.generic; | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 195 | let τ = fbconfig.τ0 / opA.adjoint_product_bound(prox_penalty).unwrap(); | 
| 32 | 196 | // We multiply tolerance by τ for FB since our subproblems depending on tolerances are scaled | 
| 197 | // by τ compared to the conditional gradient approach. | |
| 198 | let tolerance = config.tolerance * τ * reg.tolerance_scaling(); | |
| 199 | let mut ε = tolerance.initial(); | |
| 200 | ||
| 201 | // Initialise iterates | |
| 202 | let mut μ = DiscreteMeasure::new(); | |
| 203 | let mut residual = -b; | |
| 35 | 204 | |
| 205 | // Statistics | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 206 | let full_stats = |residual: &A::Observable, μ: &RNDM<F, N>, ε, stats| IterInfo { | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 207 | value: residual.norm2_squared_div2() + reg.apply(μ), | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 208 | n_spikes: μ.len(), | 
| 35 | 209 | ε, | 
| 210 | //postprocessing: config.postprocessing.then(|| μ.clone()), | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 211 | ..stats | 
| 35 | 212 | }; | 
| 32 | 213 | let mut stats = IterInfo::new(); | 
| 214 | ||
| 215 | // Run the algorithm | |
| 35 | 216 | for state in iterator.iter_init(|| full_stats(&residual, &μ, ε, stats.clone())) { | 
| 32 | 217 | // Calculate smooth part of surrogate model. | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 218 | let mut τv = opA.preadjoint().apply(residual * τ); | 
| 32 | 219 | |
| 220 | // Save current base point | |
| 221 | let μ_base = μ.clone(); | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 222 | |
| 32 | 223 | // Insert and reweigh | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 224 | let (maybe_d, _within_tolerances) = prox_penalty.insert_and_reweigh( | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 225 | &mut μ, &mut τv, &μ_base, None, τ, ε, config, ®, &state, &mut stats, | 
| 32 | 226 | ); | 
| 227 | ||
| 228 | // Prune and possibly merge spikes | |
| 35 | 229 | if config.merge_now(&state) { | 
| 39 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 230 | stats.merged += prox_penalty.merge_spikes( | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 231 | &mut μ, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 232 | &mut τv, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 233 | &μ_base, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 234 | None, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 235 | τ, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 236 | ε, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 237 | config, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 238 | ®, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 239 | Some(|μ̃: &RNDM<F, N>| L2Squared.calculate_fit_op(μ̃, opA, b)), | 
| 39 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 240 | ); | 
| 35 | 241 | } | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 242 | |
| 35 | 243 | stats.pruned += prune_with_stats(&mut μ); | 
| 32 | 244 | |
| 245 | // Update residual | |
| 246 | residual = calculate_residual(&μ, opA, b); | |
| 247 | ||
| 35 | 248 | let iter = state.iteration(); | 
| 32 | 249 | stats.this_iters += 1; | 
| 250 | ||
| 35 | 251 | // Give statistics if needed | 
| 32 | 252 | state.if_verbose(|| { | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 253 | plotter.plot_spikes(iter, maybe_d.as_ref(), Some(&τv), &μ); | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 254 | full_stats( | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 255 | &residual, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 256 | &μ, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 257 | ε, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 258 | std::mem::replace(&mut stats, IterInfo::new()), | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 259 | ) | 
| 35 | 260 | }); | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 261 | |
| 35 | 262 | // Update main tolerance for next iteration | 
| 263 | ε = tolerance.update(ε, iter); | |
| 264 | } | |
| 32 | 265 | |
| 266 | postprocess(μ, config, L2Squared, opA, b) | |
| 267 | } | |
| 24 
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
13diff
changeset | 268 | |
| 32 | 269 | /// Iteratively solve the pointsource localisation problem using inertial forward-backward splitting. | 
| 270 | /// | |
| 271 | /// The settings in `config` have their [respective documentation](FBConfig). `opA` is the | |
| 272 | /// forward operator $A$, $b$ the observable, and $\lambda$ the regularisation weight. | |
| 273 | /// The operator `op𝒟` is used for forming the proximal term. Typically it is a convolution | |
| 274 | /// operator. Finally, the `iterator` is an outer loop verbosity and iteration count control | |
| 275 | /// as documented in [`alg_tools::iterate`]. | |
| 276 | /// | |
| 277 | /// For details on the mathematical formulation, see the [module level](self) documentation. | |
| 278 | /// | |
| 279 | /// The implementation relies on [`alg_tools::bisection_tree::BTFN`] presentations of | |
| 280 | /// sums of simple functions usign bisection trees, and the related | |
| 281 | /// [`alg_tools::bisection_tree::Aggregator`]s, to efficiently search for component functions | |
| 282 | /// active at a specific points, and to maximise their sums. Through the implementation of the | |
| 283 | /// [`alg_tools::bisection_tree::BT`] bisection trees, it also relies on the copy-on-write features | |
| 284 | /// of [`std::sync::Arc`] to only update relevant parts of the bisection tree when adding functions. | |
| 285 | /// | |
| 286 | /// Returns the final iterate. | |
| 287 | #[replace_float_literals(F::cast_from(literal))] | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 288 | pub fn pointsource_fista_reg<F, I, A, Reg, P, const N: usize>( | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 289 | opA: &A, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 290 | b: &A::Observable, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 291 | reg: Reg, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 292 | prox_penalty: &P, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 293 | fbconfig: &FBConfig<F>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 294 | iterator: I, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 295 | mut plotter: SeqPlotter<F, N>, | 
| 35 | 296 | ) -> RNDM<F, N> | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 297 | where | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 298 | F: Float + ToNalgebraRealField, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 299 | I: AlgIteratorFactory<IterInfo<F, N>>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 300 | for<'b> &'b A::Observable: std::ops::Neg<Output = A::Observable>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 301 | A: ForwardModel<RNDM<F, N>, F> + AdjointProductBoundedBy<RNDM<F, N>, P, FloatType = F>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 302 | A::PreadjointCodomain: RealMapping<F, N>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 303 | PlotLookup: Plotting<N>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 304 | RNDM<F, N>: SpikeMerging<F>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 305 | Reg: RegTerm<F, N>, | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 306 | P: ProxPenalty<F, A::PreadjointCodomain, Reg, N>, | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 307 | { | 
| 32 | 308 | // Set up parameters | 
| 34 
efa60bc4f743
Radon FB + sliding improvements
 Tuomo Valkonen <tuomov@iki.fi> parents: 
32diff
changeset | 309 | let config = &fbconfig.generic; | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 310 | let τ = fbconfig.τ0 / opA.adjoint_product_bound(prox_penalty).unwrap(); | 
| 32 | 311 | let mut λ = 1.0; | 
| 312 | // We multiply tolerance by τ for FB since our subproblems depending on tolerances are scaled | |
| 313 | // by τ compared to the conditional gradient approach. | |
| 314 | let tolerance = config.tolerance * τ * reg.tolerance_scaling(); | |
| 315 | let mut ε = tolerance.initial(); | |
| 316 | ||
| 317 | // Initialise iterates | |
| 318 | let mut μ = DiscreteMeasure::new(); | |
| 319 | let mut μ_prev = DiscreteMeasure::new(); | |
| 320 | let mut residual = -b; | |
| 35 | 321 | let mut warned_merging = false; | 
| 322 | ||
| 323 | // Statistics | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 324 | let full_stats = |ν: &RNDM<F, N>, ε, stats| IterInfo { | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 325 | value: L2Squared.calculate_fit_op(ν, opA, b) + reg.apply(ν), | 
| 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 326 | n_spikes: ν.len(), | 
| 35 | 327 | ε, | 
| 328 | // postprocessing: config.postprocessing.then(|| ν.clone()), | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 329 | ..stats | 
| 35 | 330 | }; | 
| 32 | 331 | let mut stats = IterInfo::new(); | 
| 332 | ||
| 333 | // Run the algorithm | |
| 35 | 334 | for state in iterator.iter_init(|| full_stats(&μ, ε, stats.clone())) { | 
| 32 | 335 | // Calculate smooth part of surrogate model. | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 336 | let mut τv = opA.preadjoint().apply(residual * τ); | 
| 32 | 337 | |
| 338 | // Save current base point | |
| 339 | let μ_base = μ.clone(); | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 340 | |
| 32 | 341 | // Insert new spikes and reweigh | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 342 | let (maybe_d, _within_tolerances) = prox_penalty.insert_and_reweigh( | 
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 343 | &mut μ, &mut τv, &μ_base, None, τ, ε, config, ®, &state, &mut stats, | 
| 32 | 344 | ); | 
| 345 | ||
| 346 | // (Do not) merge spikes. | |
| 39 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 347 | if config.merge_now(&state) && !warned_merging { | 
| 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 348 | let err = format!("Merging not supported for μFISTA"); | 
| 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 349 | println!("{}", err.red()); | 
| 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 350 | warned_merging = true; | 
| 32 | 351 | } | 
| 352 | ||
| 353 | // Update inertial prameters | |
| 354 | let λ_prev = λ; | |
| 51 
0693cc9ba9f0
Update documentation references
 Tuomo Valkonen <tuomov@iki.fi> parents: 
39diff
changeset | 355 | λ = 2.0 * λ_prev / (λ_prev + (4.0 + λ_prev * λ_prev).sqrt()); | 
| 32 | 356 | let θ = λ / λ_prev - λ; | 
| 357 | ||
| 358 | // Perform inertial update on μ. | |
| 359 | // This computes μ ← (1 + θ) * μ - θ * μ_prev, pruning spikes where both μ | |
| 360 | // and μ_prev have zero weight. Since both have weights from the finite-dimensional | |
| 361 | // subproblem with a proximal projection step, this is likely to happen when the | |
| 362 | // spike is not needed. A copy of the pruned μ without artithmetic performed is | |
| 363 | // stored in μ_prev. | |
| 364 | let n_before_prune = μ.len(); | |
| 365 | μ.pruning_sub(1.0 + θ, θ, &mut μ_prev); | |
| 39 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 366 | //let μ_new = (&μ * (1.0 + θ)).sub_matching(&(&μ_prev * θ)); | 
| 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 367 | // μ_prev = μ; | 
| 
6316d68b58af
Merging adjustments, parameter tuning, etc.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
37diff
changeset | 368 | // μ = μ_new; | 
| 32 | 369 | debug_assert!(μ.len() <= n_before_prune); | 
| 370 | stats.pruned += n_before_prune - μ.len(); | |
| 371 | ||
| 372 | // Update residual | |
| 373 | residual = calculate_residual(&μ, opA, b); | |
| 374 | ||
| 35 | 375 | let iter = state.iteration(); | 
| 32 | 376 | stats.this_iters += 1; | 
| 377 | ||
| 35 | 378 | // Give statistics if needed | 
| 32 | 379 | state.if_verbose(|| { | 
| 37 
c5d8bd1a7728
Generic proximal penalty support
 Tuomo Valkonen <tuomov@iki.fi> parents: 
35diff
changeset | 380 | plotter.plot_spikes(iter, maybe_d.as_ref(), Some(&τv), &μ_prev); | 
| 35 | 381 | full_stats(&μ_prev, ε, std::mem::replace(&mut stats, IterInfo::new())) | 
| 382 | }); | |
| 383 | ||
| 384 | // Update main tolerance for next iteration | |
| 385 | ε = tolerance.update(ε, iter); | |
| 386 | } | |
| 32 | 387 | |
| 388 | postprocess(μ_prev, config, L2Squared, opA, b) | |
| 24 
d29d1fcf5423
Support arbitrary regularisation terms; implement non-positivity-constrained regularisation.
 Tuomo Valkonen <tuomov@iki.fi> parents: 
13diff
changeset | 389 | } |