diff -r 9738b51d90d7 -r 4f468d35fa29 src/plot.rs --- a/src/plot.rs Sun Apr 27 15:03:51 2025 -0500 +++ b/src/plot.rs Thu Feb 26 11:38:43 2026 -0500 @@ -1,37 +1,30 @@ //! Plotting helper utilities +use crate::measures::*; +use alg_tools::lingrid::LinGrid; +use alg_tools::loc::Loc; +use alg_tools::mapping::RealMapping; +use alg_tools::tabledump::write_csv; +use alg_tools::types::*; use numeric_literals::replace_float_literals; use serde::Serialize; -use alg_tools::types::*; -use alg_tools::lingrid::LinGrid; -use alg_tools::mapping::RealMapping; -use alg_tools::loc::Loc; -use alg_tools::tabledump::write_csv; -use crate::measures::*; /// Helper trait for implementing dimension-dependent plotting routines. -pub trait Plotting { +pub trait Plotting { /// Plot several mappings and a discrete measure into a file. - fn plot_into_file_spikes< - F : Float, - T1 : RealMapping, - T2 : RealMapping - > ( - g : Option<&T1>, - ω : Option<&T2>, - grid : LinGrid, - μ : &RNDM, - filename : String, + fn plot_into_file_spikes, T2: RealMapping>( + g: Option<&T1>, + ω: Option<&T2>, + grid: LinGrid, + μ: &RNDM, + filename: String, ); /// Plot a mapping into a file, sampling values on a given grid. - fn plot_into_file< - F : Float, - T1 : RealMapping, - > ( - g : &T1, - grid : LinGrid, - filename : String, + fn plot_into_file>( + g: &T1, + grid: LinGrid, + filename: String, ); } @@ -39,172 +32,181 @@ pub struct PlotLookup; #[derive(Serialize)] -struct CSVHelper1 { - x : F, - f : F, +struct CSVHelper1 { + x: F, + f: F, } #[derive(Serialize)] -struct CSVHelper1_2{ - x : F, - g : Option, - omega : Option +struct CSVHelper1_2 { + x: F, + g: Option, + omega: Option, } #[derive(Serialize)] -struct CSVSpike1 { - x : F, - alpha : F, +struct CSVSpike1 { + x: F, + alpha: F, } impl Plotting<1> for PlotLookup { - fn plot_into_file_spikes< - F : Float, - T1 : RealMapping, - T2 : RealMapping - > ( - g0 : Option<&T1>, - ω0 : Option<&T2>, - grid : LinGrid, - μ : &DiscreteMeasure, F>, - filename : String, + fn plot_into_file_spikes, T2: RealMapping<1, F>>( + g0: Option<&T1>, + ω0: Option<&T2>, + grid: LinGrid<1, F>, + μ: &DiscreteMeasure, F>, + filename: String, ) { - let data = grid.into_iter().map(|p@Loc([x]) : Loc| CSVHelper1_2 { - x, - g : g0.map(|g| g.apply(&p)), - omega : ω0.map(|ω| ω.apply(&p)) - }); + let data = grid + .into_iter() + .map(|p @ Loc([x]): Loc<1, F>| CSVHelper1_2 { + x, + g: g0.map(|g| g.apply(&p)), + omega: ω0.map(|ω| ω.apply(&p)), + }); let csv_f = format!("{}_functions.csv", filename); write_csv(data, csv_f).expect("CSV save error"); let spikes = μ.iter_spikes().map(|δ| { let Loc([x]) = δ.x; - CSVSpike1 { x, alpha : δ.α } + CSVSpike1 { x, alpha: δ.α } }); let csv_f = format!("{}_spikes.csv", filename); write_csv(spikes, csv_f).expect("CSV save error"); } - fn plot_into_file< - F : Float, - T1 : RealMapping, - > ( - g : &T1, - grid : LinGrid, - filename : String, + fn plot_into_file>( + g: &T1, + grid: LinGrid<1, F>, + filename: String, ) { - let data = grid.into_iter().map(|p@Loc([x]) : Loc| CSVHelper1 { - x, - f : g.apply(&p), - }); + let data = grid + .into_iter() + .map(|p @ Loc([x]): Loc<1, F>| CSVHelper1 { x, f: g.apply(&p) }); let csv_f = format!("{}.txt", filename); write_csv(data, csv_f).expect("CSV save error"); } - } #[derive(Serialize)] -struct CSVHelper2 { - x : F, - y : F, - f : F, +struct CSVHelper2 { + x: F, + y: F, + f: F, } #[derive(Serialize)] -struct CSVHelper2_2{ - x : F, - y : F, - g : Option, - omega : Option +struct CSVHelper2_2 { + x: F, + y: F, + g: Option, + omega: Option, } #[derive(Serialize)] -struct CSVSpike2 { - x : F, - y : F, - alpha : F, +struct CSVSpike2 { + x: F, + y: F, + alpha: F, } - impl Plotting<2> for PlotLookup { #[replace_float_literals(F::cast_from(literal))] - fn plot_into_file_spikes< - F : Float, - T1 : RealMapping, - T2 : RealMapping - > ( - g0 : Option<&T1>, - ω0 : Option<&T2>, - grid : LinGrid, - μ : &DiscreteMeasure, F>, - filename : String, + fn plot_into_file_spikes, T2: RealMapping<2, F>>( + g0: Option<&T1>, + ω0: Option<&T2>, + grid: LinGrid<2, F>, + μ: &DiscreteMeasure, F>, + filename: String, ) { - let data = grid.into_iter().map(|p@Loc([x, y]) : Loc| CSVHelper2_2 { - x, - y, - g : g0.map(|g| g.apply(&p)), - omega : ω0.map(|ω| ω.apply(&p)) - }); + let data = grid + .into_iter() + .map(|p @ Loc([x, y]): Loc<2, F>| CSVHelper2_2 { + x, + y, + g: g0.map(|g| g.apply(&p)), + omega: ω0.map(|ω| ω.apply(&p)), + }); let csv_f = format!("{}_functions.csv", filename); write_csv(data, csv_f).expect("CSV save error"); let spikes = μ.iter_spikes().map(|δ| { let Loc([x, y]) = δ.x; - CSVSpike2 { x, y, alpha : δ.α } + CSVSpike2 { x, y, alpha: δ.α } }); let csv_f = format!("{}_spikes.csv", filename); write_csv(spikes, csv_f).expect("CSV save error"); } - fn plot_into_file< - F : Float, - T1 : RealMapping, - > ( - g : &T1, - grid : LinGrid, - filename : String, + fn plot_into_file>( + g: &T1, + grid: LinGrid<2, F>, + filename: String, ) { - let data = grid.into_iter().map(|p@Loc([x, y]) : Loc| CSVHelper2 { - x, - y, - f : g.apply(&p), - }); + let data = grid + .into_iter() + .map(|p @ Loc([x, y]): Loc<2, F>| CSVHelper2 { + x, + y, + f: g.apply(&p), + }); let csv_f = format!("{}.txt", filename); write_csv(data, csv_f).expect("CSV save error"); } - } -/// A helper structure for plotting a sequence of images. -#[derive(Clone,Debug)] -pub struct SeqPlotter { - /// File name prefix - prefix : String, - /// Maximum number of plots to perform - max_plots : usize, - /// Sampling grid - grid : LinGrid, - /// Current plot count - plot_count : usize, +/// Trait for plotters +pub trait Plotter { + /// Plot the functions `g` and `ω` as well as the spikes of `μ`. + fn plot_spikes(&mut self, iter: usize, g: Option<&T1>, ω: Option<&T2>, μ: &M); +} + +/// A plotter that does nothing. +pub struct NoPlotter; + +impl Plotter for NoPlotter { + fn plot_spikes(&mut self, _iter: usize, _g: Option<&T1>, _ω: Option<&T2>, _μ: &M) {} } -impl SeqPlotter -where PlotLookup : Plotting { - /// Creates a new sequence plotter instance - pub fn new(prefix : String, max_plots : usize, grid : LinGrid) -> Self { - SeqPlotter { prefix, max_plots, grid, plot_count : 0 } - } +/// A basic plotter. +/// +/// This calls [`PlotLookup::plot_into_file_spikes`] with a sequentially numbered file name. +#[derive(Clone, Debug)] +pub struct SeqPlotter { + /// File name prefix + prefix: String, + /// Maximum number of plots to perform + max_plots: usize, + /// Sampling grid + grid: LinGrid, + /// Current plot count + plot_count: usize, +} - /// This calls [`PlotLookup::plot_into_file_spikes`] with a sequentially numbered file name. - pub fn plot_spikes( - &mut self, - iter : usize, - g : Option<&T1>, - ω : Option<&T2>, - μ : &RNDM, - ) where T1 : RealMapping, - T2 : RealMapping - { +impl SeqPlotter +where + PlotLookup: Plotting, +{ + /// Creates a new sequence plotter instance + pub fn new(prefix: String, max_plots: usize, grid: LinGrid) -> Self { + SeqPlotter { + prefix, + max_plots, + grid, + plot_count: 0, + } + } +} + +impl Plotter> for SeqPlotter +where + F: Float, + T1: RealMapping, + T2: RealMapping, + PlotLookup: Plotting, +{ + fn plot_spikes(&mut self, iter: usize, g: Option<&T1>, ω: Option<&T2>, μ: &RNDM) { if self.plot_count == 0 && self.max_plots > 0 { std::fs::create_dir_all(&self.prefix).expect("Unable to create plot directory"); } @@ -214,7 +216,7 @@ ω, self.grid, μ, - format!("{}out{:03}", self.prefix, iter) + format!("{}out{:03}", self.prefix, iter), ); self.plot_count += 1; }