src/prox_penalty.rs

changeset 52
f0e8704d3f0e
parent 51
0693cc9ba9f0
equal deleted inserted replaced
31:6105b5cd8d89 52:f0e8704d3f0e
1 /*!
2 Proximal penalty abstraction
3 */
4
5 use alg_tools::types::*;
6 use numeric_literals::replace_float_literals;
7 use serde::{Deserialize, Serialize};
8
9 use crate::measures::merging::SpikeMergingMethod;
10 use crate::measures::RNDM;
11 use crate::regularisation::RegTerm;
12 use crate::subproblem::InnerSettings;
13 use crate::tolerance::Tolerance;
14 use crate::types::{IterInfo, RefinementSettings};
15 use alg_tools::iterate::{AlgIterator, AlgIteratorIteration};
16 use alg_tools::mapping::RealMapping;
17 use alg_tools::nalgebra_support::ToNalgebraRealField;
18
19 pub mod radon_squared;
20 pub mod wave;
21 pub use radon_squared::RadonSquared;
22
23 /// Settings for the solution of the stepwise optimality condition.
24 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)]
25 #[serde(default)]
26 pub struct FBGenericConfig<F: Float> {
27 /// Tolerance for point insertion.
28 pub tolerance: Tolerance<F>,
29
30 /// Stop looking for predual maximum (where to isert a new point) below
31 /// `tolerance` multiplied by this factor.
32 ///
33 /// Not used by [`crate::prox_penalty::radon_squared`].
34 pub insertion_cutoff_factor: F,
35
36 /// Settings for branch and bound refinement when looking for predual maxima
37 pub refinement: RefinementSettings<F>,
38
39 /// Maximum insertions within each outer iteration
40 ///
41 /// Not used by [`crate::prox_penalty::radon_squared`].
42 pub max_insertions: usize,
43
44 /// Pair `(n, m)` for maximum insertions `m` on first `n` iterations.
45 ///
46 /// Not used by [`crate::prox_penalty::radon_squared`].
47 pub bootstrap_insertions: Option<(usize, usize)>,
48
49 /// Inner method settings
50 pub inner: InnerSettings<F>,
51
52 /// Spike merging method
53 pub merging: SpikeMergingMethod<F>,
54
55 /// Tolerance multiplier for merges
56 pub merge_tolerance_mult: F,
57
58 /// Merge spikes after last step (even if merging not generally enabled)
59 pub final_merging: bool,
60
61 /// Use fitness as merging criterion. Implies worse convergence guarantees.
62 pub fitness_merging: bool,
63
64 /// Iterations between merging heuristic tries
65 pub merge_every: usize,
66 // /// Save $μ$ for postprocessing optimisation
67 // pub postprocessing : bool
68 }
69
70 #[replace_float_literals(F::cast_from(literal))]
71 impl<F: Float> Default for FBGenericConfig<F> {
72 fn default() -> Self {
73 FBGenericConfig {
74 tolerance: Default::default(),
75 insertion_cutoff_factor: 1.0,
76 refinement: Default::default(),
77 max_insertions: 100,
78 //bootstrap_insertions : None,
79 bootstrap_insertions: Some((10, 1)),
80 inner: Default::default(),
81 merging: Default::default(),
82 final_merging: true,
83 fitness_merging: false,
84 merge_every: 10,
85 merge_tolerance_mult: 2.0,
86 // postprocessing : false,
87 }
88 }
89 }
90
91 impl<F: Float> FBGenericConfig<F> {
92 /// Check if merging should be attempted this iteration
93 pub fn merge_now<I: AlgIterator>(&self, state: &AlgIteratorIteration<I>) -> bool {
94 self.merging.enabled && state.iteration() % self.merge_every == 0
95 }
96
97 /// Returns the final merging method
98 pub fn final_merging_method(&self) -> SpikeMergingMethod<F> {
99 SpikeMergingMethod {
100 enabled: self.final_merging,
101 ..self.merging
102 }
103 }
104 }
105
106 /// Trait for proximal penalties
107 pub trait ProxPenalty<F, PreadjointCodomain, Reg, const N: usize>
108 where
109 F: Float + ToNalgebraRealField,
110 Reg: RegTerm<F, N>,
111 {
112 type ReturnMapping: RealMapping<F, N>;
113
114 /// Insert new spikes into `μ` to approximately satisfy optimality conditions
115 /// with the forward step term fixed to `τv`.
116 ///
117 /// May return `τv + w` for `w` a subdifferential of the regularisation term `reg`,
118 /// as well as an indication of whether the tolerance bounds `ε` are satisfied.
119 ///
120 /// `μ_base + ν_delta` is the base point, where `μ` and `μ_base` are assumed to have the same
121 /// spike locations, while `ν_delta` may have different locations.
122 ///
123 /// `τv` is mutable to allow [`alg_tools::bisection_tree::BTFN`] refinement.
124 /// Actual values of `τv` are not supposed to be mutated.
125 fn insert_and_reweigh<I>(
126 &self,
127 μ: &mut RNDM<F, N>,
128 τv: &mut PreadjointCodomain,
129 μ_base: &RNDM<F, N>,
130 ν_delta: Option<&RNDM<F, N>>,
131 τ: F,
132 ε: F,
133 config: &FBGenericConfig<F>,
134 reg: &Reg,
135 state: &AlgIteratorIteration<I>,
136 stats: &mut IterInfo<F, N>,
137 ) -> (Option<Self::ReturnMapping>, bool)
138 where
139 I: AlgIterator;
140
141 /// Merge spikes, if possible.
142 ///
143 /// Either optimality condition merging or objective value (fitness) merging
144 /// may be used, the latter only if `fitness` is provided and `config.fitness_merging`
145 /// is set.
146 fn merge_spikes(
147 &self,
148 μ: &mut RNDM<F, N>,
149 τv: &mut PreadjointCodomain,
150 μ_base: &RNDM<F, N>,
151 ν_delta: Option<&RNDM<F, N>>,
152 τ: F,
153 ε: F,
154 config: &FBGenericConfig<F>,
155 reg: &Reg,
156 fitness: Option<impl Fn(&RNDM<F, N>) -> F>,
157 ) -> usize;
158
159 /// Merge spikes, if possible.
160 ///
161 /// Unlike [`Self::merge_spikes`], this variant only supports optimality condition based merging
162 #[inline]
163 fn merge_spikes_no_fitness(
164 &self,
165 μ: &mut RNDM<F, N>,
166 τv: &mut PreadjointCodomain,
167 μ_base: &RNDM<F, N>,
168 ν_delta: Option<&RNDM<F, N>>,
169 τ: F,
170 ε: F,
171 config: &FBGenericConfig<F>,
172 reg: &Reg,
173 ) -> usize {
174 /// This is a hack to create a `None` of same type as a `Some`
175 // for the `impl Fn` parameter of `merge_spikes`.
176 #[inline]
177 fn into_none<T>(_: Option<T>) -> Option<T> {
178 None
179 }
180 self.merge_spikes(
181 μ,
182 τv,
183 μ_base,
184 ν_delta,
185 τ,
186 ε,
187 config,
188 reg,
189 into_none(Some(|_: &RNDM<F, N>| F::ZERO)),
190 )
191 }
192 }

mercurial