general cleanup

This commit is contained in:
Simon Gardling 2022-04-06 11:26:38 -04:00
parent 2025528682
commit 30b5a15cc8

View File

@ -52,11 +52,11 @@ pub struct FunctionEntry {
/// If displaying derivatives are enabled (note, they are still calculated for other purposes) /// If displaying derivatives are enabled (note, they are still calculated for other purposes)
pub derivative: bool, pub derivative: bool,
back_data: Option<Vec<Value>>, back_data: Vec<Value>,
integral_data: Option<(Vec<Bar>, f64)>, integral_data: Option<(Vec<Bar>, f64)>,
derivative_data: Option<Vec<Value>>, derivative_data: Vec<Value>,
extrema_data: Option<Vec<Value>>, extrema_data: Vec<Value>,
roots_data: Option<Vec<Value>>, roots_data: Vec<Value>,
autocomplete: AutoComplete, autocomplete: AutoComplete,
@ -73,11 +73,11 @@ impl Default for FunctionEntry {
max_x: 1.0, max_x: 1.0,
integral: false, integral: false,
derivative: false, derivative: false,
back_data: None, back_data: Vec::new(),
integral_data: None, integral_data: None,
derivative_data: None, derivative_data: Vec::new(),
extrema_data: None, extrema_data: Vec::new(),
roots_data: None, roots_data: Vec::new(),
autocomplete: AutoComplete::default(), autocomplete: AutoComplete::default(),
test_result: None, test_result: None,
} }
@ -168,37 +168,29 @@ impl FunctionEntry {
} }
/// Helps with processing newton's method depending on level of derivative /// Helps with processing newton's method depending on level of derivative
fn newtons_method_helper( fn newtons_method_helper(&self, threshold: &f64, derivative_level: usize) -> Vec<Value> {
&self, threshold: &f64, derivative_level: usize,
) -> Option<Vec<Value>> {
let range = self.min_x..self.max_x; let range = self.min_x..self.max_x;
let newtons_method_output: Vec<f64> = match derivative_level { let newtons_method_output: Vec<f64> = match derivative_level {
0 => newtons_method_helper( 0 => newtons_method_helper(
threshold, threshold,
&range, &range,
self.back_data.as_ref().unwrap(), self.back_data.as_slice(),
&|x: f64| self.function.get(x), &|x: f64| self.function.get(x),
&|x: f64| self.function.get_derivative_1(x), &|x: f64| self.function.get_derivative_1(x),
), ),
1 => newtons_method_helper( 1 => newtons_method_helper(
threshold, threshold,
&range, &range,
self.derivative_data.as_ref().unwrap(), self.derivative_data.as_slice(),
&|x: f64| self.function.get_derivative_1(x), &|x: f64| self.function.get_derivative_1(x),
&|x: f64| self.function.get_derivative_2(x), &|x: f64| self.function.get_derivative_2(x),
), ),
_ => unreachable!(), _ => unreachable!(),
}; };
if newtons_method_output.is_empty() { dyn_iter(&newtons_method_output)
None .map(|x| Value::new(*x, self.function.get(*x)))
} else { .collect()
Some(
dyn_iter(&newtons_method_output)
.map(|x| Value::new(*x, self.function.get(*x)))
.collect(),
)
}
} }
/// Does the calculations and stores results in `self` /// Does the calculations and stores results in `self`
@ -227,12 +219,11 @@ impl FunctionEntry {
if width_changed { if width_changed {
self.invalidate_back(); self.invalidate_back();
self.invalidate_derivative(); self.invalidate_derivative();
} else if min_max_changed && self.back_data.is_some() { } else if min_max_changed && !self.back_data.is_empty() {
partial_regen = true; partial_regen = true;
let back_cache = self.back_data.as_ref().unwrap(); let x_data: SteppedVector = self
.back_data
let x_data: SteppedVector = back_cache
.iter() .iter()
.map(|ele| ele.x) .map(|ele| ele.x)
.collect::<Vec<f64>>() .collect::<Vec<f64>>()
@ -241,7 +232,7 @@ impl FunctionEntry {
let back_data: Vec<Value> = dyn_iter(&resolution_iter) let back_data: Vec<Value> = dyn_iter(&resolution_iter)
.map(|x| { .map(|x| {
if let Some(i) = x_data.get_index(x) { if let Some(i) = x_data.get_index(x) {
back_cache[i] self.back_data[i]
} else { } else {
Value::new(*x, self.function.get(*x)) Value::new(*x, self.function.get(*x))
} }
@ -250,14 +241,13 @@ impl FunctionEntry {
debug_assert_eq!(back_data.len(), settings.plot_width + 1); debug_assert_eq!(back_data.len(), settings.plot_width + 1);
self.back_data = Some(back_data); self.back_data = back_data;
if derivative_required { if derivative_required {
let derivative_cache = self.derivative_data.as_ref().unwrap();
let new_derivative_data: Vec<Value> = dyn_iter(&resolution_iter) let new_derivative_data: Vec<Value> = dyn_iter(&resolution_iter)
.map(|x| { .map(|x| {
if let Some(i) = x_data.get_index(x) { if let Some(i) = x_data.get_index(x) {
derivative_cache[i] self.derivative_data[i]
} else { } else {
Value::new(*x, self.function.get_derivative_1(*x)) Value::new(*x, self.function.get_derivative_1(*x))
} }
@ -266,9 +256,9 @@ impl FunctionEntry {
debug_assert_eq!(new_derivative_data.len(), settings.plot_width + 1); debug_assert_eq!(new_derivative_data.len(), settings.plot_width + 1);
self.derivative_data = Some(new_derivative_data); self.derivative_data = new_derivative_data;
} else { } else {
self.derivative_data = None; self.invalidate_derivative();
} }
} else { } else {
self.invalidate_back(); self.invalidate_back();
@ -278,21 +268,21 @@ impl FunctionEntry {
let threshold: f64 = resolution / 2.0; let threshold: f64 = resolution / 2.0;
if !partial_regen { if !partial_regen {
if self.back_data.is_none() { if self.back_data.is_empty() {
let data: Vec<Value> = dyn_iter(&resolution_iter) let data: Vec<Value> = dyn_iter(&resolution_iter)
.map(|x| Value::new(*x, self.function.get(*x))) .map(|x| Value::new(*x, self.function.get(*x)))
.collect(); .collect();
debug_assert_eq!(data.len(), settings.plot_width + 1); debug_assert_eq!(data.len(), settings.plot_width + 1);
self.back_data = Some(data); self.back_data = data;
} }
if derivative_required && self.derivative_data.is_none() { if derivative_required && self.derivative_data.is_empty() {
let data: Vec<Value> = dyn_iter(&resolution_iter) let data: Vec<Value> = dyn_iter(&resolution_iter)
.map(|x| Value::new(*x, self.function.get_derivative_1(*x))) .map(|x| Value::new(*x, self.function.get_derivative_1(*x)))
.collect(); .collect();
debug_assert_eq!(data.len(), settings.plot_width + 1); debug_assert_eq!(data.len(), settings.plot_width + 1);
self.derivative_data = Some(data); self.derivative_data = data;
} }
} }
@ -312,12 +302,12 @@ impl FunctionEntry {
} }
// Calculates extrema // Calculates extrema
if settings.do_extrema && (min_max_changed | self.extrema_data.is_none()) { if settings.do_extrema && (min_max_changed | self.extrema_data.is_empty()) {
self.extrema_data = self.newtons_method_helper(&threshold, 1); self.extrema_data = self.newtons_method_helper(&threshold, 1);
} }
// Calculates roots // Calculates roots
if settings.do_roots && (min_max_changed | self.roots_data.is_none()) { if settings.do_roots && (min_max_changed | self.roots_data.is_empty()) {
self.roots_data = self.newtons_method_helper(&threshold, 0); self.roots_data = self.newtons_method_helper(&threshold, 0);
} }
} }
@ -334,11 +324,11 @@ impl FunctionEntry {
let derivative_str = self.function.get_derivative_str(); let derivative_str = self.function.get_derivative_str();
let step = (settings.integral_min_x - settings.integral_max_x).abs() let step = (settings.integral_min_x - settings.integral_max_x).abs()
/ (settings.integral_num as f64); / (settings.integral_num as f64);
// Plot back data // Plot back data
if let Some(back_data) = &self.back_data { if !self.back_data.is_empty() {
plot_ui.line( plot_ui.line(
back_data self.back_data
.clone()
.to_line() .to_line()
.color(main_plot_color) .color(main_plot_color)
.name(&self.raw_func_str), .name(&self.raw_func_str),
@ -347,10 +337,9 @@ impl FunctionEntry {
// Plot derivative data // Plot derivative data
if self.derivative { if self.derivative {
if let Some(derivative_data) = &self.derivative_data { if !self.derivative_data.is_empty() {
plot_ui.line( plot_ui.line(
derivative_data self.derivative_data
.clone()
.to_line() .to_line()
.color(Color32::GREEN) .color(Color32::GREEN)
.name(derivative_str), .name(derivative_str),
@ -360,30 +349,24 @@ impl FunctionEntry {
// Plot extrema points // Plot extrema points
if settings.do_extrema { if settings.do_extrema {
if let Some(extrema_data) = &self.extrema_data { plot_ui.points(
plot_ui.points( self.extrema_data
extrema_data .to_points()
.clone() .color(Color32::YELLOW)
.to_points() .name("Extrema")
.color(Color32::YELLOW) .radius(5.0), // Radius of points of Extrema
.name("Extrema") );
.radius(5.0), // Radius of points of Extrema
);
}
} }
// Plot roots points // Plot roots points
if settings.do_roots { if settings.do_roots {
if let Some(roots_data) = &self.roots_data { plot_ui.points(
plot_ui.points( self.roots_data
roots_data .to_points()
.clone() .color(Color32::LIGHT_BLUE)
.to_points() .name("Root")
.color(Color32::LIGHT_BLUE) .radius(5.0), // Radius of points of Roots
.name("Root") );
.radius(5.0), // Radius of points of Roots
);
}
} }
// Plot integral data // Plot integral data
@ -404,21 +387,21 @@ impl FunctionEntry {
/// Invalidate entire cache /// Invalidate entire cache
pub fn invalidate_whole(&mut self) { pub fn invalidate_whole(&mut self) {
self.back_data = None; self.invalidate_back();
self.integral_data = None; self.invalidate_integral();
self.derivative_data = None; self.invalidate_derivative();
self.extrema_data = None; self.extrema_data.clear();
self.roots_data = None; self.roots_data.clear();
} }
/// Invalidate `back` data /// Invalidate `back` data
pub fn invalidate_back(&mut self) { self.back_data = None; } pub fn invalidate_back(&mut self) { self.back_data.clear(); }
/// Invalidate Integral data /// Invalidate Integral data
pub fn invalidate_integral(&mut self) { self.integral_data = None; } pub fn invalidate_integral(&mut self) { self.integral_data = None; }
/// Invalidate Derivative data /// Invalidate Derivative data
pub fn invalidate_derivative(&mut self) { self.derivative_data = None; } pub fn invalidate_derivative(&mut self) { self.derivative_data.clear(); }
/// Runs asserts to make sure everything is the expected value /// Runs asserts to make sure everything is the expected value
#[cfg(test)] #[cfg(test)]
@ -428,33 +411,29 @@ impl FunctionEntry {
) { ) {
{ {
self.calculate(&min_x, &max_x, true, &settings); self.calculate(&min_x, &max_x, true, &settings);
let settings = settings;
let back_target = back_target; let back_target = back_target;
assert!(self.back_data.is_some()); assert!(!self.back_data.is_empty());
let back_data = self.back_data.as_ref().unwrap().clone(); assert_eq!(self.back_data.len(), settings.plot_width + 1);
assert_eq!(back_data.len(), settings.plot_width + 1); let back_vec_tuple = self.back_data.to_tuple();
let back_vec_tuple = back_data.to_tuple();
assert_eq!(back_vec_tuple, back_target); assert_eq!(back_vec_tuple, back_target);
assert!(self.integral); assert!(self.integral);
assert!(self.derivative); assert!(self.derivative);
assert_eq!(self.roots_data.is_some(), settings.do_roots); assert_eq!(!self.roots_data.is_empty(), settings.do_roots);
assert_eq!(self.extrema_data.is_some(), settings.do_extrema); assert_eq!(!self.extrema_data.is_empty(), settings.do_extrema);
assert!(self.derivative_data.is_some()); assert!(!self.derivative_data.is_empty());
assert!(self.integral_data.is_some()); assert!(self.integral_data.is_some());
assert_eq!( assert_eq!(self.derivative_data.to_tuple(), derivative_target);
self.derivative_data.as_ref().unwrap().to_tuple(),
derivative_target
);
assert_eq!(self.integral_data.clone().unwrap().1, area_target); assert_eq!(self.integral_data.clone().unwrap().1, area_target);
} }
{ {
self.update_string("x^3"); self.update_string("sin(x)");
assert_eq!(&self.raw_func_str, "x^3"); assert!(self.get_test_result().is_none());
assert_eq!(&self.raw_func_str, "sin(x)");
self.integral = false; self.integral = false;
self.derivative = false; self.derivative = false;
@ -462,19 +441,19 @@ impl FunctionEntry {
assert!(!self.integral); assert!(!self.integral);
assert!(!self.derivative); assert!(!self.derivative);
assert!(self.back_data.is_none()); assert!(self.back_data.is_empty());
assert!(self.integral_data.is_none()); assert!(self.integral_data.is_none());
assert!(self.roots_data.is_none()); assert!(self.roots_data.is_empty());
assert!(self.extrema_data.is_none()); assert!(self.extrema_data.is_empty());
assert!(self.derivative_data.is_none()); assert!(self.derivative_data.is_empty());
self.calculate(&min_x, &max_x, true, &settings); self.calculate(&min_x, &max_x, true, &settings);
assert!(self.back_data.is_some()); assert!(!self.back_data.is_empty());
assert!(self.integral_data.is_none()); assert!(self.integral_data.is_none());
assert!(self.roots_data.is_none()); assert!(self.roots_data.is_empty());
assert!(self.extrema_data.is_none()); assert!(self.extrema_data.is_empty());
assert!(self.derivative_data.is_none()); assert!(self.derivative_data.is_empty());
} }
} }
} }