src/experiments.rs

changeset 52
f0e8704d3f0e
parent 45
5200e7090e06
--- a/src/experiments.rs	Tue Aug 01 10:25:09 2023 +0300
+++ b/src/experiments.rs	Mon Feb 17 13:54:53 2025 -0500
@@ -13,21 +13,24 @@
 use alg_tools::error::DynResult;
 use alg_tools::norms::Linfinity;
 
-use crate::ExperimentOverrides;
+use crate::{ExperimentOverrides, AlgorithmOverrides};
 use crate::kernels::*;
-use crate::kernels::{SupportProductFirst as Prod};
-use crate::pdps::PDPSConfig;
+use crate::kernels::SupportProductFirst as Prod;
 use crate::types::*;
 use crate::run::{
     RunnableExperiment,
     ExperimentV2,
+    ExperimentBiased,
     Named,
     DefaultAlgorithm,
-    AlgorithmConfig
 };
 //use crate::fb::FBGenericConfig;
 use crate::rand_distr::{SerializableNormal, SaltAndPepper};
 use crate::regularisation::Regularisation;
+use alg_tools::euclidean::Euclidean;
+use alg_tools::instance::Instance;
+use alg_tools::mapping::Mapping;
+use alg_tools::operator_arithmetic::{MappingSum, Weighted};
 
 /// Experiments shorthands, to be used with the command line parser
 
@@ -58,6 +61,12 @@
     /// Two dimensions, “fast” spread, 1-norm data fidelity
     #[clap(name = "2d_l1_fast")]
     Experiment2D_L1_Fast,
+    /// One dimension, “fast” spread, 2-norm-squared data fidelity with extra TV-regularised bias
+    #[clap(name = "1d_tv_fast")]
+    Experiment1D_TV_Fast,
+    /// Two dimensions, “fast” spread, 2-norm-squared data fidelity with extra TV-regularised bias
+    #[clap(name = "2d_tv_fast")]
+    Experiment2D_TV_Fast,
 }
 
 macro_rules! make_float_constant {
@@ -92,6 +101,25 @@
     ([0.30, 0.70], 5.0)
 ];
 
