refactor newtons_method

This commit is contained in:
Simon Gardling 2022-03-23 20:56:04 -04:00
parent fd82c71652
commit c4c29328b6
3 changed files with 35 additions and 53 deletions

View File

@ -36,6 +36,7 @@ tar = "0.4.38"
ruzstd = { git = "https://github.com/KillingSpark/zstd-rs.git" } ruzstd = { git = "https://github.com/KillingSpark/zstd-rs.git" }
serde_json = "1.0.79" serde_json = "1.0.79"
tracing = "0.1.32" tracing = "0.1.32"
itertools = "0.10.3"
[build-dependencies] [build-dependencies]
shadow-rs = "0.11.0" shadow-rs = "0.11.0"

View File

@ -226,9 +226,6 @@ impl FunctionEntry {
self.output.invalidate_derivative(); self.output.invalidate_derivative();
} }
let do_extrema = settings.extrema && (min_max_changed | self.output.extrema.is_none());
let do_roots = settings.roots && (min_max_changed | self.output.roots.is_none());
self.min_x = min_x; self.min_x = min_x;
self.max_x = max_x; self.max_x = max_x;
@ -281,12 +278,12 @@ impl FunctionEntry {
}; };
// Calculates extrema // Calculates extrema
if do_extrema { if settings.extrema && (min_max_changed | self.output.extrema.is_none()) {
self.output.extrema = self.newtons_method_helper(threshold, 1); self.output.extrema = self.newtons_method_helper(threshold, 1);
} }
// Calculates roots // Calculates roots
if do_roots { if settings.roots && (min_max_changed | self.output.roots.is_none()) {
self.output.roots = self.newtons_method_helper(threshold, 0); self.output.roots = self.newtons_method_helper(threshold, 0);
} }

View File

@ -1,4 +1,5 @@
use eframe::egui::plot::Value as EguiValue; use eframe::egui::plot::Value as EguiValue;
use itertools::Itertools;
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -183,61 +184,44 @@ pub fn newtons_method(
threshold: f64, range: std::ops::Range<f64>, data: Vec<EguiValue>, f: &dyn Fn(f64) -> f64, threshold: f64, range: std::ops::Range<f64>, data: Vec<EguiValue>, f: &dyn Fn(f64) -> f64,
f_1: &dyn Fn(f64) -> f64, f_1: &dyn Fn(f64) -> f64,
) -> Vec<f64> { ) -> Vec<f64> {
let mut output_list: Vec<f64> = Vec::new(); data.iter()
let mut last_ele_option: Option<EguiValue> = None; .tuples()
for ele in data.iter() { .filter(|(prev, curr)| !(prev.y.is_nan() | curr.y.is_nan()))
if last_ele_option.is_none() { .map(|(prev, curr)| {
last_ele_option = Some(*ele); if prev.y.signum() != curr.y.signum() {
continue; // actual start of newton's method
} let x = {
let mut x1: f64 = prev.x;
let mut x2: f64;
let mut fail: bool = false;
loop {
x2 = x1 - (f(x1) / f_1(x1));
if !range.contains(&x2) {
fail = true;
break;
}
// if `ele.y` is NaN, just continue iterating // If below threshold, break
if ele.y.is_nan() { if (x2 - x1).abs() < threshold {
continue; break;
} }
let last_ele_y = last_ele_option.unwrap().y; // store this here as it's used multiple times x1 = x2;
// if `last_ele.y` is NaN, continue iterating
if last_ele_y.is_nan() {
continue;
}
if last_ele_y.signum() != ele.y.signum() {
// actual start of newton's method
let x = {
let mut x1: f64 = last_ele_option.unwrap().x;
let mut x2: f64;
let mut fail: bool = false;
loop {
x2 = x1 - (f(x1) / f_1(x1));
if !range.contains(&x2) {
fail = true;
break;
} }
// If below threshold, break // If failed, return NaN, which is then filtered out
if (x2 - x1).abs() < threshold { match fail {
break; true => f64::NAN,
false => x1,
} }
};
x1 = x2; return x;
}
// If failed, return NaN, which is then filtered out
match fail {
true => f64::NAN,
false => x1,
}
};
if !x.is_nan() {
output_list.push(x);
} }
} f64::NAN
last_ele_option = Some(*ele); })
} .filter(|x| !x.is_nan())
output_list .collect()
} }
// Returns a vector of length `max_i` starting at value `min_x` with resolution // Returns a vector of length `max_i` starting at value `min_x` with resolution