| 11 |
11 |
| 12 use alg_tools::bisection_tree::*; |
12 use alg_tools::bisection_tree::*; |
| 13 use alg_tools::error::DynResult; |
13 use alg_tools::error::DynResult; |
| 14 use alg_tools::norms::Linfinity; |
14 use alg_tools::norms::Linfinity; |
| 15 |
15 |
| 16 use crate::ExperimentOverrides; |
16 use crate::{ExperimentOverrides, AlgorithmOverrides}; |
| 17 use crate::kernels::*; |
17 use crate::kernels::*; |
| 18 use crate::kernels::{SupportProductFirst as Prod}; |
18 use crate::kernels::SupportProductFirst as Prod; |
| 19 use crate::pdps::PDPSConfig; |
|
| 20 use crate::types::*; |
19 use crate::types::*; |
| 21 use crate::run::{ |
20 use crate::run::{ |
| 22 RunnableExperiment, |
21 RunnableExperiment, |
| 23 ExperimentV2, |
22 ExperimentV2, |
| |
23 ExperimentBiased, |
| 24 Named, |
24 Named, |
| 25 DefaultAlgorithm, |
25 DefaultAlgorithm, |
| 26 AlgorithmConfig |
|
| 27 }; |
26 }; |
| 28 //use crate::fb::FBGenericConfig; |
27 //use crate::fb::FBGenericConfig; |
| 29 use crate::rand_distr::{SerializableNormal, SaltAndPepper}; |
28 use crate::rand_distr::{SerializableNormal, SaltAndPepper}; |
| 30 use crate::regularisation::Regularisation; |
29 use crate::regularisation::Regularisation; |
| |
30 use alg_tools::euclidean::Euclidean; |
| |
31 use alg_tools::instance::Instance; |
| |
32 use alg_tools::mapping::Mapping; |
| |
33 use alg_tools::operator_arithmetic::{MappingSum, Weighted}; |
| 31 |
34 |
| 32 /// Experiments shorthands, to be used with the command line parser |
35 /// Experiments shorthands, to be used with the command line parser |
| 33 |
36 |
| 34 #[derive(ValueEnum, Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] |
37 #[derive(ValueEnum, Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] |
| 35 #[allow(non_camel_case_types)] |
38 #[allow(non_camel_case_types)] |
| 56 #[clap(name = "2d_l1")] |
59 #[clap(name = "2d_l1")] |
| 57 Experiment2D_L1, |
60 Experiment2D_L1, |
| 58 /// Two dimensions, “fast” spread, 1-norm data fidelity |
61 /// Two dimensions, “fast” spread, 1-norm data fidelity |
| 59 #[clap(name = "2d_l1_fast")] |
62 #[clap(name = "2d_l1_fast")] |
| 60 Experiment2D_L1_Fast, |
63 Experiment2D_L1_Fast, |
| |
64 /// One dimension, “fast” spread, 2-norm-squared data fidelity with extra TV-regularised bias |
| |
65 #[clap(name = "1d_tv_fast")] |
| |
66 Experiment1D_TV_Fast, |
| |
67 /// Two dimensions, “fast” spread, 2-norm-squared data fidelity with extra TV-regularised bias |
| |
68 #[clap(name = "2d_tv_fast")] |
| |
69 Experiment2D_TV_Fast, |
| 61 } |
70 } |
| 62 |
71 |
| 63 macro_rules! make_float_constant { |
72 macro_rules! make_float_constant { |
| 64 ($name:ident = $value:expr) => { |
73 ($name:ident = $value:expr) => { |
| 65 #[derive(Debug, Copy, Eq, PartialEq, Clone, Serialize, Deserialize)] |
74 #[derive(Debug, Copy, Eq, PartialEq, Clone, Serialize, Deserialize)] |
| 90 ([0.75, 0.45], 2.0), |
99 ([0.75, 0.45], 2.0), |
| 91 ([0.80, 0.50], 4.0), |
100 ([0.80, 0.50], 4.0), |
| 92 ([0.30, 0.70], 5.0) |
101 ([0.30, 0.70], 5.0) |
| 93 ]; |
102 ]; |
| 94 |
103 |
| |
104 /// The $\{0,1\}$-valued characteristic function of a ball as a [`Mapping`]. |
| |
105 #[derive(Debug,Copy,Clone,Serialize,PartialEq)] |
| |
106 struct BallCharacteristic<F : Float, const N : usize> { |
| |
107 pub center : Loc<F, N>, |
| |
108 pub radius : F, |
| |
109 } |
| |
110 |
| |
111 impl<F : Float, const N : usize> Mapping<Loc<F, N>> for BallCharacteristic<F, N> { |
| |
112 type Codomain =F; |
| |
113 |
| |
114 fn apply<I : Instance<Loc<F, N>>>(&self, i : I) -> F { |
| |
115 if self.center.dist2(i) <= self.radius { |
| |
116 F::ONE |
| |
117 } else { |
| |
118 F::ZERO |
| |
119 } |
| |
120 } |
| |
121 } |
| |
122 |
| 95 //#[replace_float_literals(F::cast_from(literal))] |
123 //#[replace_float_literals(F::cast_from(literal))] |
| 96 impl DefaultExperiment { |
124 impl DefaultExperiment { |
| 97 /// Convert the experiment shorthand into a runnable experiment configuration. |
125 /// Convert the experiment shorthand into a runnable experiment configuration. |
| 98 pub fn get_experiment(&self, cli : &ExperimentOverrides<float>) -> DynResult<Box<dyn RunnableExperiment<float>>> { |
126 pub fn get_experiment(&self, cli : &ExperimentOverrides<float>) -> DynResult<Box<dyn RunnableExperiment<float>>> { |
| 99 let name = "pointsource".to_string() |
127 let name = "pointsource".to_string() |
| 113 make_float_constant!(SensorWidth2DMore = 0.4/(N_SENSORS_2D_MORE as float)); |
141 make_float_constant!(SensorWidth2DMore = 0.4/(N_SENSORS_2D_MORE as float)); |
| 114 |
142 |
| 115 make_float_constant!(Variance1 = 0.05.powi(2)); |
143 make_float_constant!(Variance1 = 0.05.powi(2)); |
| 116 make_float_constant!(CutOff1 = 0.15); |
144 make_float_constant!(CutOff1 = 0.15); |
| 117 make_float_constant!(Hat1 = 0.16); |
145 make_float_constant!(Hat1 = 0.16); |
| |
146 make_float_constant!(HatBias = 0.05); |
| 118 |
147 |
| 119 // We use a different step length for PDPS in 2D experiments |
148 // We use a different step length for PDPS in 2D experiments |
| 120 let pdps_2d = || { |
149 // let pdps_2d = (DefaultAlgorithm::PDPS, |
| 121 let τ0 = 3.0; |
150 // AlgorithmOverrides { |
| 122 PDPSConfig { |
151 // tau0 : Some(3.0), |
| 123 τ0, |
152 // sigma0 : Some(0.99 / 3.0), |
| 124 σ0 : 0.99 / τ0, |
153 // .. Default::default() |
| |
154 // } |
| |
155 // ); |
| |
156 // let radon_pdps_2d = (DefaultAlgorithm::RadonPDPS, |
| |
157 // AlgorithmOverrides { |
| |
158 // tau0 : Some(3.0), |
| |
159 // sigma0 : Some(0.99 / 3.0), |
| |
160 // .. Default::default() |
| |
161 // } |
| |
162 // ); |
| |
163 let sliding_fb_cut_gaussian = (DefaultAlgorithm::SlidingFB, |
| |
164 AlgorithmOverrides { |
| |
165 theta0 : Some(0.3), |
| 125 .. Default::default() |
166 .. Default::default() |
| 126 } |
167 } |
| 127 }; |
168 ); |
| 128 |
169 // let higher_cpos = |alg| (alg, |
| |
170 // AlgorithmOverrides { |
| |
171 // transport_tolerance_pos : Some(1000.0), |
| |
172 // .. Default::default() |
| |
173 // } |
| |
174 // ); |
| |
175 let higher_cpos_merging = |alg| (alg, |
| |
176 AlgorithmOverrides { |
| |
177 transport_tolerance_pos : Some(1000.0), |
| |
178 merge : Some(true), |
| |
179 fitness_merging : Some(true), |
| |
180 .. Default::default() |
| |
181 } |
| |
182 ); |
| |
183 let higher_cpos_merging_steptune = |alg| (alg, |
| |
184 AlgorithmOverrides { |
| |
185 transport_tolerance_pos : Some(1000.0), |
| |
186 theta0 : Some(0.3), |
| |
187 merge : Some(true), |
| |
188 fitness_merging : Some(true), |
| |
189 .. Default::default() |
| |
190 } |
| |
191 ); |
| |
192 let much_higher_cpos_merging_steptune = |alg| (alg, |
| |
193 AlgorithmOverrides { |
| |
194 transport_tolerance_pos : Some(10000.0), |
| |
195 sigma0 : Some(0.15), |
| |
196 theta0 : Some(0.3), |
| |
197 merge : Some(true), |
| |
198 fitness_merging : Some(true), |
| |
199 .. Default::default() |
| |
200 } |
| |
201 ); |
| 129 // We add a hash of the experiment name to the configured |
202 // We add a hash of the experiment name to the configured |
| 130 // noise seed to not use the same noise for different experiments. |
203 // noise seed to not use the same noise for different experiments. |
| 131 let mut h = DefaultHasher::new(); |
204 let mut h = DefaultHasher::new(); |
| 132 name.hash(&mut h); |
205 name.hash(&mut h); |
| 133 let noise_seed = cli.noise_seed.unwrap_or(BASE_SEED) + h.finish(); |
206 let noise_seed = cli.noise_seed.unwrap_or(BASE_SEED) + h.finish(); |
| 134 |
207 |
| |
208 let default_merge_radius = 0.01; |
| |
209 |
| 135 use DefaultExperiment::*; |
210 use DefaultExperiment::*; |
| 136 Ok(match self { |
211 Ok(match self { |
| 137 Experiment1D => { |
212 Experiment1D => { |
| 138 let base_spread = Gaussian { variance : Variance1 }; |
213 let base_spread = Gaussian { variance : Variance1 }; |
| 139 let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity }; |
214 let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity }; |
| 140 Box::new(Named { name, data : ExperimentV2 { |
215 Box::new(Named { name, data : ExperimentV2 { |
| 141 domain : [[0.0, 1.0]].into(), |
216 domain : [[0.0, 1.0]].into(), |
| 142 sensor_count : [N_SENSORS_1D], |
217 sensor_count : [N_SENSORS_1D], |
| 143 regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.09)), |
218 regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.08)), |
| 144 noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.2))?, |
219 noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.2))?, |
| 145 dataterm : DataTerm::L2Squared, |
220 dataterm : DataTerm::L2Squared, |
| 146 μ_hat : MU_TRUE_1D_BASIC.into(), |
221 μ_hat : MU_TRUE_1D_BASIC.into(), |
| 147 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, |
222 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, |
| 148 spread : Prod(spread_cutoff, base_spread), |
223 spread : Prod(spread_cutoff, base_spread), |
| 149 kernel : Prod(AutoConvolution(spread_cutoff), base_spread), |
224 kernel : Prod(AutoConvolution(spread_cutoff), base_spread), |
| 150 kernel_plot_width, |
225 kernel_plot_width, |
| 151 noise_seed, |
226 noise_seed, |
| 152 algorithm_defaults: HashMap::new(), |
227 default_merge_radius, |
| |
228 algorithm_overrides: HashMap::from([ |
| |
229 sliding_fb_cut_gaussian, |
| |
230 higher_cpos_merging(DefaultAlgorithm::RadonFB), |
| |
231 higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), |
| |
232 ]), |
| 153 }}) |
233 }}) |
| 154 }, |
234 }, |
| 155 Experiment1DFast => { |
235 Experiment1DFast => { |
| 156 let base_spread = HatConv { radius : Hat1 }; |
236 let base_spread = HatConv { radius : Hat1 }; |
| 157 Box::new(Named { name, data : ExperimentV2 { |
237 Box::new(Named { name, data : ExperimentV2 { |
| 182 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, |
266 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, |
| 183 spread : Prod(spread_cutoff, base_spread), |
267 spread : Prod(spread_cutoff, base_spread), |
| 184 kernel : Prod(AutoConvolution(spread_cutoff), base_spread), |
268 kernel : Prod(AutoConvolution(spread_cutoff), base_spread), |
| 185 kernel_plot_width, |
269 kernel_plot_width, |
| 186 noise_seed, |
270 noise_seed, |
| 187 algorithm_defaults: HashMap::from([ |
271 default_merge_radius, |
| 188 (DefaultAlgorithm::PDPS, AlgorithmConfig::PDPS(pdps_2d())) |
272 algorithm_overrides: HashMap::from([ |
| |
273 sliding_fb_cut_gaussian, |
| |
274 higher_cpos_merging(DefaultAlgorithm::RadonFB), |
| |
275 higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), |
| 189 ]), |
276 ]), |
| 190 }}) |
277 }}) |
| 191 }, |
278 }, |
| 192 Experiment2DFast => { |
279 Experiment2DFast => { |
| 193 let base_spread = HatConv { radius : Hat1 }; |
280 let base_spread = HatConv { radius : Hat1 }; |
| 224 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, |
313 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, |
| 225 spread : Prod(spread_cutoff, base_spread), |
314 spread : Prod(spread_cutoff, base_spread), |
| 226 kernel : Prod(AutoConvolution(spread_cutoff), base_spread), |
315 kernel : Prod(AutoConvolution(spread_cutoff), base_spread), |
| 227 kernel_plot_width, |
316 kernel_plot_width, |
| 228 noise_seed, |
317 noise_seed, |
| 229 algorithm_defaults: HashMap::new(), |
318 default_merge_radius, |
| |
319 algorithm_overrides: HashMap::new(), |
| 230 }}) |
320 }}) |
| 231 }, |
321 }, |
| 232 Experiment1D_L1_Fast => { |
322 Experiment1D_L1_Fast => { |
| 233 let base_spread = HatConv { radius : Hat1 }; |
323 let base_spread = HatConv { radius : Hat1 }; |
| 234 Box::new(Named { name, data : ExperimentV2 { |
324 Box::new(Named { name, data : ExperimentV2 { |
| 287 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, |
378 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, |
| 288 spread : base_spread, |
379 spread : base_spread, |
| 289 kernel : base_spread, |
380 kernel : base_spread, |
| 290 kernel_plot_width, |
381 kernel_plot_width, |
| 291 noise_seed, |
382 noise_seed, |
| 292 algorithm_defaults: HashMap::from([ |
383 default_merge_radius, |
| 293 (DefaultAlgorithm::PDPS, AlgorithmConfig::PDPS(pdps_2d())) |
384 algorithm_overrides: HashMap::from([ |
| 294 ]), |
385 ]), |
| |
386 }}) |
| |
387 }, |
| |
388 Experiment1D_TV_Fast => { |
| |
389 let base_spread = HatConv { radius : HatBias }; |
| |
390 Box::new(Named { name, data : ExperimentBiased { |
| |
391 λ : 0.02, |
| |
392 bias : MappingSum::new([ |
| |
393 Weighted::new(1.0, BallCharacteristic{ center : 0.3.into(), radius : 0.2 }), |
| |
394 Weighted::new(0.5, BallCharacteristic{ center : 0.6.into(), radius : 0.3 }), |
| |
395 ]), |
| |
396 base : ExperimentV2 { |
| |
397 domain : [[0.0, 1.0]].into(), |
| |
398 sensor_count : [N_SENSORS_1D], |
| |
399 regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.2)), |
| |
400 noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.1))?, |
| |
401 dataterm : DataTerm::L2Squared, |
| |
402 μ_hat : MU_TRUE_1D_BASIC.into(), |
| |
403 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, |
| |
404 spread : base_spread, |
| |
405 kernel : base_spread, |
| |
406 kernel_plot_width, |
| |
407 noise_seed, |
| |
408 default_merge_radius, |
| |
409 algorithm_overrides: HashMap::from([ |
| |
410 higher_cpos_merging_steptune(DefaultAlgorithm::RadonForwardPDPS), |
| |
411 higher_cpos_merging_steptune(DefaultAlgorithm::RadonSlidingPDPS), |
| |
412 ]), |
| |
413 }, |
| |
414 }}) |
| |
415 }, |
| |
416 Experiment2D_TV_Fast => { |
| |
417 let base_spread = HatConv { radius : Hat1 }; |
| |
418 Box::new(Named { name, data : ExperimentBiased { |
| |
419 λ : 0.005, |
| |
420 bias : MappingSum::new([ |
| |
421 Weighted::new(1.0, BallCharacteristic{ center : [0.3, 0.3].into(), radius : 0.2 }), |
| |
422 Weighted::new(0.5, BallCharacteristic{ center : [0.6, 0.6].into(), radius : 0.3 }), |
| |
423 ]), |
| |
424 base : ExperimentV2 { |
| |
425 domain : [[0.0, 1.0]; 2].into(), |
| |
426 sensor_count : [N_SENSORS_2D; 2], |
| |
427 regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.06)), |
| |
428 noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.15))?, //0.25 |
| |
429 dataterm : DataTerm::L2Squared, |
| |
430 μ_hat : MU_TRUE_2D_BASIC.into(), |
| |
431 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, |
| |
432 spread : base_spread, |
| |
433 kernel : base_spread, |
| |
434 kernel_plot_width, |
| |
435 noise_seed, |
| |
436 default_merge_radius, |
| |
437 algorithm_overrides: HashMap::from([ |
| |
438 much_higher_cpos_merging_steptune(DefaultAlgorithm::RadonForwardPDPS), |
| |
439 much_higher_cpos_merging_steptune(DefaultAlgorithm::RadonSlidingPDPS), |
| |
440 ]), |
| |
441 }, |
| 295 }}) |
442 }}) |
| 296 }, |
443 }, |
| 297 }) |
444 }) |
| 298 } |
445 } |
| 299 } |
446 } |