src/weight_optim.rs

Tue, 29 Nov 2022 15:36:12 +0200

author
Tuomo Valkonen <tuomov@iki.fi>
date
Tue, 29 Nov 2022 15:36:12 +0200
changeset 2
7a953a87b6c1
permissions
-rw-r--r--

fubar

2
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
1 //! Weight optimisation routines
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
2
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
3 use numeric_literals::replace_float_literals;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
4 use alg_tools::nalgebra_support::ToNalgebraRealField;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
5 use alg_tools::loc::Loc;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
6 use alg_tools::iterate::AlgIteratorFactory;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
7 use crate::types::*;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
8 use crate::subproblem::*;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
9 use crate::measures::*;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
10 use crate::forward_model::ForwardModel;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
11
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
12 /// Helper struct for pre-initialising the finite-dimensional subproblems solver
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
13 /// [`prepare_optimise_weights_l2`].
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
14 ///
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
15 /// The pre-initialisation is done by [`prepare_optimise_weights_l2`].
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
16 pub struct FindimData<F : Float> {
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
17 opAnorm_squared : F
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
18 }
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
19
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
20 /// Return a pre-initialisation struct for [`prepare_optimise_weights_l2`].
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
21 ///
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
22 /// The parameter `opA` is the forward operator $A$.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
23 pub fn prepare_optimise_weights<F, A, const N : usize>(opA : &A) -> FindimData<F>
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
24 where F : Float + ToNalgebraRealField,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
25 A : ForwardModel<Loc<F, N>, F> {
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
26 FindimData{
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
27 opAnorm_squared : opA.opnorm_bound().powi(2)
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
28 }
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
29 }
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
30
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
31 /// Solve the finite-dimensional weight optimisation problem for the 2-norm-squared data fidelity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
32 /// point source localisation problem.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
33 ///
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
34 /// That is, we minimise
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
35 /// <div>$$
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
36 /// μ ↦ \frac{1}{2}\|Aμ-b\|_2^2 + α\|μ\|_ℳ + δ_{≥ 0}(μ)
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
37 /// $$</div>
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
38 /// only with respect to the weights of $μ$.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
39 ///
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
40 /// The parameter `μ` is the discrete measure whose weights are to be optimised.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
41 /// The `opA` parameter is the forward operator $A$, while `b`$ and `α` are as in the
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
42 /// objective above. The method parameter are set in `inner` (see [`InnerSettings`]), while
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
43 /// `iterator` is used to iterate the steps of the method, and `plotter` may be used to
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
44 /// save intermediate iteration states as images. The parameter `findim_data` should be
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
45 /// prepared using [`prepare_optimise_weights`]:
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
46 ///
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
47 /// Returns the number of iterations taken by the method configured in `inner`.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
48 pub fn optimise_weights_l2<'a, F, A, I, const N : usize>(
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
49 μ : &mut DiscreteMeasure<Loc<F, N>, F>,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
50 opA : &'a A,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
51 b : &A::Observable,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
52 α : F,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
53 findim_data : &FindimData<F>,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
54 inner : &InnerSettings<F>,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
55 iterator : I
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
56 ) -> usize
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
57 where F : Float + ToNalgebraRealField,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
58 I : AlgIteratorFactory<F>,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
59 A : ForwardModel<Loc<F, N>, F>
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
60 {
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
61 // Form and solve finite-dimensional subproblem.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
62 let (Ã, g̃) = opA.findim_quadratic_model(&μ, b);
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
63 let mut x = μ.masses_dvector();
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
64
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
65 // `inner_τ1` is based on an estimate of the operator norm of $A$ from ℳ(Ω) to
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
66 // ℝ^n. This estimate is a good one for the matrix norm from ℝ^m to ℝ^n when the
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
67 // former is equipped with the 1-norm. We need the 2-norm. To pass from 1-norm to
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
68 // 2-norm, we estimate
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
69 // ‖A‖_{2,2} := sup_{‖x‖_2 ≤ 1} ‖Ax‖_2 ≤ sup_{‖x‖_1 ≤ C} ‖Ax‖_2
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
70 // = C sup_{‖x‖_1 ≤ 1} ‖Ax‖_2 = C ‖A‖_{1,2},
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
71 // where C = √m satisfies ‖x‖_1 ≤ C ‖x‖_2. Since we are intested in ‖A_*A‖, no
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
72 // square root is needed when we scale:
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
73 let inner_τ = inner.τ0 / (findim_data.opAnorm_squared * F::cast_from(μ.len()));
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
74 let iters = quadratic_nonneg(inner.method, &Ã, &g̃, α, &mut x, inner_τ, iterator);
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
75 // Update masses of μ based on solution of finite-dimensional subproblem.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
76 μ.set_masses_dvector(&x);
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
77
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
78 iters
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
79 }
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
80
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
81 /// Solve the finite-dimensional weight optimisation problem for the 2-norm-squared data fidelity
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
82 /// point source localisation problem.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
83 ///
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
84 /// That is, we minimise
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
85 /// <div>$$
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
86 /// μ ↦ \|Aμ-b\|_1 + α\|μ\|_ℳ + δ_{≥ 0}(μ)
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
87 /// $$</div>
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
88 /// only with respect to the weights of $μ$.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
89 ///
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
90 /// The parameter `μ` is the discrete measure whose weights are to be optimised.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
91 /// The `opA` parameter is the forward operator $A$, while `b`$ and `α` are as in the
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
92 /// objective above. The method parameter are set in `inner` (see [`InnerSettings`]), while
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
93 /// `iterator` is used to iterate the steps of the method, and `plotter` may be used to
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
94 /// save intermediate iteration states as images.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
95 ///
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
96 /// Returns the number of iterations taken by the method configured in `inner`.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
97 #[replace_float_literals(F::cast_from(literal))]
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
98 pub fn optimise_weights_l1<'a, F, A, I, const N : usize>(
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
99 μ : &mut DiscreteMeasure<Loc<F, N>, F>,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
100 opA : &'a A,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
101 b : &A::Observable,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
102 α : F,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
103 findim_data : &FindimData<F>,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
104 inner : &InnerSettings<F>,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
105 iterator : I
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
106 ) -> usize
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
107 where F : Float + ToNalgebraRealField,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
108 I : AlgIteratorFactory<F>,
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
109 A : ForwardModel<Loc<F, N>, F>
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
110 {
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
111 // Form and solve finite-dimensional subproblem.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
112 let à = opA.findim_model(&μ);
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
113 let mut x = μ.masses_dvector();
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
114
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
115 // `inner_τ1` is based on an estimate of the operator norm of $A$ from ℳ(Ω) to
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
116 // ℝ^n. This estimate is a good one for the matrix norm from ℝ^m to ℝ^n when the
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
117 // former is equipped with the 1-norm. We need the 2-norm. To pass from 1-norm to
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
118 // 2-norm, we estimate
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
119 // ‖A‖_{2,2} := sup_{‖x‖_2 ≤ 1} ‖Ax‖_2 ≤ sup_{‖x‖_1 ≤ C} ‖Ax‖_2
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
120 // = C sup_{‖x‖_1 ≤ 1} ‖Ax‖_2 = C ‖A‖_{1,2},
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
121 // where C = √m satisfies ‖x‖_1 ≤ C ‖x‖_2. Since we are intested in ‖A_*A‖, no
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
122 // square root is needed when we scale:
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
123 let l = (findim_data.opAnorm_squared * F::cast_from(μ.len())).sqrt();
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
124 let inner_σ = (0.99 / inner.τ0) / l;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
125 let inner_τ = inner.τ0 / l;
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
126 let iters = l1_nonneg(L1InnerMethod::PDPS, &Ã, b, α, &mut x, inner_τ, inner_σ, iterator);
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
127 // Update masses of μ based on solution of finite-dimensional subproblem.
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
128 μ.set_masses_dvector(&x);
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
129
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
130 iters
Tuomo Valkonen <tuomov@iki.fi>
parents:
diff changeset
131 }

mercurial