nth derivative

This commit is contained in:
Simon Gardling
2022-04-12 12:47:36 -04:00
parent 927ca265e6
commit e46040d616
5 changed files with 123 additions and 8 deletions

View File

@@ -50,7 +50,7 @@ pub const DEFAULT_INTEGRAL_NUM: usize = 100;
/// Colors used for plotting
// Colors commented out are used elsewhere and are not included here for better user experience
pub const COLORS: &[Color32; 14] = &[
pub const COLORS: &[Color32; 13] = &[
Color32::RED,
// Color32::GREEN,
// Color32::YELLOW,
@@ -65,7 +65,7 @@ pub const COLORS: &[Color32; 14] = &[
Color32::LIGHT_GRAY,
Color32::LIGHT_RED,
Color32::DARK_GRAY,
Color32::DARK_RED,
// Color32::DARK_RED,
Color32::KHAKI,
Color32::DARK_GREEN,
Color32::DARK_BLUE,

View File

@@ -8,6 +8,7 @@ use eframe::{egui, epaint};
use egui::{
plot::{BarChart, PlotUi, Value},
widgets::plot::Bar,
Checkbox, Context,
};
use epaint::Color32;
use std::fmt::{self, Debug};
@@ -52,15 +53,21 @@ pub struct FunctionEntry {
/// If displaying derivatives are enabled (note, they are still calculated for other purposes)
pub derivative: bool,
pub nth_derviative: bool,
back_data: Vec<Value>,
integral_data: Option<(Vec<Bar>, f64)>,
derivative_data: Vec<Value>,
extrema_data: Vec<Value>,
root_data: Vec<Value>,
nth_derivative_data: Option<Vec<Value>>,
autocomplete: AutoComplete<'static>,
test_result: Option<String>,
curr_nth: usize,
pub settings_opened: bool,
}
impl Default for FunctionEntry {
@@ -73,13 +80,17 @@ impl Default for FunctionEntry {
max_x: 1.0,
integral: false,
derivative: false,
nth_derviative: false,
back_data: Vec::new(),
integral_data: None,
derivative_data: Vec::new(),
extrema_data: Vec::new(),
root_data: Vec::new(),
nth_derivative_data: None,
autocomplete: AutoComplete::default(),
test_result: None,
curr_nth: 3,
settings_opened: false,
}
}
}
@@ -94,6 +105,32 @@ impl FunctionEntry {
self.update_string(&output_string);
}
pub fn settings(&mut self, ctx: &Context) {
let mut invalidate_nth = false;
egui::Window::new(format!("Settings: {}", self.raw_func_str))
.open(&mut self.settings_opened)
.default_pos([200.0, 200.0])
.resizable(false)
.collapsible(false)
.show(ctx, |ui| {
ui.add(Checkbox::new(
&mut self.nth_derviative,
"Display Nth Derivative",
));
if ui
.add(egui::Slider::new(&mut self.curr_nth, 3..=5).text("Nth Derivative"))
.changed()
{
invalidate_nth = true;
}
});
if invalidate_nth {
self.invalidate_nth();
}
}
/// Get function's cached test result
pub fn get_test_result(&self) -> &Option<String> { &self.test_result }
@@ -263,6 +300,24 @@ impl FunctionEntry {
} else {
self.invalidate_derivative();
}
if self.nth_derviative && let Some(nth_derivative_data) = &self.nth_derivative_data {
let new_nth_derivative_data: Vec<Value> = dyn_iter(&resolution_iter)
.map(|x| {
if let Some(i) = x_data.get_index(x) {
(*nth_derivative_data)[i]
} else {
Value::new(*x, self.function.get_nth_derivative(self.curr_nth, *x))
}
})
.collect();
debug_assert_eq!(new_nth_derivative_data.len(), settings.plot_width + 1);
self.nth_derivative_data = Some(new_nth_derivative_data);
} else {
self.invalidate_nth();
}
} else {
self.invalidate_back();
self.invalidate_derivative();
@@ -287,6 +342,14 @@ impl FunctionEntry {
debug_assert_eq!(data.len(), settings.plot_width + 1);
self.derivative_data = data;
}
if self.nth_derviative && self.nth_derivative_data.is_none() {
let data: Vec<Value> = dyn_iter(&resolution_iter)
.map(|x| Value::new(*x, self.function.get_nth_derivative(self.curr_nth, *x)))
.collect();
debug_assert_eq!(data.len(), settings.plot_width + 1);
self.nth_derivative_data = Some(data);
}
}
if self.integral {
@@ -370,6 +433,15 @@ impl FunctionEntry {
);
}
if self.nth_derviative && let Some(nth_derviative) = &self.nth_derivative_data {
plot_ui.line(
(*nth_derviative)
.to_line()
.color(Color32::DARK_RED)
.name(self.function.get_nth_derivative_str()),
);
}
// Plot integral data
match &self.integral_data {
Some(integral_data) => {
@@ -391,6 +463,7 @@ impl FunctionEntry {
self.invalidate_back();
self.invalidate_integral();
self.invalidate_derivative();
self.invalidate_nth();
self.extrema_data.clear();
self.root_data.clear();
}
@@ -404,6 +477,8 @@ impl FunctionEntry {
/// Invalidate Derivative data
pub fn invalidate_derivative(&mut self) { self.derivative_data.clear(); }
pub fn invalidate_nth(&mut self) { self.nth_derivative_data = None }
/// Runs asserts to make sure everything is the expected value
#[cfg(test)]
pub fn tests(

View File

@@ -464,9 +464,19 @@ impl MathApp {
.clicked(),
);
function.settings_opened.bitxor_assign(
ui.add(Button::new(""))
.on_hover_text(match function.settings_opened {
true => "Close Settings",
false => "Open Settings",
})
.clicked(),
);
// Contains the function string in a text box that the user can edit
function.auto_complete(ui, i as i32)
});
function.settings(ctx);
}
// Remove function if the user requests it

View File

@@ -16,6 +16,8 @@ pub struct BackingFunction {
derivative_1_str: String,
/// f''(x)
derivative_2: FlatEx<f64>,
nth_derivative: Option<(usize, FlatEx<f64>, String)>,
}
impl BackingFunction {
@@ -66,6 +68,7 @@ impl BackingFunction {
derivative_1,
derivative_1_str,
derivative_2,
nth_derivative: None,
})
}
@@ -84,6 +87,34 @@ impl BackingFunction {
pub fn get_derivative_2(&self, x: f64) -> f64 {
self.derivative_2.eval(&[x]).unwrap_or(f64::NAN)
}
pub fn get_nth_derivative_str(&self) -> &str { &self.nth_derivative.as_ref().unwrap().2 }
pub fn get_nth_derivative(&mut self, n: usize, x: f64) -> f64 {
match n {
0 => self.get(x),
1 => self.get_derivative_1(x),
2 => self.get_derivative_2(x),
_ => {
if let Some((curr_n, curr_n_func, _)) = &self.nth_derivative {
if curr_n == &n {
return curr_n_func.eval(&[x]).unwrap_or(f64::NAN);
}
}
let new_func = self
.function
.partial_iter((1..=n).map(|_| 0).collect::<Vec<usize>>().iter())
.unwrap_or_else(|_| EMPTY_FUNCTION.clone());
self.nth_derivative = Some((
n,
new_func.clone(),
new_func.unparse().to_owned().replace("{x}", "x"),
));
return new_func.eval(&[x]).unwrap_or(f64::NAN);
}
}
}
}
const VALID_VARIABLES: [char; 5] = ['x', 'X', 'e', 'E', 'π'];