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
|
- Display of intersections between functions
|
||||||
4. Allow constants in min/max integral input (like pi or euler's number)
|
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)
|
5. Sliding values for functions (like a user-interactable slider that adjusts a variable in the function, like desmos)
|
||||||
6. nth derivative support (again)
|
6. Threading (Partially implemented when running natively)
|
||||||
7. Threading (Partially mplemented when running natively)
|
7. Fix integral display
|
||||||
8. Fix integral display
|
8. Look into other, better methods of compression that would be faster
|
||||||
9. Look into other, better methods of compression that would be faster
|
9. Better handling of panics and errors to display to the user
|
||||||
10. Better handling of panics and errors to display to the user
|
10. Turn Dynamic Iterator functions into traits
|
||||||
11. Turn Dynamic Iterator functions into traits
|
|
||||||
|
|||||||
@ -50,7 +50,7 @@ pub const DEFAULT_INTEGRAL_NUM: usize = 100;
|
|||||||
|
|
||||||
/// Colors used for plotting
|
/// Colors used for plotting
|
||||||
// Colors commented out are used elsewhere and are not included here for better user experience
|
// 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::RED,
|
||||||
// Color32::GREEN,
|
// Color32::GREEN,
|
||||||
// Color32::YELLOW,
|
// Color32::YELLOW,
|
||||||
@ -65,7 +65,7 @@ pub const COLORS: &[Color32; 14] = &[
|
|||||||
Color32::LIGHT_GRAY,
|
Color32::LIGHT_GRAY,
|
||||||
Color32::LIGHT_RED,
|
Color32::LIGHT_RED,
|
||||||
Color32::DARK_GRAY,
|
Color32::DARK_GRAY,
|
||||||
Color32::DARK_RED,
|
// Color32::DARK_RED,
|
||||||
Color32::KHAKI,
|
Color32::KHAKI,
|
||||||
Color32::DARK_GREEN,
|
Color32::DARK_GREEN,
|
||||||
Color32::DARK_BLUE,
|
Color32::DARK_BLUE,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use eframe::{egui, epaint};
|
|||||||
use egui::{
|
use egui::{
|
||||||
plot::{BarChart, PlotUi, Value},
|
plot::{BarChart, PlotUi, Value},
|
||||||
widgets::plot::Bar,
|
widgets::plot::Bar,
|
||||||
|
Checkbox, Context,
|
||||||
};
|
};
|
||||||
use epaint::Color32;
|
use epaint::Color32;
|
||||||
use std::fmt::{self, Debug};
|
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)
|
/// If displaying derivatives are enabled (note, they are still calculated for other purposes)
|
||||||
pub derivative: bool,
|
pub derivative: bool,
|
||||||
|
|
||||||
|
pub nth_derviative: bool,
|
||||||
|
|
||||||
back_data: Vec<Value>,
|
back_data: Vec<Value>,
|
||||||
integral_data: Option<(Vec<Bar>, f64)>,
|
integral_data: Option<(Vec<Bar>, f64)>,
|
||||||
derivative_data: Vec<Value>,
|
derivative_data: Vec<Value>,
|
||||||
extrema_data: Vec<Value>,
|
extrema_data: Vec<Value>,
|
||||||
root_data: Vec<Value>,
|
root_data: Vec<Value>,
|
||||||
|
nth_derivative_data: Option<Vec<Value>>,
|
||||||
|
|
||||||
autocomplete: AutoComplete<'static>,
|
autocomplete: AutoComplete<'static>,
|
||||||
|
|
||||||
test_result: Option<String>,
|
test_result: Option<String>,
|
||||||
|
curr_nth: usize,
|
||||||
|
|
||||||
|
pub settings_opened: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FunctionEntry {
|
impl Default for FunctionEntry {
|
||||||
@ -73,13 +80,17 @@ impl Default for FunctionEntry {
|
|||||||
max_x: 1.0,
|
max_x: 1.0,
|
||||||
integral: false,
|
integral: false,
|
||||||
derivative: false,
|
derivative: false,
|
||||||
|
nth_derviative: false,
|
||||||
back_data: Vec::new(),
|
back_data: Vec::new(),
|
||||||
integral_data: None,
|
integral_data: None,
|
||||||
derivative_data: Vec::new(),
|
derivative_data: Vec::new(),
|
||||||
extrema_data: Vec::new(),
|
extrema_data: Vec::new(),
|
||||||
root_data: Vec::new(),
|
root_data: Vec::new(),
|
||||||
|
nth_derivative_data: None,
|
||||||
autocomplete: AutoComplete::default(),
|
autocomplete: AutoComplete::default(),
|
||||||
test_result: None,
|
test_result: None,
|
||||||
|
curr_nth: 3,
|
||||||
|
settings_opened: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,6 +105,32 @@ impl FunctionEntry {
|
|||||||
self.update_string(&output_string);
|
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
|
/// Get function's cached test result
|
||||||
pub fn get_test_result(&self) -> &Option<String> { &self.test_result }
|
pub fn get_test_result(&self) -> &Option<String> { &self.test_result }
|
||||||
|
|
||||||
@ -263,6 +300,24 @@ impl FunctionEntry {
|
|||||||
} else {
|
} else {
|
||||||
self.invalidate_derivative();
|
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 {
|
} else {
|
||||||
self.invalidate_back();
|
self.invalidate_back();
|
||||||
self.invalidate_derivative();
|
self.invalidate_derivative();
|
||||||
@ -287,6 +342,14 @@ impl FunctionEntry {
|
|||||||
debug_assert_eq!(data.len(), settings.plot_width + 1);
|
debug_assert_eq!(data.len(), settings.plot_width + 1);
|
||||||
self.derivative_data = data;
|
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 {
|
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
|
// Plot integral data
|
||||||
match &self.integral_data {
|
match &self.integral_data {
|
||||||
Some(integral_data) => {
|
Some(integral_data) => {
|
||||||
@ -391,6 +463,7 @@ impl FunctionEntry {
|
|||||||
self.invalidate_back();
|
self.invalidate_back();
|
||||||
self.invalidate_integral();
|
self.invalidate_integral();
|
||||||
self.invalidate_derivative();
|
self.invalidate_derivative();
|
||||||
|
self.invalidate_nth();
|
||||||
self.extrema_data.clear();
|
self.extrema_data.clear();
|
||||||
self.root_data.clear();
|
self.root_data.clear();
|
||||||
}
|
}
|
||||||
@ -404,6 +477,8 @@ impl FunctionEntry {
|
|||||||
/// Invalidate Derivative data
|
/// Invalidate Derivative data
|
||||||
pub fn invalidate_derivative(&mut self) { self.derivative_data.clear(); }
|
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
|
/// Runs asserts to make sure everything is the expected value
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn tests(
|
pub fn tests(
|
||||||
|
|||||||
@ -464,9 +464,19 @@ impl MathApp {
|
|||||||
.clicked(),
|
.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
|
// Contains the function string in a text box that the user can edit
|
||||||
function.auto_complete(ui, i as i32)
|
function.auto_complete(ui, i as i32)
|
||||||
});
|
});
|
||||||
|
function.settings(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove function if the user requests it
|
// Remove function if the user requests it
|
||||||
|
|||||||
@ -16,6 +16,8 @@ pub struct BackingFunction {
|
|||||||
derivative_1_str: String,
|
derivative_1_str: String,
|
||||||
/// f''(x)
|
/// f''(x)
|
||||||
derivative_2: FlatEx<f64>,
|
derivative_2: FlatEx<f64>,
|
||||||
|
|
||||||
|
nth_derivative: Option<(usize, FlatEx<f64>, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackingFunction {
|
impl BackingFunction {
|
||||||
@ -66,6 +68,7 @@ impl BackingFunction {
|
|||||||
derivative_1,
|
derivative_1,
|
||||||
derivative_1_str,
|
derivative_1_str,
|
||||||
derivative_2,
|
derivative_2,
|
||||||
|
nth_derivative: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +87,34 @@ impl BackingFunction {
|
|||||||
pub fn get_derivative_2(&self, x: f64) -> f64 {
|
pub fn get_derivative_2(&self, x: f64) -> f64 {
|
||||||
self.derivative_2.eval(&[x]).unwrap_or(f64::NAN)
|
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', 'π'];
|
const VALID_VARIABLES: [char; 5] = ['x', 'X', 'e', 'E', 'π'];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user