nth derivative
This commit is contained in:
parent
927ca265e6
commit
e46040d616
11
TODO.md
11
TODO.md
@ -9,9 +9,8 @@
|
||||
- Display of intersections between functions
|
||||
4. Allow constants in min/max integral input (like pi or euler's number)
|
||||
5. Sliding values for functions (like a user-interactable slider that adjusts a variable in the function, like desmos)
|
||||
6. nth derivative support (again)
|
||||
7. Threading (Partially mplemented when running natively)
|
||||
8. Fix integral display
|
||||
9. Look into other, better methods of compression that would be faster
|
||||
10. Better handling of panics and errors to display to the user
|
||||
11. Turn Dynamic Iterator functions into traits
|
||||
6. Threading (Partially implemented when running natively)
|
||||
7. Fix integral display
|
||||
8. Look into other, better methods of compression that would be faster
|
||||
9. Better handling of panics and errors to display to the user
|
||||
10. Turn Dynamic Iterator functions into traits
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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', 'π'];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user