general cleanup
This commit is contained in:
parent
2025528682
commit
30b5a15cc8
137
src/function.rs
137
src/function.rs
@ -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() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(
|
|
||||||
dyn_iter(&newtons_method_output)
|
dyn_iter(&newtons_method_output)
|
||||||
.map(|x| Value::new(*x, self.function.get(*x)))
|
.map(|x| Value::new(*x, self.function.get(*x)))
|
||||||
.collect(),
|
.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,31 +349,25 @@ 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(
|
||||||
extrema_data
|
self.extrema_data
|
||||||
.clone()
|
|
||||||
.to_points()
|
.to_points()
|
||||||
.color(Color32::YELLOW)
|
.color(Color32::YELLOW)
|
||||||
.name("Extrema")
|
.name("Extrema")
|
||||||
.radius(5.0), // Radius of points of 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(
|
||||||
roots_data
|
self.roots_data
|
||||||
.clone()
|
|
||||||
.to_points()
|
.to_points()
|
||||||
.color(Color32::LIGHT_BLUE)
|
.color(Color32::LIGHT_BLUE)
|
||||||
.name("Root")
|
.name("Root")
|
||||||
.radius(5.0), // Radius of points of Roots
|
.radius(5.0), // Radius of points of Roots
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Plot integral data
|
// Plot integral data
|
||||||
match &self.integral_data {
|
match &self.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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user