src/experiments.rs

changeset 52
f0e8704d3f0e
parent 45
5200e7090e06
equal deleted inserted replaced
31:6105b5cd8d89 52:f0e8704d3f0e
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 {
164 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, 244 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity },
165 spread : base_spread, 245 spread : base_spread,
166 kernel : base_spread, 246 kernel : base_spread,
167 kernel_plot_width, 247 kernel_plot_width,
168 noise_seed, 248 noise_seed,
169 algorithm_defaults: HashMap::new(), 249 default_merge_radius,
250 algorithm_overrides: HashMap::from([
251 higher_cpos_merging(DefaultAlgorithm::RadonFB),
252 higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB),
253 ]),
170 }}) 254 }})
171 }, 255 },
172 Experiment2D => { 256 Experiment2D => {
173 let base_spread = Gaussian { variance : Variance1 }; 257 let base_spread = Gaussian { variance : Variance1 };
174 let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity }; 258 let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity };
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 };
201 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, 288 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity },
202 spread : base_spread, 289 spread : base_spread,
203 kernel : base_spread, 290 kernel : base_spread,
204 kernel_plot_width, 291 kernel_plot_width,
205 noise_seed, 292 noise_seed,
206 algorithm_defaults: HashMap::from([ 293 default_merge_radius,
207 (DefaultAlgorithm::PDPS, AlgorithmConfig::PDPS(pdps_2d())) 294 algorithm_overrides: HashMap::from([
295 higher_cpos_merging(DefaultAlgorithm::RadonFB),
296 higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB),
208 ]), 297 ]),
209 }}) 298 }})
210 }, 299 },
211 Experiment1D_L1 => { 300 Experiment1D_L1 => {
212 let base_spread = Gaussian { variance : Variance1 }; 301 let base_spread = Gaussian { variance : Variance1 };
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 {
244 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, 334 sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity },
245 spread : base_spread, 335 spread : base_spread,
246 kernel : base_spread, 336 kernel : base_spread,
247 kernel_plot_width, 337 kernel_plot_width,
248 noise_seed, 338 noise_seed,
249 algorithm_defaults: HashMap::new(), 339 default_merge_radius,
340 algorithm_overrides: HashMap::new(),
250 }}) 341 }})
251 }, 342 },
252 Experiment2D_L1 => { 343 Experiment2D_L1 => {
253 let base_spread = Gaussian { variance : Variance1 }; 344 let base_spread = Gaussian { variance : Variance1 };
254 let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity }; 345 let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity };
265 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, 356 sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity },
266 spread : Prod(spread_cutoff, base_spread), 357 spread : Prod(spread_cutoff, base_spread),
267 kernel : Prod(AutoConvolution(spread_cutoff), base_spread), 358 kernel : Prod(AutoConvolution(spread_cutoff), base_spread),
268 kernel_plot_width, 359 kernel_plot_width,
269 noise_seed, 360 noise_seed,
270 algorithm_defaults: HashMap::from([ 361 default_merge_radius,
271 (DefaultAlgorithm::PDPS, AlgorithmConfig::PDPS(pdps_2d())) 362 algorithm_overrides: HashMap::from([
272 ]), 363 ]),
273 }}) 364 }})
274 }, 365 },
275 Experiment2D_L1_Fast => { 366 Experiment2D_L1_Fast => {
276 let base_spread = HatConv { radius : Hat1 }; 367 let base_spread = HatConv { radius : Hat1 };
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 }

mercurial