From f520c8b3cbfb7bf38c32b0eac6b4398afc1bf810 Mon Sep 17 00:00:00 2001 From: Jan Bergen Date: Tue, 16 Jul 2024 15:48:35 +0200 Subject: [PATCH] Push current version --- bachelorarbeit/src/calc.rs | 313 ++++++++++++-------- bachelorarbeit/src/gq_storage.rs | 2 +- bachelorarbeit/src/main.rs | 475 +++++++++++++++++++++---------- 3 files changed, 519 insertions(+), 271 deletions(-) diff --git a/bachelorarbeit/src/calc.rs b/bachelorarbeit/src/calc.rs index 1fc0788..2de2bd7 100644 --- a/bachelorarbeit/src/calc.rs +++ b/bachelorarbeit/src/calc.rs @@ -1,21 +1,16 @@ use core::f64::consts::PI; -use std::time::Instant; use gauss_quad::GaussLegendre; -use num::Float; use std::collections::HashMap; use std::io; use std::rc::Rc; -use std::{ - fs::File, - io::BufReader, -}; +use std::{fs::File, io::BufReader}; -use crate::gq_storage; // This should be moved to main.rs after new archtitecture (see main.rs TODO) +use crate::gq_storage; pub type Complex = num::complex::Complex; -const M_ROH: f64 = 0.7736; +const M_ROH: f64 = 0.7736; const M_PI: f64 = 0.13957; pub const S0: f64 = 4.0 * M_PI * M_PI; const M_K: f64 = 0.496; @@ -26,35 +21,55 @@ const LAMBDA2: f64 = -1.96; const LAMBDA_HIGH: f64 = 10.0; pub const EPSILON: f64 = 1e-15; const S_MID_CUTOFF: f64 = 1.42 * 1.42; -const INF: f64 = 1e5; +const INF: f64 = 1e6; #[derive(Default)] pub struct Cache { - pub gauss_quad_lut: HashMap, Rc<[f64]>), nohash_hasher::BuildNoHashHasher>, - pub delta_lut: HashMap>, - pub omnes_lut: HashMap>, nohash_hasher::BuildNoHashHasher> // First key is n, second is s + pub gauss_quad_lut: HashMap, Rc<[f64]>), nohash_hasher::BuildNoHashHasher>, + pub delta_lut: HashMap>, + pub omnes_lut: HashMap< + u32, + HashMap>, + nohash_hasher::BuildNoHashHasher, + >, // First key is n, second is s } impl Cache { pub fn from_file(filepath: &str) -> io::Result { let file = File::open(filepath)?; let mut file = BufReader::new(file); - - let me = Cache{ - gauss_quad_lut: gq_storage::deserialize(&mut file, |_| true)?.into_iter() - .map(|(roots, weights)| (u32::try_from(roots.len()).unwrap(), (Rc::from(roots), Rc::from(weights)))).collect(), + + let me = Cache { + gauss_quad_lut: gq_storage::deserialize(&mut file, |_| true)? + .into_iter() + .map(|(roots, weights)| { + ( + u32::try_from(roots.len()).unwrap(), + (Rc::from(roots), Rc::from(weights)), + ) + }) + .collect(), delta_lut: HashMap::with_hasher(Default::default()), - omnes_lut: HashMap::with_hasher(Default::default()) + omnes_lut: HashMap::with_hasher(Default::default()), }; Ok(me) } + + #[allow(unused)] pub fn from_slice(data: &[u8]) -> io::Result { let mut cursor = std::io::Cursor::new(data); - let me = Cache{ - gauss_quad_lut: gq_storage::deserialize(&mut cursor, |_| true)?.into_iter() - .map(|(roots, weights)| (u32::try_from(roots.len()).unwrap(), (Rc::from(roots), Rc::from(weights)))).collect(), + let me = Cache { + gauss_quad_lut: gq_storage::deserialize(&mut cursor, |_| true)? + .into_iter() + .map(|(roots, weights)| { + ( + u32::try_from(roots.len()).unwrap(), + (Rc::from(roots), Rc::from(weights)), + ) + }) + .collect(), delta_lut: HashMap::with_hasher(Default::default()), - omnes_lut: HashMap::with_hasher(Default::default()) + omnes_lut: HashMap::with_hasher(Default::default()), }; Ok(me) } @@ -63,7 +78,7 @@ impl Cache { // derivated values fn lambda_0() -> f64 { - delta((2.0*M_K).powi(2)) + delta((2.0 * M_K).powi(2)) } fn delta_mid_cutoff() -> f64 { @@ -79,31 +94,54 @@ fn atan_shift(x: f64) -> f64 { } } -fn integrate f64>(roots: &[f64], weights: &[f64], a:f64, b:f64, mut f: G) -> f64 { +fn integrate f64>( + roots: &[f64], + weights: &[f64], + a: f64, + b: f64, + mut f: G, + print_prog: bool, +) -> f64 { let mut sum: f64 = 0.0; let mut i: usize = 0; if roots.len() != weights.len() { panic!("Error: roots and weights are of different length"); } - - while i < roots.len() { - sum += weights[i] * f(roots[i]*(b-a)/2.0 + (a+b)/2.0); - i += 1; + if print_prog { + println!("Calculating single integration: "); + let prog = indicatif::ProgressBar::new(roots.len() as u64); + while i < roots.len() { + sum += weights[i] * f(roots[i] * (b - a) / 2.0 + (a + b) / 2.0); + i += 1; + prog.inc(1); + } + prog.finish(); + } else { + while i < roots.len() { + sum += weights[i] * f(roots[i] * (b - a) / 2.0 + (a + b) / 2.0); + i += 1; + } } - sum * (b-a)/2.0 + sum * (b - a) / 2.0 } -fn integrate_complex Complex>(roots: &[f64], weights: &[f64], a:f64, b:f64, mut f: G) -> Complex { - let mut sum: Complex = Complex::new(0.0,0.0); +fn integrate_complex Complex>( + roots: &[f64], + weights: &[f64], + a: f64, + b: f64, + mut f: G, +) -> Complex { + let mut sum: Complex = Complex::new(0.0, 0.0); let mut i: usize = 0; if roots.len() != weights.len() { panic!("Error: roots and weights are of different length"); } while i < roots.len() { - sum += weights[i] * f(roots[i]*(b-a)/2.0 + (a+b)/2.0); + sum += weights[i] * f(roots[i] * (b - a) / 2.0 + (a + b) / 2.0); i += 1; } - sum * (b-a)/2.0 + sum * (b - a) / 2.0 } fn omega(s: f64) -> f64 { @@ -113,14 +151,12 @@ fn omega(s: f64) -> f64 { } fn k(s: f64) -> f64 { - (s/4.0 - M_PI.powi(2)).sqrt() + (s / 4.0 - M_PI.powi(2)).sqrt() } -pub fn delta_with_lut(cache:&mut Cache, s: f64) -> f64 { +pub fn delta_with_lut(cache: &mut Cache, s: f64) -> f64 { match cache.delta_lut.get(&s.to_bits()) { - Some(val) => { - *val - } + Some(val) => *val, None => { let val = delta(s); cache.delta_lut.insert(s.to_bits(), val); @@ -132,154 +168,179 @@ pub fn delta_with_lut(cache:&mut Cache, s: f64) -> f64 { pub fn delta(s: f64) -> f64 { if s <= 2.0 * M_K { atan_shift( - (s.sqrt() / (2.0*k(s).powi(3)) - * (M_ROH.powi(2) - s) - * ( (2.0*M_PI.powi(3)) / (M_ROH.powi(2) * s.sqrt()) + B0 + B1 * omega(s)) - ).powi(-1) + (s.sqrt() / (2.0 * k(s).powi(3)) + * (M_ROH.powi(2) - s) + * ((2.0 * M_PI.powi(3)) / (M_ROH.powi(2) * s.sqrt()) + B0 + B1 * omega(s))) + .powi(-1), ) } else if s <= S_MID_CUTOFF { let par = 0.5 * s.sqrt() / M_K - 1.0; lambda_0() + LAMBDA1 * par + LAMBDA2 * par.powi(2) } else { - PI + - (delta_mid_cutoff() - PI) - * (LAMBDA_HIGH * LAMBDA_HIGH + S_MID_CUTOFF) - / (LAMBDA_HIGH * LAMBDA_HIGH + s) + PI + (delta_mid_cutoff() - PI) * (LAMBDA_HIGH * LAMBDA_HIGH + S_MID_CUTOFF) + / (LAMBDA_HIGH * LAMBDA_HIGH + s) } } -pub fn omnes_integrand_tan(cache:&mut Cache, s_tick:f64, s:f64) -> Complex { +pub fn omnes_integrand_tan(cache: &mut Cache, s_tick: f64, s: f64) -> Complex { let sub = s_tick.tan(); - (delta_with_lut(cache, sub) - delta_with_lut(cache, s)) - / ( - sub - * (sub - s + Complex::new(0.0, EPSILON)) - * s_tick.cos().powi(2) - ) + (delta_with_lut(cache, sub) - delta_with_lut(cache, s)) + / (sub * (sub - s + Complex::new(0.0, EPSILON)) * s_tick.cos().powi(2)) } -pub fn omnes_integrand_notan(cache:&mut Cache, s_tick:f64, s:f64) -> Complex { - (delta_with_lut(cache, s_tick) - delta_with_lut(cache, s)) - / (s_tick * (s_tick - s + Complex::new(0.0, EPSILON))) +pub fn omnes_integrand_notan(cache: &mut Cache, s_tick: f64, s: f64) -> Complex { + (delta_with_lut(cache, s_tick) - delta_with_lut(cache, s)) + / (s_tick * (s_tick - s + Complex::new(0.0, EPSILON))) } -pub fn omnes(cache:&mut Cache, s:f64, n:u32, use_tan: bool) -> Complex { +pub fn omnes(cache: &mut Cache, s: f64, n: u32, use_tan: bool) -> Complex { let roots: Rc<[f64]>; let weights: Rc<[f64]>; if let Some(inner_lut) = cache.omnes_lut.get(&n) { if let Some(res) = inner_lut.get(&s.to_bits()) { - return *res + return *res; } } - + if !cache.omnes_lut.contains_key(&n) { - cache.omnes_lut.insert(n, HashMap::with_hasher(Default::default())); - } - + cache + .omnes_lut + .insert(n, HashMap::with_hasher(Default::default())); + } + match cache.gauss_quad_lut.get_mut(&n) { Some(gq_values) => { roots = Rc::clone(&gq_values.0); weights = Rc::clone(&gq_values.1); } None => { - let gq_values = GaussLegendre::nodes_and_weights(n.try_into().unwrap()); + let gq_values = GaussLegendre::nodes_and_weights(n.try_into().unwrap()); roots = Rc::from(gq_values.0.as_slice()); weights = Rc::from(gq_values.1.as_slice()); } } - + if !cache.gauss_quad_lut.contains_key(&n) { let gq_values = GaussLegendre::nodes_and_weights(n.try_into().unwrap()); - cache.gauss_quad_lut.insert(n, (Rc::from(gq_values.0), Rc::from(gq_values.1))); - println!("n_omnes={} is not included in the lookup file. Consider generating a new lookup file via the appropriate function in gq_storage.rs", n); + cache + .gauss_quad_lut + .insert(n, (Rc::from(gq_values.0), Rc::from(gq_values.1))); + println!("n_omnes={} is not included in the lookup file. Consider generating a new lookup file via the appropriate function in gq_storage.rs", n); } let intgrl = if use_tan { - integrate_complex(&roots, &weights, S0.atan(), PI / 2.0, |s_tick| omnes_integrand_tan(cache, s_tick, s)) + integrate_complex(&roots, &weights, S0.atan(), PI / 2.0, |s_tick| { + omnes_integrand_tan(cache, s_tick, s) + }) } else { - integrate_complex(&roots, &weights, S0, INF, |s_tick| omnes_integrand_notan(cache, s_tick, s)) + integrate_complex(&roots, &weights, S0, INF, |s_tick| { + omnes_integrand_notan(cache, s_tick, s) + }) }; - let omnes_res = (s/PI*(intgrl)).exp() * (S0 / Complex::new(S0 - s, -EPSILON)).powf(delta_with_lut(cache, s) / PI); - cache.omnes_lut.get_mut(&n).unwrap().insert(s.to_bits(), omnes_res); + let omnes_res = (s / PI * (intgrl)).exp() + * (S0 / Complex::new(S0 - s, -EPSILON)).powf(delta_with_lut(cache, s) / PI); + cache + .omnes_lut + .get_mut(&n) + .unwrap() + .insert(s.to_bits(), omnes_res); omnes_res } -pub fn phi0_integrand_tan_xsub(cache:&mut Cache, s_tick: f64, s: f64, n_omnes:u32, use_tan_omnes: bool) -> f64 { - let x_sub = s_tick.tan().powi(2) + S0; +pub fn phi0_integrand( + cache: &mut Cache, + s_tick: f64, + s: f64, + n_omnes: u32, + use_tan_omnes: bool, + use_tan_phi0: bool, + use_xsub: bool, + _use_reduced_integrand: bool, +) -> f64 { + let sub = match (use_tan_phi0, use_xsub) { + (true, true) => s_tick.tan().powi(2) + S0, + (true, false) => s_tick.tan(), + (false, true) => s_tick.powi(2) + S0, + (false, false) => s_tick, + }; let omnes_s = omnes(cache, s, n_omnes, use_tan_omnes); - let omnes_x = omnes(cache, x_sub, n_omnes, use_tan_omnes); - (omnes_x / omnes_s).norm_sqr().ln() - / ( (x_sub)* (x_sub-s) ) - / s_tick.cos().powi(2) // Don't use x_sub here, since this term is from tan substitution itself -} - -pub fn phi0_integrand_notan_xsub(cache:&mut Cache, s_tick: f64, s: f64, n_omnes:u32, use_tan_omnes: bool) -> f64 { - let x_sub = s_tick.powi(2) + S0; - let omnes_s = omnes(cache, s, n_omnes, use_tan_omnes); - let omnes_x = omnes(cache, x_sub, n_omnes, use_tan_omnes); - (omnes_x / omnes_s).norm_sqr().ln() - / ( (x_sub)* (x_sub-s) ) -} - -pub fn phi0_integrand_tan_noxsub(cache:&mut Cache, s_tick: f64, s: f64, n_omnes:u32, use_tan_omnes: bool) -> f64 { - let tansub = s_tick.tan(); - println!("lol {:?}", omnes(cache, tansub, n_omnes, use_tan_omnes)); - let omnes_s = omnes(cache, s, n_omnes, use_tan_omnes); - let omnes_s_tick = omnes(cache, tansub, n_omnes, use_tan_omnes); - let res = (omnes_s_tick / omnes_s).norm_sqr().ln() - / ( (tansub - S0).sqrt() * tansub * (tansub - s) ) - / s_tick.cos().powi(2); - println!("{:?} {:?} {:?} {:?} {:?}", s_tick, tansub, omnes_s, omnes_s_tick, res); - println!("LOL {:?}", omnes(cache, tansub, n_omnes, use_tan_omnes)); + let omnes_sub = omnes(cache, sub, n_omnes, use_tan_omnes); + let mut res = (omnes_sub / omnes_s).norm().ln() / (sub * (sub - s)); + res *= match (use_tan_phi0, use_xsub) { + (true, true) => 2.0 / s_tick.cos().powi(2), + (true, false) => 1.0 / ((sub - S0).sqrt() * s_tick.cos().powi(2)), + (false, true) => 2.0, + (false, false) => 1.0 / (sub - S0).sqrt(), + }; res } -pub fn phi0_integrand_notan_noxsub(cache:&mut Cache, s: f64, s_tick: f64, n_omnes:u32, use_tan_omnes: bool) -> f64 { - - let omnes_s = omnes(cache, s, n_omnes, use_tan_omnes); - let omnes_s_tick = omnes(cache, s_tick, n_omnes, use_tan_omnes); - let res = (omnes_s_tick / omnes_s).norm_sqr().ln() - / ( (s_tick - S0).sqrt() * s_tick * (s_tick - s) ); - println!("{:?} {:?} {:?} {:?} {:?}", s, s_tick, omnes_s, omnes_s_tick, res); - - res - -} - -pub fn phi0(cache:&mut Cache, s: f64, n_omnes: u32, n_phi0: u32, use_tan_omnes: bool, use_tan_phi0: bool, use_xsub: bool) -> f64 { - //let t0 = Instant::now(); +pub fn phi0( + cache: &mut Cache, + s: f64, + n_omnes: u32, + n_phi0: u32, + use_tan_omnes: bool, + use_tan_phi0: bool, + use_xsub: bool, + use_reduced_integrand: bool, + print_prog: bool, +) -> f64 { if !cache.gauss_quad_lut.contains_key(&n_phi0) { let gq_values = GaussLegendre::nodes_and_weights(n_phi0.try_into().unwrap()); - cache.gauss_quad_lut.insert(n_phi0, (Rc::from(gq_values.0), Rc::from(gq_values.1))); + cache + .gauss_quad_lut + .insert(n_phi0, (Rc::from(gq_values.0), Rc::from(gq_values.1))); println!("n_omnes={} is not included in the lookup file. Consider generating a new lookup file via the appropriate function in gq_storage.rs", n_phi0); } let (ref roots, ref weights) = cache.gauss_quad_lut.get(&n_phi0).unwrap(); let (roots, weights) = (Rc::clone(roots), Rc::clone(weights)); - let analyt = omnes(cache, s, n_omnes, use_tan_omnes).norm_sqr().ln() / S0.sqrt() / 2.0; - let intgrl = if use_tan_phi0 { - if use_xsub { - s / PI * integrate(&*roots, &*weights, 0.0, PI / 2.0, |x| phi0_integrand_tan_xsub(cache, x, s, n_omnes, use_tan_omnes)) - } else { - s / PI * integrate(&*roots, &*weights, S0.atan(), PI / 2.0, |x| phi0_integrand_tan_noxsub(cache, x, s, n_omnes, use_tan_omnes)) - } + let analyt = if use_reduced_integrand { + omnes(cache, s, n_omnes, use_tan_omnes).norm().ln() / S0.sqrt() } else { - if use_xsub { - s / PI * integrate(&*roots, &*weights, 0.0, INF, |x| phi0_integrand_notan_xsub(cache, x, s, n_omnes, use_tan_omnes)) - } else { - s / PI * integrate(&*roots, &*weights, S0, INF, |x| phi0_integrand_notan_noxsub(cache, x, s, n_omnes, use_tan_omnes)) - } + (omnes(cache, s, n_omnes, use_tan_omnes) / omnes(cache, S0, n_omnes, use_tan_omnes)) + .norm() + .ln() + / (s * (s - S0).powf(1.5)) }; - //println!("{:?}", t0.elapsed()); - -(s-S0).sqrt() * (intgrl - analyt) + let intgrl = integrate( + &*roots, + &*weights, + if use_xsub { + 0.0 + } else if use_tan_phi0 { + S0.atan() + } else { + S0 + }, + if use_tan_phi0 { PI / 2.0 } else { INF }, + |x| { + phi0_integrand( + cache, + x, + s, + n_omnes, + use_tan_omnes, + use_tan_phi0, + use_xsub, + use_reduced_integrand, + ) * s + / PI + }, + print_prog, + ); + -(s - S0).sqrt() * (intgrl - analyt) } #[allow(unused)] -pub fn bit_pattern_randomness_tester(a:f64, b:f64, n_points: u64) -> Vec{ +pub fn bit_pattern_randomness_tester(a: f64, b: f64, n_points: u64) -> Vec { let mut modulos = vec![0.0; n_points as usize]; - let x_values: Vec = (0..modulos.len() as u32).map(|x| (f64::from(x) * ((b - a) / f64::from(modulos.len() as u32)) + a).to_bits()).collect(); + let x_values: Vec = (0..modulos.len() as u32) + .map(|x| (f64::from(x) * ((b - a) / f64::from(modulos.len() as u32)) + a).to_bits()) + .collect(); for i in 0..x_values.len() { let val = (x_values[i] % n_points) as usize; modulos[val] += 1.0; diff --git a/bachelorarbeit/src/gq_storage.rs b/bachelorarbeit/src/gq_storage.rs index e52630a..75c8182 100644 --- a/bachelorarbeit/src/gq_storage.rs +++ b/bachelorarbeit/src/gq_storage.rs @@ -28,7 +28,7 @@ pub fn serialize(filepath: &str, params: Vec<(Vec, Vec)>) -> io::Resul Ok(()) } -pub fn deserialize(reader: &mut R, filter: impl Fn(u64) -> bool) -> io::Result, Vec)>> { +pub fn deserialize(reader: &mut R, filter: impl Fn(u64) -> bool) -> io::Result, Vec)>> { let mut buf = [0u8; 8]; let mut values = Vec::new(); diff --git a/bachelorarbeit/src/main.rs b/bachelorarbeit/src/main.rs index 828e95e..3ad4f9c 100644 --- a/bachelorarbeit/src/main.rs +++ b/bachelorarbeit/src/main.rs @@ -1,38 +1,35 @@ - // TODO -// - Lookup Table implementieren -> Weights, roots schon früher rausziehen? -// -> Warum macht delta_lut alles langsamer? -// - Omnes auch komplex integrieren (geht nicht mit Integralmethode von gauss-quad) -// - Textfelder und "Berechnen"-Button in UI, um z.B. Wertebereich zu setzen -// - Neue Architketur: struct calculator, das lookups speichert -> In die nötigen Funktionen übergeben. Dadurch kann man omnes auch als single calc machen und trotzdem die Punkte nur einmal berechnen // - AutoImport ausschalten +// - Reduziertes Integral aus Paper zu numerisch berechenbarer Form umformen +use indicatif; +use std::collections::HashMap; use egui_plot::{log_grid_spacer, AxisHints, GridInput, GridMark, Legend, Line, Plot}; use num::complex::ComplexFloat; -use std::time::Instant; -mod gq_storage; mod calc; +mod gq_storage; struct App { plot_data: Vec, - plots_available: [String; 6], + plots_available: [String; 4], calc_cache: calc::Cache, - scaling_type: ScalingType, + scaling_type: ScalingType, a: f64, - b: f64, + b: f64, n_points: u32, n_omnes: u32, n_phi0: u32, use_tan_omnes: bool, use_tan_phi0: bool, - use_xsub_phi0: bool + use_xsub_phi0: bool, + use_reduced_integrand: bool, } #[derive(Clone)] struct PlotCurve { - points: Vec<[f64;2]>, + points: Vec<[f64; 2]>, name: String, } @@ -40,26 +37,32 @@ impl Default for App { fn default() -> Self { App { plot_data: Vec::default(), - plots_available: ["Delta".to_string(), "Omnes Integrand".to_string(), "Omnes".to_string(), "Phi0 Integrand".to_string(), "Phi0".to_string(), "Phi0 / delta".to_string()], + plots_available: [ + "Delta".to_string(), + "Omnes".to_string(), + "Phi0".to_string(), + "Phi0 / delta".to_string(), + ], calc_cache: calc::Cache::default(), scaling_type: ScalingType::default(), a: calc::S0, b: 9.0, - n_points: 5000, - n_omnes:1000, - n_phi0:1000, + n_points: 500, + n_omnes: 500, + n_phi0: 500, use_tan_omnes: true, use_tan_phi0: true, - use_xsub_phi0: true + use_xsub_phi0: true, + use_reduced_integrand: true, } } } #[derive(Debug, Default, PartialEq, Clone, Copy)] enum ScalingType { - Logarithmic, + Logarithmic, #[default] - Linear + Linear, } impl eframe::App for App { @@ -72,38 +75,65 @@ impl eframe::App for App { egui::Grid::new("grid1") .min_col_width(125.0) .show(ui, |ui| { - ui.label("calc interval start:").on_hover_text("the upper bound of the interval that functions are calculated in");; - float_text_edit_singleline(ui, &mut self.a); - ui.end_row(); + ui.label("calc interval start:").on_hover_text( + "the lower bound of the interval that functions are calculated in", + ); + float_text_edit_singleline(ui, &mut self.a); + ui.end_row(); - ui.label("calc interval end:").on_hover_text("the upper bound of the interval that functions are calculated in"); - float_text_edit_singleline(ui, &mut self.b); - ui.end_row(); - - ui.label("N for omnes:").on_hover_text("the number of points used in calculation of omnes function"); - int_text_edit_singleline(ui, &mut self.n_omnes); - ui.end_row(); + ui.label("calc interval end:").on_hover_text( + "the upper bound of the interval that functions are calculated in", + ); + float_text_edit_singleline(ui, &mut self.b); + ui.end_row(); - ui.label("N for phi0:").on_hover_text("the number of points used in calculation of phi0 function"); - int_text_edit_singleline(ui, &mut self.n_phi0); - ui.end_row(); + ui.label("N for omnes:").on_hover_text( + "the number of points used in calculation of omnes function", + ); + int_text_edit_singleline(ui, &mut self.n_omnes); + ui.end_row(); - ui.label("number of plotpoints:").on_hover_text("the number of points shown in the plot"); - int_text_edit_singleline(ui, &mut self.n_points); - ui.end_row(); - }); + ui.label("N for phi0:").on_hover_text( + "the number of points used in calculation of phi0 function", + ); + int_text_edit_singleline(ui, &mut self.n_phi0); + ui.end_row(); + + ui.label("number of plotpoints:") + .on_hover_text("the number of points shown in the plot"); + int_text_edit_singleline(ui, &mut self.n_points); + ui.end_row(); + }); ui.separator(); ui.vertical(|ui| { - ui.checkbox(&mut self.use_tan_omnes, "Use tan()-subst. for Omnes"); - ui.checkbox(&mut self.use_tan_phi0, "Use tan()-subst. for phi0"); - ui.checkbox(&mut self.use_xsub_phi0, "Use second subst. for phi0"); - egui::ComboBox::from_label("pick y-scaling").selected_text(format!("{:?}", self.scaling_type)).show_ui(ui, |ui| { - ui.selectable_value(&mut self.scaling_type, ScalingType::Logarithmic, "log10"); - ui.selectable_value(&mut self.scaling_type, ScalingType::Linear, "linear"); - }); - + let omnes_cb = + ui.checkbox(&mut self.use_tan_omnes, "Use tan()-subst. for Omnes ('ot')"); + if omnes_cb.clicked() { + self.calc_cache.omnes_lut = HashMap::with_hasher(Default::default()); // TODO split omnes_lut so that this is no longer necessary + } + ui.checkbox(&mut self.use_tan_phi0, "Use tan()-subst. for phi0 ('pt')"); + ui.checkbox(&mut self.use_xsub_phi0, "Use second subst. for phi0 ('ss')"); + ui.checkbox( + &mut self.use_reduced_integrand, + "Use reduced integrand for phi0", + ); + egui::ComboBox::from_label("pick y-scaling") + .selected_text(format!("{:?}", self.scaling_type)) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.scaling_type, + ScalingType::Logarithmic, + "log10", + ); + ui.selectable_value( + &mut self.scaling_type, + ScalingType::Linear, + "linear", + ); + }); + ui.horizontal(|ui| { let button_clear = ui.button("Clear canvas"); if button_clear.clicked() { @@ -111,99 +141,225 @@ impl eframe::App for App { } egui::widgets::global_dark_light_mode_switch(ui); }); - }); }); - - ui.separator(); - + + ui.separator(); + ui.label("You can calculate the following functions:"); - ui.horizontal( |ui| { + ui.horizontal(|ui| { for i in 0..self.plots_available.len() { - let button = ui.button( format!("{}", self.plots_available[i].clone())); + let button = ui.button(format!("{}", self.plots_available[i].clone())); if button.clicked() { - let x_values: Vec = (0..self.n_points).map(|x| -> f64 {f64::from(x) * ((self.b - self.a) / f64::from(self.n_points)) + self.a}).collect(); + let x_values: Vec = (0..self.n_points) + .map(|x| -> f64 { + f64::from(x) * ((self.b - self.a) / f64::from(self.n_points)) + + self.a + }) + .collect(); match i { 0 => { - let y_values_delta:Vec = if self.scaling_type == ScalingType::Linear { - x_values.iter().map(|&x| calc::delta_with_lut(&mut self.calc_cache, x)).collect() + let y_values_delta: Vec = if self.scaling_type + == ScalingType::Linear + { + x_values + .iter() + .map(|&x| calc::delta_with_lut(&mut self.calc_cache, x)) + .collect() } else { - x_values.iter().map(|&x| calc::delta_with_lut(&mut self.calc_cache, x).log10()).collect() + x_values + .iter() + .map(|&x| { + calc::delta_with_lut(&mut self.calc_cache, x) + .log10() + }) + .collect() }; - + self.plot_data.push(PlotCurve { - points: x_values.iter().zip(y_values_delta.iter()).map(|(&x,&y)| [x.powf(0.5),y]).collect(), - name: "Delta".to_string() + points: x_values + .iter() + .zip(y_values_delta.iter()) + .map(|(&x, &y)| [x.powf(0.5), y]) + .collect(), + name: format!("(#{}) Delta", self.plot_data.len() + 1), }) } 1 => { - let y_values_omnes_integrand:Vec = if self.scaling_type == ScalingType::Linear { - x_values.iter().map(|&x| calc::omnes_integrand_tan(&mut self.calc_cache, x, 100.0).abs()).collect() + let y_values_omnes: Vec = if self.scaling_type + == ScalingType::Linear + { + print!("Calculating all plot points: "); + let bar = + indicatif::ProgressBar::new(u64::from(self.n_points)); + let res = x_values + .iter() + .map(|&x| { + bar.inc(1); + calc::omnes( + &mut self.calc_cache, + x, + self.n_omnes, + self.use_tan_omnes, + ) + .abs() + //.powi(2) + }) + .collect(); + bar.finish(); + res } else { - x_values.iter().map(|&x| calc::omnes_integrand_tan(&mut self.calc_cache, x, 100.0).abs().log10()).collect() + x_values + .iter() + .map(|&x| { + calc::omnes( + &mut self.calc_cache, + x, + self.n_omnes, + self.use_tan_omnes, + ) + .abs() + .powi(2) + .log10() + }) + .collect() }; self.plot_data.push(PlotCurve { - points: x_values.iter().zip(y_values_omnes_integrand.iter()).map(|(&x,&y)| [x.powf(0.5),y]).collect(), - name: "Omnes Integrand".to_string() + points: x_values + .iter() + .zip(y_values_omnes.iter()) + .map(|(&x, &y)| [x.powf(0.5), y]) + .collect(), + name: format!( + "(#{}) Omnes, {} ot, n_o={}", + self.plot_data.len() + 1, + if self.use_tan_omnes { "w/" } else { "no " }, + self.n_omnes + ), }) } 2 => { - let y_values_omnes:Vec = if self.scaling_type == ScalingType::Linear { - x_values.iter().map(|&x| calc::omnes(&mut self.calc_cache, x, self.n_omnes, self.use_tan_omnes).abs().powi(2)).collect() - } else { - x_values.iter().map(|&x| calc::omnes(&mut self.calc_cache, x, self.n_omnes, self.use_tan_omnes).abs().powi(2).log10()).collect() - }; + let y_values_phi0: Vec = + if self.scaling_type == ScalingType::Linear { + let bar = + indicatif::ProgressBar::new(u64::from(self.n_points)); + x_values + .iter() + .map(|&x| { + bar.inc(1); + calc::phi0( + &mut self.calc_cache, + x, + self.n_omnes, + self.n_phi0, + self.use_tan_omnes, + self.use_tan_phi0, + self.use_xsub_phi0, + self.use_reduced_integrand, + x == self.a, + ) + }) + .collect() + } else { + x_values + .iter() + .map(|&x| { + calc::phi0( + &mut self.calc_cache, + x, + self.n_omnes, + self.n_phi0, + self.use_tan_omnes, + self.use_tan_phi0, + self.use_xsub_phi0, + self.use_reduced_integrand, + x == self.a, + ) + .log10() + }) + .collect() + }; self.plot_data.push(PlotCurve { - points: x_values.iter().zip(y_values_omnes.iter()).map(|(&x,&y)| [x.powf(0.5),y]).collect(), - name: "Omnes".to_string() + points: x_values + .iter() + .zip(y_values_phi0.iter()) + .map(|(&x, &y)| [x.powf(0.5), y]) + .collect(), + name: format!( + "(#{}) phi0, {} ot, {} pt, {} ss, n_o={}, n_p={}", + self.plot_data.len() + 1, + if self.use_tan_omnes { "w/" } else { "no " }, + if self.use_tan_phi0 { "w/" } else { "no " }, + if self.use_xsub_phi0 { "w/" } else { "no " }, + self.n_omnes, + self.n_phi0 + ), }) } 3 => { - let y_values_phi0_integrand:Vec = if self.scaling_type == ScalingType::Linear { - x_values.iter().map(|&x| calc::phi0_integrand_tan_xsub(&mut self.calc_cache, x, 10000.0, self.n_omnes, self.use_tan_omnes)).collect() - } else { - x_values.iter().map(|&x| calc::phi0_integrand_tan_xsub(&mut self.calc_cache, x, 10000.0, self.n_omnes, self.use_tan_omnes).log10()).collect() - }; + let y_values_phi0: Vec = + if self.scaling_type == ScalingType::Linear { + x_values + .iter() + .map(|&x| { + let val = calc::phi0( + &mut self.calc_cache, + x, + self.n_omnes, + self.n_phi0, + self.use_tan_omnes, + self.use_tan_phi0, + self.use_xsub_phi0, + self.use_reduced_integrand, + x == self.a, + ) / calc::delta_with_lut( + &mut self.calc_cache, + x, + ); + val + }) + .collect() + } else { + x_values + .iter() + .map(|&x| { + let val = calc::phi0( + &mut self.calc_cache, + x, + self.n_omnes, + self.n_phi0, + self.use_tan_omnes, + self.use_tan_phi0, + self.use_xsub_phi0, + self.use_reduced_integrand, + x == self.a, + ) / calc::delta_with_lut( + &mut self.calc_cache, + x, + ); + val.log10() + }) + .collect() + }; self.plot_data.push(PlotCurve { - points: x_values.iter().zip(y_values_phi0_integrand.iter()).map(|(&x,&y)| [x.powf(0.5),y]).collect(), - name: "Phi0 Integrand".to_string() + points: x_values + .iter() + .zip(y_values_phi0.iter()) + .map(|(&x, &y)| [x.powf(0.5), y]) + .collect(), + name: format!( + "(#{}) phi0 / delta, {} ot, {} pt, {} ss, n_o={}, n_p={}", + self.plot_data.len() + 1, + if self.use_tan_omnes { "w/" } else { "no " }, + if self.use_tan_phi0 { "w/" } else { "no " }, + if self.use_xsub_phi0 { "w/" } else { "no " }, + self.n_omnes, + self.n_phi0 + ), }) } - 4 => { - let y_values_phi0: Vec = if self.scaling_type == ScalingType::Linear { - x_values.iter().map(|&x| calc::phi0(&mut self.calc_cache, x, self.n_omnes, self.n_phi0, self.use_tan_omnes, self.use_tan_phi0, self.use_xsub_phi0)).collect() - } else { - x_values.iter().map(|&x| calc::phi0(&mut self.calc_cache, x, self.n_omnes, self.n_phi0, self.use_tan_omnes, self.use_tan_phi0, self.use_xsub_phi0).log10()).collect() - }; - self.plot_data.push(PlotCurve { - points: x_values.iter().zip(y_values_phi0.iter()).map(|(&x,&y)| [x.powf(0.5),y]).collect(), - name: "Phi0".to_string() - }) - // let y_values_phi0 = calc::bit_pattern_randomness_tester(self.a, self.b, self.n_points as u64); - // self.plot_data.push(PlotCurve { - // points: (0..self.n_points).zip(y_values_phi0.iter()).map(|(x,&y)| [x as f64,y]).collect(), - // name: "Phi0".to_string() - // }) - } - 5 => { - let y_values_phi0: Vec = if self.scaling_type == ScalingType::Linear { - x_values.iter().map(|&x| { - let val = calc::phi0(&mut self.calc_cache, x.powi(2), self.n_omnes, self.n_phi0, self.use_tan_omnes, self.use_tan_phi0, self.use_xsub_phi0) / calc::delta_with_lut(&mut self.calc_cache, x.powi(2)); - val - }).collect() - } else { - x_values.iter().map(|&x| { - let val = calc::phi0(&mut self.calc_cache, x.powi(2), self.n_omnes, self.n_phi0, self.use_tan_omnes, self.use_tan_phi0, self.use_xsub_phi0) / calc::delta_with_lut(&mut self.calc_cache, x.powi(2)); - val.log10() - }).collect() - }; - self.plot_data.push(PlotCurve { - points: x_values.iter().zip(y_values_phi0.iter()).map(|(&x,&y)| [x,y]).collect(), - name: "phi0 / delta".to_string() - }) - } - 6_usize.. => { + 4_usize.. => { panic!("Not all buttons have been assigned data!"); } } @@ -211,10 +367,10 @@ impl eframe::App for App { } }); }); - + if self.scaling_type != cur_scaling_type { - for curve in self.plot_data.iter_mut() { - for [_x,y] in curve.points.iter_mut() { + for curve in self.plot_data.iter_mut() { + for [_x, y] in curve.points.iter_mut() { if self.scaling_type == ScalingType::Linear { *y = 10.0f64.powf(*y); } else if self.scaling_type == ScalingType::Logarithmic { @@ -230,27 +386,42 @@ impl eframe::App for App { .legend(Legend::default()); let plot = match self.scaling_type { - ScalingType::Linear => plot.custom_y_axes(vec![AxisHints::new_y().formatter(|mark, _l, _| scientific_notation(mark.value, false))]), - ScalingType::Logarithmic => {plot.y_grid_spacer(|input| { - let input_exp = GridInput {bounds: (inverse_log_map(input.bounds.0), inverse_log_map(input.bounds.1)), base_step_size: input.base_step_size}; + ScalingType::Linear => plot.custom_y_axes(vec![AxisHints::new_y() + .formatter(|mark, _l, _| scientific_notation(mark.value, false))]), + ScalingType::Logarithmic => plot + .y_grid_spacer(|input| { + let input_exp = GridInput { + bounds: ( + inverse_log_map(input.bounds.0), + inverse_log_map(input.bounds.1), + ), + base_step_size: input.base_step_size, + }; let lin_gridmarks = (log_grid_spacer(10))(input_exp); let mut log_gridmarks: Vec = Vec::new(); for v in lin_gridmarks.iter() { if v.value - v.value.floor() < 0.9 { - log_gridmarks.push(GridMark{value:log_map(v.value), step_size:v.step_size / 1.14}); - } + log_gridmarks.push(GridMark { + value: log_map(v.value), + step_size: v.step_size / 1.14, + }); + } } log_gridmarks }) - .label_formatter(|_,point| format!("x = {:.5}\ny = {:.5}", point.x, 10.0f64.powf(point.y)).to_string()) - .custom_y_axes(vec![AxisHints::new_y().formatter(|mark, _l, _| scientific_notation(mark.value, true))]) - } - }; - - + .label_formatter(|_, point| { + format!("x = {:.5}\ny = {:.5}", point.x, 10.0f64.powf(point.y)).to_string() + }) + .custom_y_axes(vec![AxisHints::new_y() + .formatter(|mark, _l, _| scientific_notation(mark.value, true))]), + }; + plot.show(ui, |plot_ui| { for i in 0..self.plot_data.len() { - plot_ui.line(Line::new(self.plot_data[i].points.clone()).name(self.plot_data[i].name.clone())); // is clone necessary? + plot_ui.line( + Line::new(self.plot_data[i].points.clone()) + .name(self.plot_data[i].name.clone()), + ); // is clone necessary? } }); }); @@ -261,14 +432,23 @@ impl eframe::App for App { fn main() { let mut app = App::default(); app.calc_cache = calc::Cache::from_file("./gauss_quad_lut.morello").unwrap(); - // let x_values: Vec = (0..app.n_points).map(|x| -> f64 {f64::from(x) * ((app.b - app.a) / f64::from(app.n_points)) + app.a}).collect(); + // let x_values: Vec = (0..app.n_points) + // .map(|x| -> f64 { f64::from(x) * ((app.b - app.a) / f64::from(app.n_points)) + app.a }) + // .collect(); // let t0 = Instant::now(); - // let y_values_phi0: Vec = x_values.iter().map(|&x| calc::phi0(&mut app.calc_cache, x, app.n_omnes, app.n_phi0)).collect(); + // let y_values_phi0: Vec = x_values + // .iter() + // .map(|&x| calc::phi0(&mut app.calc_cache, x, app.n_omnes, app.n_phi0)) + // .collect(); // std::hint::black_box(&y_values_phi0); // println!("{:?}", t0.elapsed()); - - eframe::run_native("Morellus", eframe::NativeOptions::default(), Box::new(|_cc| Box::new(app))).unwrap(); + eframe::run_native( + "Titel", + eframe::NativeOptions::default(), + Box::new(|_cc| Box::new(app)), + ) + .unwrap(); } #[cfg(target_arch = "wasm32")] @@ -277,10 +457,10 @@ fn main() { wasm_bindgen_futures::spawn_local(async { let res = gloo_net::http::RequestBuilder::new("/lut/gauss_quad_lut.morello") - .method(gloo_net::http::Method::POST) - .send() - .await - .unwrap(); + .method(gloo_net::http::Method::POST) + .send() + .await + .unwrap(); app.calc_cache = calc::Cache::from_slice(&res.binary().await.unwrap()).unwrap(); let web_options = eframe::WebOptions::default(); @@ -296,22 +476,30 @@ fn main() { }); } -fn log_map(x:f64) -> f64 { +fn log_map(x: f64) -> f64 { x.floor() + (1.0 + (x - x.floor()) * 10.0).log10() } -fn inverse_log_map(x:f64) -> f64 { +fn inverse_log_map(x: f64) -> f64 { x.floor() + (10f64.powf(x - x.floor()) - 1.0) / 10.0 } -fn scientific_notation(x:f64, log:bool) -> String { +fn scientific_notation(x: f64, log: bool) -> String { if log { - format!("{}*10^{}", format!( - "{:.8}", 10f64.powf(x - x.floor())) - .trim_end_matches('0').trim_end_matches('.').to_string(), - x.floor()).to_string() + format!( + "{}*10^{}", + format!("{:.8}", 10f64.powf(x - x.floor())) + .trim_end_matches('0') + .trim_end_matches('.') + .to_string(), + x.floor() + ) + .to_string() } else { - format!("{:.9}", x).trim_end_matches('0').trim_end_matches('.').to_string() + format!("{:.9}", x) + .trim_end_matches('0') + .trim_end_matches('.') + .to_string() } } @@ -322,7 +510,6 @@ fn int_text_edit_singleline(ui: &mut egui::Ui, value: &mut u32) -> egui::Respons *value = result; } else if tmp_value == "" { *value = 0; - } res } @@ -336,4 +523,4 @@ fn float_text_edit_singleline(ui: &mut egui::Ui, value: &mut f64) -> egui::Respo *value = 0.0; } res -} \ No newline at end of file +}