diff -r 9738b51d90d7 -r 4f468d35fa29 src/experiments.rs --- a/src/experiments.rs Sun Apr 27 15:03:51 2025 -0500 +++ b/src/experiments.rs Thu Feb 26 11:38:43 2026 -0500 @@ -3,37 +3,30 @@ */ //use numeric_literals::replace_float_literals; -use serde::{Serialize, Deserialize}; -use clap::ValueEnum; -use std::collections::HashMap; -use std::hash::{Hash, Hasher}; -use std::collections::hash_map::DefaultHasher; - +use crate::kernels::SupportProductFirst as Prod; +use crate::kernels::*; +use crate::run::{DefaultAlgorithm, ExperimentBiased, ExperimentV2, Named, RunnableExperiment}; +use crate::types::*; +use crate::{AlgorithmOverrides, ExperimentSetup}; use alg_tools::bisection_tree::*; use alg_tools::error::DynResult; use alg_tools::norms::Linfinity; - -use crate::{ExperimentOverrides, AlgorithmOverrides}; -use crate::kernels::*; -use crate::kernels::SupportProductFirst as Prod; -use crate::types::*; -use crate::run::{ - RunnableExperiment, - ExperimentV2, - ExperimentBiased, - Named, - DefaultAlgorithm, -}; -//use crate::fb::FBGenericConfig; -use crate::rand_distr::{SerializableNormal, SaltAndPepper}; +use clap::{Parser, ValueEnum}; +use serde::{Deserialize, Serialize}; +use std::collections::hash_map::DefaultHasher; +use std::collections::HashMap; +use std::hash::{Hash, Hasher}; +//use crate::fb::InsertionConfig; +use crate::rand_distr::{SaltAndPepper, SerializableNormal}; 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}; +use itertools::Itertools; +use serde_with::skip_serializing_none; /// Experiments shorthands, to be used with the command line parser - #[derive(ValueEnum, Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] #[allow(non_camel_case_types)] pub enum DefaultExperiment { @@ -69,49 +62,77 @@ Experiment2D_TV_Fast, } +/// Command line experiment setup overrides +#[skip_serializing_none] +#[derive(Parser, Debug, Serialize, Deserialize, Default, Clone, Hash)] +pub struct DefaultExperimentSetup { + /// List of experiments to perform + #[arg(value_name = "EXPERIMENT")] + experiments: Vec, + + #[arg(long)] + /// Regularisation parameter override. + /// + /// Only use if running just a single experiment, as different experiments have different + /// regularisation parameters. + alpha: Option, + + #[arg(long)] + /// Gaussian noise variance override + variance: Option, + + #[arg(long, value_names = &["MAGNITUDE", "PROBABILITY"])] + /// Salt and pepper noise override. + salt_and_pepper: Option>, + + #[arg(long)] + /// Noise seed + noise_seed: Option, +} + macro_rules! make_float_constant { ($name:ident = $value:expr) => { #[derive(Debug, Copy, Eq, PartialEq, Clone, Serialize, Deserialize)] #[serde(into = "float")] struct $name; - impl Into for $name { + impl Into for $name { #[inline] - fn into(self) -> float { $value } + fn into(self) -> float { + $value + } } impl Constant for $name { type Type = float; - fn value(&self) -> float { $value } + fn value(&self) -> float { + $value + } } - } + }; } /// Ground-truth measure spike locations and magnitudes for 1D experiments -static MU_TRUE_1D_BASIC : [(float, float); 4] = [ - (0.10, 10.0), - (0.30, 2.0), - (0.70, 3.0), - (0.80, 5.0) -]; +static MU_TRUE_1D_BASIC: [(float, float); 4] = + [(0.10, 10.0), (0.30, 2.0), (0.70, 3.0), (0.80, 5.0)]; /// Ground-truth measure spike locations and magnitudes for 2D experiments -static MU_TRUE_2D_BASIC : [([float; 2], float); 4] = [ +static MU_TRUE_2D_BASIC: [([float; 2], float); 4] = [ ([0.15, 0.15], 10.0), ([0.75, 0.45], 2.0), ([0.80, 0.50], 4.0), - ([0.30, 0.70], 5.0) + ([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 { - pub center : Loc, - pub radius : F, +#[derive(Debug, Copy, Clone, Serialize, PartialEq)] +struct BallCharacteristic { + pub center: Loc, + pub radius: F, } -impl Mapping> for BallCharacteristic { - type Codomain =F; +impl Mapping> for BallCharacteristic { + type Codomain = F; - fn apply>>(&self, i : I) -> F { + fn apply>>(&self, i: I) -> F { if self.center.dist2(i) <= self.radius { F::ONE } else { @@ -120,25 +141,52 @@ } } +/// Trait for customising the experiments available from the command line +impl ExperimentSetup for DefaultExperimentSetup { + type FloatType = f64; + + fn runnables(&self) -> DynResult>>> { + self.experiments + .iter() + .unique() + .map(|e| e.get_experiment(self)) + .try_collect() + } +} + //#[replace_float_literals(F::cast_from(literal))] impl DefaultExperiment { + // fn default_list() -> Vec { + // use DefaultExperiment::*; + // [ + // Experiment1D, + // Experiment1DFast, + // Experiment2D, + // Experiment2DFast, + // Experiment1D_L1, + // ] + // .into() + // } + /// Convert the experiment shorthand into a runnable experiment configuration. - pub fn get_experiment(&self, cli : &ExperimentOverrides) -> DynResult>> { - let name = "pointsource".to_string() - + self.to_possible_value().unwrap().get_name(); + fn get_experiment( + &self, + cli: &DefaultExperimentSetup, + ) -> DynResult>> { + let name = "pointsource".to_string() + self.to_possible_value().unwrap().get_name(); let kernel_plot_width = 0.2; - const BASE_SEED : u64 = 915373234; + const BASE_SEED: u64 = 915373234; - const N_SENSORS_1D : usize = 100; - make_float_constant!(SensorWidth1D = 0.4/(N_SENSORS_1D as float)); + const N_SENSORS_1D: usize = 100; + make_float_constant!(SensorWidth1D = 0.4 / (N_SENSORS_1D as float)); - const N_SENSORS_2D : usize = 16; - make_float_constant!(SensorWidth2D = 0.4/(N_SENSORS_2D as float)); + const N_SENSORS_2D: usize = 16; + make_float_constant!(SensorWidth2D = 0.4 / (N_SENSORS_2D as float)); - const N_SENSORS_2D_MORE : usize = 32; - make_float_constant!(SensorWidth2DMore = 0.4/(N_SENSORS_2D_MORE as float)); + //const N_SENSORS_2D_MORE: usize = 32; + //make_float_constant!(SensorWidth2DMore = 0.4 / (N_SENSORS_2D_MORE as float)); make_float_constant!(Variance1 = 0.05.powi(2)); make_float_constant!(CutOff1 = 0.15); @@ -160,45 +208,43 @@ // .. Default::default() // } // ); - let sliding_fb_cut_gaussian = (DefaultAlgorithm::SlidingFB, - AlgorithmOverrides { - theta0 : Some(0.3), - .. 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() - } - ); + 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(); @@ -210,238 +256,284 @@ use DefaultExperiment::*; Ok(match self { Experiment1D => { - let base_spread = Gaussian { variance : Variance1 }; - let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity }; - 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.08)), - noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.2))?, - dataterm : DataTerm::L2Squared, - μ_hat : MU_TRUE_1D_BASIC.into(), - sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, - spread : Prod(spread_cutoff, base_spread), - kernel : Prod(AutoConvolution(spread_cutoff), base_spread), - kernel_plot_width, - noise_seed, - default_merge_radius, - algorithm_overrides: HashMap::from([ - sliding_fb_cut_gaussian, - higher_cpos_merging(DefaultAlgorithm::RadonFB), - higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), - ]), - }}) - }, + let base_spread = Gaussian { variance: Variance1 }; + let spread_cutoff = BallIndicator { r: CutOff1, exponent: Linfinity }; + 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.08)), + noise_distr: SerializableNormal::new(0.0, cli.variance.unwrap_or(0.2))?, + dataterm: DataTermType::L222, + μ_hat: MU_TRUE_1D_BASIC.into(), + sensor: BallIndicator { r: SensorWidth1D, exponent: Linfinity }, + spread: Prod(spread_cutoff, base_spread), + kernel: Prod(AutoConvolution(spread_cutoff), base_spread), + kernel_plot_width, + noise_seed, + default_merge_radius, + algorithm_overrides: HashMap::from([ + sliding_fb_cut_gaussian, + higher_cpos_merging(DefaultAlgorithm::RadonFB), + higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), + ]), + }, + }) + } Experiment1DFast => { - let base_spread = HatConv { radius : Hat1 }; - 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.06)), - noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.2))?, - 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(DefaultAlgorithm::RadonFB), - higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), - ]), - }}) - }, + let base_spread = HatConv { radius: Hat1 }; + 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.06)), + noise_distr: SerializableNormal::new(0.0, cli.variance.unwrap_or(0.2))?, + dataterm: DataTermType::L222, + μ_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(DefaultAlgorithm::RadonFB), + higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), + ]), + }, + }) + } Experiment2D => { - let base_spread = Gaussian { variance : Variance1 }; - let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity }; - Box::new(Named { name, data : ExperimentV2 { - domain : [[0.0, 1.0]; 2].into(), - sensor_count : [N_SENSORS_2D; 2], - regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.19)), - noise_distr : SerializableNormal::new(0.0, cli.variance.unwrap_or(0.25))?, - dataterm : DataTerm::L2Squared, - μ_hat : MU_TRUE_2D_BASIC.into(), - sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, - spread : Prod(spread_cutoff, base_spread), - kernel : Prod(AutoConvolution(spread_cutoff), base_spread), - kernel_plot_width, - noise_seed, - default_merge_radius, - algorithm_overrides: HashMap::from([ - sliding_fb_cut_gaussian, - higher_cpos_merging(DefaultAlgorithm::RadonFB), - higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), - ]), - }}) - }, + let base_spread = Gaussian { variance: Variance1 }; + let spread_cutoff = BallIndicator { r: CutOff1, exponent: Linfinity }; + Box::new(Named { + name, + data: ExperimentV2 { + domain: [[0.0, 1.0]; 2].into(), + sensor_count: [N_SENSORS_2D; 2], + regularisation: Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.19)), + noise_distr: SerializableNormal::new(0.0, cli.variance.unwrap_or(0.25))?, + dataterm: DataTermType::L222, + μ_hat: MU_TRUE_2D_BASIC.into(), + sensor: BallIndicator { r: SensorWidth2D, exponent: Linfinity }, + spread: Prod(spread_cutoff, base_spread), + kernel: Prod(AutoConvolution(spread_cutoff), base_spread), + kernel_plot_width, + noise_seed, + default_merge_radius, + algorithm_overrides: HashMap::from([ + sliding_fb_cut_gaussian, + higher_cpos_merging(DefaultAlgorithm::RadonFB), + higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), + ]), + }, + }) + } Experiment2DFast => { - let base_spread = HatConv { radius : Hat1 }; - Box::new(Named { name, data : ExperimentV2 { - domain : [[0.0, 1.0]; 2].into(), - sensor_count : [N_SENSORS_2D; 2], - regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.12)), - 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([ - higher_cpos_merging(DefaultAlgorithm::RadonFB), - higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), - ]), - }}) - }, - Experiment1D_L1 => { - let base_spread = Gaussian { variance : Variance1 }; - let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity }; - 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.1)), - noise_distr : SaltAndPepper::new( - cli.salt_and_pepper.as_ref().map_or(0.6, |v| v[0]), - cli.salt_and_pepper.as_ref().map_or(0.4, |v| v[1]) - )?, - dataterm : DataTerm::L1, - μ_hat : MU_TRUE_1D_BASIC.into(), - sensor : BallIndicator { r : SensorWidth1D, exponent : Linfinity }, - spread : Prod(spread_cutoff, base_spread), - kernel : Prod(AutoConvolution(spread_cutoff), base_spread), - kernel_plot_width, - noise_seed, - default_merge_radius, - algorithm_overrides: HashMap::new(), - }}) - }, - Experiment1D_L1_Fast => { - let base_spread = HatConv { radius : Hat1 }; - 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.12)), - noise_distr : SaltAndPepper::new( - cli.salt_and_pepper.as_ref().map_or(0.6, |v| v[0]), - cli.salt_and_pepper.as_ref().map_or(0.4, |v| v[1]) - )?, - dataterm : DataTerm::L1, - μ_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::new(), - }}) - }, - Experiment2D_L1 => { - let base_spread = Gaussian { variance : Variance1 }; - let spread_cutoff = BallIndicator { r : CutOff1, exponent : Linfinity }; - Box::new(Named { name, data : ExperimentV2 { - domain : [[0.0, 1.0]; 2].into(), - sensor_count : [N_SENSORS_2D; 2], - regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.35)), - noise_distr : SaltAndPepper::new( - cli.salt_and_pepper.as_ref().map_or(0.8, |v| v[0]), - cli.salt_and_pepper.as_ref().map_or(0.2, |v| v[1]) - )?, - dataterm : DataTerm::L1, - μ_hat : MU_TRUE_2D_BASIC.into(), - sensor : BallIndicator { r : SensorWidth2D, exponent : Linfinity }, - spread : Prod(spread_cutoff, base_spread), - kernel : Prod(AutoConvolution(spread_cutoff), base_spread), - kernel_plot_width, - noise_seed, - default_merge_radius, - algorithm_overrides: HashMap::from([ - ]), - }}) - }, - Experiment2D_L1_Fast => { - let base_spread = HatConv { radius : Hat1 }; - Box::new(Named { name, data : ExperimentV2 { - domain : [[0.0, 1.0]; 2].into(), - sensor_count : [N_SENSORS_2D; 2], - regularisation : Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.40)), - noise_distr : SaltAndPepper::new( - cli.salt_and_pepper.as_ref().map_or(0.8, |v| v[0]), - cli.salt_and_pepper.as_ref().map_or(0.2, |v| v[1]) - )?, - dataterm : DataTerm::L1, - μ_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([ - ]), - }}) - }, - 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, + let base_spread = HatConv { radius: Hat1 }; + Box::new(Named { + name, + data: ExperimentV2 { + domain: [[0.0, 1.0]; 2].into(), + sensor_count: [N_SENSORS_2D; 2], + regularisation: Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.12)), + noise_distr: SerializableNormal::new(0.0, cli.variance.unwrap_or(0.15))?, //0.25 + dataterm: DataTermType::L222, + μ_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([ - higher_cpos_merging_steptune(DefaultAlgorithm::RadonForwardPDPS), - higher_cpos_merging_steptune(DefaultAlgorithm::RadonSlidingPDPS), + higher_cpos_merging(DefaultAlgorithm::RadonFB), + higher_cpos_merging(DefaultAlgorithm::RadonSlidingFB), ]), }, - }}) - }, - 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, + }) + } + Experiment1D_L1 => { + let base_spread = Gaussian { variance: Variance1 }; + let spread_cutoff = BallIndicator { r: CutOff1, exponent: Linfinity }; + 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.1)), + noise_distr: SaltAndPepper::new( + cli.salt_and_pepper.as_ref().map_or(0.6, |v| v[0]), + cli.salt_and_pepper.as_ref().map_or(0.4, |v| v[1]), + )?, + dataterm: DataTermType::L1, + μ_hat: MU_TRUE_1D_BASIC.into(), + sensor: BallIndicator { r: SensorWidth1D, exponent: Linfinity }, + spread: Prod(spread_cutoff, base_spread), + kernel: Prod(AutoConvolution(spread_cutoff), base_spread), + kernel_plot_width, + noise_seed, + default_merge_radius, + algorithm_overrides: HashMap::new(), + }, + }) + } + Experiment1D_L1_Fast => { + let base_spread = HatConv { radius: Hat1 }; + 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.12)), + noise_distr: SaltAndPepper::new( + cli.salt_and_pepper.as_ref().map_or(0.6, |v| v[0]), + cli.salt_and_pepper.as_ref().map_or(0.4, |v| v[1]), + )?, + dataterm: DataTermType::L1, + μ_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::new(), + }, + }) + } + Experiment2D_L1 => { + let base_spread = Gaussian { variance: Variance1 }; + let spread_cutoff = BallIndicator { r: CutOff1, exponent: Linfinity }; + Box::new(Named { + name, + data: ExperimentV2 { + domain: [[0.0, 1.0]; 2].into(), + sensor_count: [N_SENSORS_2D; 2], + regularisation: Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.35)), + noise_distr: SaltAndPepper::new( + cli.salt_and_pepper.as_ref().map_or(0.8, |v| v[0]), + cli.salt_and_pepper.as_ref().map_or(0.2, |v| v[1]), + )?, + dataterm: DataTermType::L1, + μ_hat: MU_TRUE_2D_BASIC.into(), + sensor: BallIndicator { r: SensorWidth2D, exponent: Linfinity }, + spread: Prod(spread_cutoff, base_spread), + kernel: Prod(AutoConvolution(spread_cutoff), 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), + algorithm_overrides: HashMap::from([]), + }, + }) + } + Experiment2D_L1_Fast => { + let base_spread = HatConv { radius: Hat1 }; + Box::new(Named { + name, + data: ExperimentV2 { + domain: [[0.0, 1.0]; 2].into(), + sensor_count: [N_SENSORS_2D; 2], + regularisation: Regularisation::NonnegRadon(cli.alpha.unwrap_or(0.40)), + noise_distr: SaltAndPepper::new( + cli.salt_and_pepper.as_ref().map_or(0.8, |v| v[0]), + cli.salt_and_pepper.as_ref().map_or(0.2, |v| v[1]), + )?, + dataterm: DataTermType::L1, + μ_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([]), + }, + }) + } + 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: DataTermType::L222, + μ_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: DataTermType::L222, + μ_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, + ), + ]), + }, + }, + }) + } }) } } -