+/// The $\{0,1\}$-valued characteristic function of a ball as a [`Mapping`].
+#[derive(Debug,Copy,Clone,Serialize,PartialEq)]
+struct BallCharacteristic<F : Float, const N : usize> {
+    pub center : Loc<F, N>,
+    pub radius : F,
+}
+
+impl<F : Float, const N : usize> Mapping<Loc<F, N>> for BallCharacteristic<F, N> {
+    type Codomain =F;
+
+    fn apply<I : Instance<Loc<F, N>>>(&self, i : I) -> F {
+        if self.center.dist2(i) <= self.radius {
+            F::ONE
+        } else {
+            F::ZERO
+        }
+    }
+}
+
 //#[replace_float_literals(F::cast_from(literal))]
 impl DefaultExperiment {
     /// Convert the experiment shorthand into a runnable experiment configuration.
@@ -115,23 +143,70 @@
         make_float_constant!(Variance1 = 0.05.powi(2));
         make_float_constant!(CutOff1 = 0.15);
         make_float_constant!(Hat1 = 0.16);
+        make_float_constant!(HatBias = 0.05);
 
         // We use a different step length for PDPS in 2D experiments
-        let pdps_2d = || {
-            let τ0 = 3.0;
-            PDPSConfig {
-                τ0,
-                σ0 : 0.99 / τ0,
+        // let pdps_2d = (DefaultAlgorithm::PDPS,
+        //     AlgorithmOverrides {
+        //         tau0 : Some(3.0),
+        //         sigma0 : Some(0.99 / 3.0),
+        //         .. Default::default()
+        //     }
+        // );
+        // let radon_pdps_2d = (DefaultAlgorithm::RadonPDPS,
+        //     AlgorithmOverrides {
+        //         tau0 : Some(3.0),
+        //         sigma0 : Some(0.99 / 3.0),
+        //         .. Default::default()
+        //     }
+        // );
+        let sliding_fb_cut_gaussian = (DefaultAlgorithm::SlidingFB,
+            AlgorithmOverrides {
+                theta0 : Some(0.3),
                 .. Default::default()
             }
-        };
-
+        );
+        // let higher_cpos = |alg| (alg,
+        //     AlgorithmOverrides {
+        //         transport_tolerance_pos : Some(1000.0),
+        //         .. Default::default()
+        //     }
+        // );
+        let higher_cpos_merging = |alg| (alg,
+            AlgorithmOverrides {
+                transport_tolerance_pos : Some(1000.0),
+                merge : Some(true),
+                fitness_merging : Some(true),
+                .. Default::default()
+            }
+        );
+        let higher_cpos_merging_steptune = |alg| (alg,
+            AlgorithmOverrides {
+                transport_tolerance_pos : Some(1000.0),
+                theta0 : Some(0.3),
+                merge : Some(true),
+                fitness_merging : Some(true),
+                .. Default::default()
+            }
+        );
+        let much_higher_cpos_merging_steptune = |alg| (alg,
+            AlgorithmOverrides {
+                transport_tolerance_pos : Some(10000.0),
+                sigma0 : Some(0.15),
+                theta0 : Some(0.3),
+                merge : Some(true),
+                fitness_merging : Some(true),
+                .. Default::default()
+            }
+        );
         //  We add a hash of the experiment name to the configured
         // noise seed to not use the same noise for different experiments.
         let mut h = DefaultHasher::new();
         name.hash(&mut h);
         let noise_seed = cli.noise_seed.unwrap_or(BASE_SEED) + h.finish();
 
+        let default_merge_radius = 0.01;
+
         use DefaultExperiment::*;
         Ok(match self {
             Experiment1D => {
@@ -140,7 +215,7 @@
                 Box::new(Named { name, data : ExperimentV2 {
                     domain : [[0.0, 1.0]].into(),
                     sensor_count : [N_SENSORS_1D],
-                    regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.09)),
+                    regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.08)),
                     noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.2))?,
                     dataterm : DataTerm::L2Squared,
                     μ_hat : MU_TRUE_1D_BASIC.into(),
@@ -149,7 +224,12 @@
                     kernel : Prod(AutoConvolution(spread_cutoff), base_spread),
                     kernel_plot_width,
                     noise_seed,
-                    algorithm_defaults: HashMap::new(),
+                    default_merge_radius,
+                    algorithm_overrides: HashMap::from([
+                        sliding_fb_cut_gaussian,
+                        higher_cpos_merging(DefaultAlgorithm::RadonFB),
+                        higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB),
+                    ]),
                 }})
             },
             Experiment1DFast => {
@@ -166,7 +246,11 @@
                     kernel : base_spread,
                     kernel_plot_width,
                     noise_seed,
-                    algorithm_defaults: HashMap::new(),
+                    default_merge_radius,
+                    algorithm_overrides: HashMap::from([
+                        higher_cpos_merging(DefaultAlgorithm::RadonFB),
+                        higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB),
+                    ]),
                 }})
             },
             Experiment2D => {
@@ -184,8 +268,11 @@
                     kernel : Prod(AutoConvolution(spread_cutoff), base_spread),
                     kernel_plot_width,
                     noise_seed,
-                    algorithm_defaults: HashMap::from([
-                        (DefaultAlgorithm::PDPS, AlgorithmConfig::PDPS(pdps_2d()))
+                    default_merge_radius,
+                    algorithm_overrides: HashMap::from([
+                        sliding_fb_cut_gaussian,
+                        higher_cpos_merging(DefaultAlgorithm::RadonFB),
+                        higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB),
                     ]),
                 }})
             },
@@ -203,8 +290,10 @@
                     kernel : base_spread,
                     kernel_plot_width,
                     noise_seed,
-                    algorithm_defaults: HashMap::from([
-                        (DefaultAlgorithm::PDPS, AlgorithmConfig::PDPS(pdps_2d()))
+                    default_merge_radius,
+                    algorithm_overrides: HashMap::from([
+                        higher_cpos_merging(DefaultAlgorithm::RadonFB),
+                        higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB),
                     ]),
                 }})
             },
