| 50 ε: F, |
50 ε: F, |
| 51 config: &InsertionConfig<F>, |
51 config: &InsertionConfig<F>, |
| 52 reg: &Reg, |
52 reg: &Reg, |
| 53 state: &AlgIteratorIteration<I>, |
53 state: &AlgIteratorIteration<I>, |
| 54 stats: &mut IterInfo<F>, |
54 stats: &mut IterInfo<F>, |
| 55 ) -> DynResult<(Option<Self::ReturnMapping>, bool)> |
55 ) -> DynResult<bool> |
| 56 where |
56 where |
| 57 I: AlgIterator, |
57 I: AlgIterator, |
| 58 { |
58 { |
| 59 let op𝒟norm = self.opnorm_bound(Radon, Linfinity)?; |
59 let op𝒟norm = self.opnorm_bound(Radon, Linfinity)?; |
| 60 |
60 |
| 68 let μ_base = μ.clone(); |
68 let μ_base = μ.clone(); |
| 69 let ω0 = self.apply(&μ_base); |
69 let ω0 = self.apply(&μ_base); |
| 70 |
70 |
| 71 // Add points to support until within error tolerance or maximum insertion count reached. |
71 // Add points to support until within error tolerance or maximum insertion count reached. |
| 72 let mut count = 0; |
72 let mut count = 0; |
| 73 let (within_tolerances, d) = 'insertion: loop { |
73 let within_tolerances = 'insertion: loop { |
| 74 if μ.len() > 0 { |
74 if μ.len() > 0 { |
| 75 // Form finite-dimensional subproblem. The subproblem references to the original μ^k |
75 // Form finite-dimensional subproblem. The subproblem references to the original μ^k |
| 76 // from the beginning of the iteration are all contained in the immutable c and g. |
76 // from the beginning of the iteration are all contained in the immutable c and g. |
| 77 // TODO: observe negation of -τv after switch from minus_τv: finite-dimensional |
77 // TODO: observe negation of -τv after switch from minus_τv: finite-dimensional |
| 78 // problems have not yet been updated to sign change. |
78 // problems have not yet been updated to sign change. |
| 113 }; |
113 }; |
| 114 |
114 |
| 115 // Find a spike to insert, if needed |
115 // Find a spike to insert, if needed |
| 116 let (ξ, _v_ξ, in_bounds) = |
116 let (ξ, _v_ξ, in_bounds) = |
| 117 match reg.find_tolerance_violation(&mut d, τ, ε, skip_by_rough_check, config) { |
117 match reg.find_tolerance_violation(&mut d, τ, ε, skip_by_rough_check, config) { |
| 118 None => break 'insertion (true, d), |
118 None => break 'insertion true, |
| 119 Some(res) => res, |
119 Some(res) => res, |
| 120 }; |
120 }; |
| 121 |
121 |
| 122 // Break if maximum insertion count reached |
122 // Break if maximum insertion count reached |
| 123 if count >= max_insertions { |
123 if count >= max_insertions { |
| 124 break 'insertion (in_bounds, d); |
124 break 'insertion in_bounds; |
| 125 } |
125 } |
| 126 |
126 |
| 127 // No point in optimising the weight here; the finite-dimensional algorithm is fast. |
127 // No point in optimising the weight here; the finite-dimensional algorithm is fast. |
| 128 *μ += DeltaMeasure { x: ξ, α: 0.0 }; |
128 *μ += DeltaMeasure { x: ξ, α: 0.0 }; |
| 129 count += 1; |
129 count += 1; |
| 137 subproblem solution tolerance" |
137 subproblem solution tolerance" |
| 138 ); |
138 ); |
| 139 println!("{}", err.red()); |
139 println!("{}", err.red()); |
| 140 } |
140 } |
| 141 |
141 |
| 142 Ok((Some(d), within_tolerances)) |
142 Ok(within_tolerances) |
| |
143 } |
| |
144 |
| |
145 fn reweigh<I>( |
| |
146 &self, |
| |
147 μ: &mut DiscreteMeasure<Domain, F>, |
| |
148 τv: &mut M, |
| |
149 τ: F, |
| |
150 ε: F, |
| |
151 config: &InsertionConfig<F>, |
| |
152 reg: &Reg, |
| |
153 _state: &AlgIteratorIteration<I>, |
| |
154 stats: &mut IterInfo<F>, |
| |
155 ) -> DynResult<()> |
| |
156 where |
| |
157 I: AlgIterator, |
| |
158 { |
| |
159 if μ.len() > 0 { |
| |
160 let op𝒟norm = self.opnorm_bound(Radon, Linfinity)?; |
| |
161 let ω0 = self.apply(&*μ); |
| |
162 |
| |
163 // Form finite-dimensional subproblem. The subproblem references to the original μ^k |
| |
164 // from the beginning of the iteration are all contained in the immutable c and g. |
| |
165 // TODO: observe negation of -τv after switch from minus_τv: finite-dimensional |
| |
166 // problems have not yet been updated to sign change. |
| |
167 let à = self.findim_matrix(μ.iter_locations()); |
| |
168 let g̃ = DVector::from_iterator( |
| |
169 μ.len(), |
| |
170 μ.iter_locations() |
| |
171 .map(|ζ| ω0.apply(ζ) - τv.apply(ζ)) |
| |
172 .map(F::to_nalgebra_mixed), |
| |
173 ); |
| |
174 let mut x = μ.masses_dvector(); |
| |
175 |
| |
176 // The gradient of the forward component of the inner objective is C^*𝒟Cx - g̃. |
| |
177 // We have |C^*𝒟Cx|_2 = sup_{|z|_2 ≤ 1} ⟨z, C^*𝒟Cx⟩ = sup_{|z|_2 ≤ 1} ⟨Cz|𝒟Cx⟩ |
| |
178 // ≤ sup_{|z|_2 ≤ 1} |Cz|_ℳ |𝒟Cx|_∞ ≤ sup_{|z|_2 ≤ 1} |Cz|_ℳ |𝒟| |Cx|_ℳ |
| |
179 // ≤ sup_{|z|_2 ≤ 1} |z|_1 |𝒟| |x|_1 ≤ sup_{|z|_2 ≤ 1} n |z|_2 |𝒟| |x|_2 |
| |
180 // = n |𝒟| |x|_2, where n is the number of points. Therefore |
| |
181 let Ã_normest = op𝒟norm * F::cast_from(μ.len()); |
| |
182 |
| |
183 // Solve finite-dimensional subproblem. |
| |
184 stats.inner_iters += reg.solve_findim(&Ã, &g̃, τ, &mut x, Ã_normest, ε, config); |
| |
185 |
| |
186 // Update masses of μ based on solution of finite-dimensional subproblem. |
| |
187 μ.set_masses_dvector(&x); |
| |
188 } |
| |
189 |
| |
190 Ok(()) |
| 143 } |
191 } |
| 144 |
192 |
| 145 fn merge_spikes( |
193 fn merge_spikes( |
| 146 &self, |
194 &self, |
| 147 μ: &mut DiscreteMeasure<Domain, F>, |
195 μ: &mut DiscreteMeasure<Domain, F>, |