@@ -226,7 +315,8 @@
                     kernel : Prod(AutoConvolution(spread_cutoff), base_spread),
                     kernel_plot_width,
                     noise_seed,
-                    algorithm_defaults: HashMap::new(),
+                    default_merge_radius,
+                    algorithm_overrides: HashMap::new(),
                 }})
             },
             Experiment1D_L1_Fast => {
@@ -246,7 +336,8 @@
                     kernel : base_spread,
                     kernel_plot_width,
                     noise_seed,
-                    algorithm_defaults: HashMap::new(),
+                    default_merge_radius,
+                    algorithm_overrides: HashMap::new(),
                 }})
             },
             Experiment2D_L1 => {
@@ -267,8 +358,8 @@
                     kernel : Prod(AutoConvolution(spread_cutoff), base_spread),
                     kernel_plot_width,
                     noise_seed,
-                    algorithm_defaults: HashMap::from([
-                        (DefaultAlgorithm::PDPS, AlgorithmConfig::PDPS(pdps_2d()))
+                    default_merge_radius,
+                    algorithm_overrides: HashMap::from([
                     ]),
                 }})
             },
@@ -289,9 +380,65 @@
                     kernel : base_spread,
                     kernel_plot_width,
                     noise_seed,
-                    algorithm_defaults: HashMap::from([
-                        (DefaultAlgorithm::PDPS, AlgorithmConfig::PDPS(pdps_2d()))
+                    default_merge_radius,
+                    algorithm_overrides: HashMap::from([
+                    ]),
+                }})
+            },
+            Experiment1D_TV_Fast => {
+                let base_spread = HatConv { radius : HatBias };
+                Box::new(Named { name, data : ExperimentBiased {
+                    λ : 0.02,
+                    bias : MappingSum::new([
+                        Weighted::new(1.0, BallCharacteristic{ center : 0.3.into(), radius : 0.2 }),
+                        Weighted::new(0.5, BallCharacteristic{ center : 0.6.into(), radius : 0.3 }),
                     ]),
+                    base : ExperimentV2 {
+                        domain : [[0.0, 1.0]].into(),
+                        sensor_count : [N_SENSORS_1D],
+                        regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.2)),
+                        noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.1))?,
+                        dataterm : DataTerm::L2Squared,
+                        μ_hat : MU_TRUE_1D_BASIC.into(),
+                        sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity },
+                        spread : base_spread,
+                        kernel : base_spread,
+                        kernel_plot_width,
+                        noise_seed,
+                        default_merge_radius,
+                        algorithm_overrides: HashMap::from([
+                            higher_cpos_merging_steptune(DefaultAlgorithm::RadonForwardPDPS),
+                            higher_cpos_merging_steptune(DefaultAlgorithm::RadonSlidingPDPS),
+                        ]),
+                    },
+                }})
+            },
+            Experiment2D_TV_Fast => {
+                let base_spread = HatConv { radius : Hat1 };
+                Box::new(Named { name, data : ExperimentBiased {
+                    λ : 0.005,
+                    bias : MappingSum::new([
+                        Weighted::new(1.0, BallCharacteristic{ center : [0.3, 0.3].into(), radius : 0.2 }),
+                        Weighted::new(0.5, BallCharacteristic{ center : [0.6, 0.6].into(), radius : 0.3 }),
+                    ]),
+                    base : ExperimentV2 {
+                        domain : [[0.0, 1.0]; 2].into(),
+                        sensor_count : [N_SENSORS_2D; 2],
+                        regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.06)),
+                        noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.15))?, //0.25
+                        dataterm : DataTerm::L2Squared,
+                        μ_hat : MU_TRUE_2D_BASIC.into(),
+                        sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity },
+                        spread : base_spread,
+                        kernel : base_spread,
+                        kernel_plot_width,
+                        noise_seed,
+                        default_merge_radius,
+                        algorithm_overrides: HashMap::from([
+                            much_higher_cpos_merging_steptune(DefaultAlgorithm::RadonForwardPDPS),
+                            much_higher_cpos_merging_steptune(DefaultAlgorithm::RadonSlidingPDPS),
+                        ]),
+                    },
                 }})
             },
         })

mercurial