refactor progress
This commit is contained in:
parent
f86d0b62d5
commit
159bb1122b
@ -17,7 +17,7 @@ fn main() {
|
|||||||
|
|
||||||
fn generate_hashmap() {
|
fn generate_hashmap() {
|
||||||
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
|
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
|
||||||
let mut file = BufWriter::new(File::create(&path).expect("Could not create file"));
|
let mut file = BufWriter::new(File::create(path).expect("Could not create file"));
|
||||||
|
|
||||||
let string_hashmap =
|
let string_hashmap =
|
||||||
compile_hashmap(SUPPORTED_FUNCTIONS.iter().map(|a| a.to_string()).collect());
|
compile_hashmap(SUPPORTED_FUNCTIONS.iter().map(|a| a.to_string()).collect());
|
||||||
|
|||||||
@ -1,21 +1,31 @@
|
|||||||
use exmex::prelude::*;
|
use exmex::prelude::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub(crate) struct FlatExWrapper {
|
pub(crate) struct FlatExWrapper<'a> {
|
||||||
func: Option<FlatEx<f64>>,
|
func: Option<FlatEx<f64>>,
|
||||||
|
func_str: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlatExWrapper {
|
impl<'a> FlatExWrapper<'a> {
|
||||||
const EMPTY: FlatExWrapper = FlatExWrapper { func: None };
|
const EMPTY: FlatExWrapper<'a> = FlatExWrapper {
|
||||||
|
func: None,
|
||||||
|
func_str: None,
|
||||||
|
};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn new(f: FlatEx<f64>) -> Self { Self { func: Some(f) } }
|
const fn new(f: FlatEx<f64>) -> Self {
|
||||||
|
Self {
|
||||||
|
func: Some(f),
|
||||||
|
func_str: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn is_none(&self) -> bool { self.func.is_none() }
|
const fn is_none(&self) -> bool { self.func.is_none() }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eval(&self, x: &[f64]) -> f64 {
|
fn eval(&'a self, x: &[f64]) -> f64 {
|
||||||
self.func
|
self.func
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|f| f.eval(x).unwrap_or(f64::NAN))
|
.map(|f| f.eval(x).unwrap_or(f64::NAN))
|
||||||
@ -23,7 +33,7 @@ impl FlatExWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial(&self, x: usize) -> Self {
|
fn partial(&'a self, x: usize) -> Self {
|
||||||
self.func
|
self.func
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|f| f.clone().partial(x).map(Self::new).unwrap_or(Self::EMPTY))
|
.map(|f| f.clone().partial(x).map(Self::new).unwrap_or(Self::EMPTY))
|
||||||
@ -31,10 +41,17 @@ impl FlatExWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_string(&self) -> &str { self.func.as_ref().map(|f| f.unparse()).unwrap_or("") }
|
fn get_string(&'a mut self) -> &'a str {
|
||||||
|
if let Some(func_str) = self.func_str {
|
||||||
|
return func_str;
|
||||||
|
}
|
||||||
|
let calculated = self.func.as_ref().map(|f| f.unparse()).unwrap_or("");
|
||||||
|
self.func_str = Some(calculated);
|
||||||
|
return calculated;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial_iter(&self, n: usize) -> Self {
|
fn partial_iter(&'a self, n: usize) -> Self {
|
||||||
self.func
|
self.func
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
@ -47,45 +64,29 @@ impl FlatExWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const Default for FlatExWrapper {
|
impl<'a> const Default for FlatExWrapper<'a> {
|
||||||
fn default() -> FlatExWrapper { FlatExWrapper::EMPTY }
|
fn default() -> FlatExWrapper<'a> { FlatExWrapper::EMPTY }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function that includes f(x), f'(x), f'(x)'s string representation, and f''(x)
|
/// Function that includes f(x), f'(x), f'(x)'s string representation, and f''(x)
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct BackingFunction {
|
pub struct BackingFunction<'a> {
|
||||||
/// f(x)
|
/// f(x)
|
||||||
function: FlatExWrapper,
|
function: FlatExWrapper<'a>,
|
||||||
|
|
||||||
/// f'(x)
|
|
||||||
derivative_1: FlatExWrapper,
|
|
||||||
|
|
||||||
/// Mathematical representation of f'(x)
|
|
||||||
derivative_1_str: String,
|
|
||||||
|
|
||||||
/// f''(x)
|
|
||||||
derivative_2: FlatExWrapper,
|
|
||||||
|
|
||||||
/// Temporary cache for nth derivative
|
/// Temporary cache for nth derivative
|
||||||
nth_derivative: Option<(usize, FlatExWrapper, String)>,
|
nth_derivative: HashMap<usize, FlatExWrapper<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackingFunction {
|
impl<'a> BackingFunction<'a> {
|
||||||
/// Empty [`BackingFunction`] instance
|
|
||||||
pub const EMPTY: BackingFunction = BackingFunction {
|
|
||||||
function: FlatExWrapper::EMPTY,
|
|
||||||
derivative_1: FlatExWrapper::EMPTY,
|
|
||||||
derivative_1_str: String::new(),
|
|
||||||
derivative_2: FlatExWrapper::EMPTY,
|
|
||||||
nth_derivative: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const fn is_none(&self) -> bool { self.function.is_none() }
|
pub const fn is_none(&self) -> bool { self.function.is_none() }
|
||||||
|
|
||||||
/// Create new [`BackingFunction`] instance
|
/// Create new [`BackingFunction`] instance
|
||||||
pub fn new(func_str: &str) -> Result<Self, String> {
|
pub fn new(func_str: &str) -> Result<Self, String> {
|
||||||
if func_str.is_empty() {
|
if func_str.is_empty() {
|
||||||
return Ok(Self::EMPTY);
|
return Ok(Self {
|
||||||
|
function: FlatExWrapper::EMPTY,
|
||||||
|
nth_derivative: HashMap::new(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let function = FlatExWrapper::new({
|
let function = FlatExWrapper::new({
|
||||||
@ -93,10 +94,8 @@ impl BackingFunction {
|
|||||||
|
|
||||||
match &parse_result {
|
match &parse_result {
|
||||||
Err(e) => return Err(e.to_string()),
|
Err(e) => return Err(e.to_string()),
|
||||||
Ok(_) => {
|
Ok(ok_result) => {
|
||||||
let var_names = unsafe { parse_result.as_ref().unwrap_unchecked() }
|
let var_names = ok_result.var_names().to_vec();
|
||||||
.var_names()
|
|
||||||
.to_vec();
|
|
||||||
|
|
||||||
if var_names != ["x"] {
|
if var_names != ["x"] {
|
||||||
let var_names_not_x: Vec<&String> = var_names
|
let var_names_not_x: Vec<&String> = var_names
|
||||||
@ -117,61 +116,25 @@ impl BackingFunction {
|
|||||||
unsafe { parse_result.unwrap_unchecked() }
|
unsafe { parse_result.unwrap_unchecked() }
|
||||||
});
|
});
|
||||||
|
|
||||||
let derivative_1 = function.partial(0);
|
|
||||||
|
|
||||||
let derivative_1_str = prettyify_function_str(derivative_1.get_string());
|
|
||||||
|
|
||||||
let derivative_2 = derivative_1.partial(0);
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
function,
|
function,
|
||||||
derivative_1,
|
|
||||||
derivative_1_str,
|
nth_derivative: HashMap::new(),
|
||||||
derivative_2,
|
|
||||||
nth_derivative: None,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns Mathematical representation of the function's derivative
|
pub fn get(&'a mut self, derivative: usize, x: f64) -> f64 {
|
||||||
pub fn get_derivative_str(&self) -> &str { &self.derivative_1_str }
|
match derivative {
|
||||||
|
0 => self.function.eval(&[x]),
|
||||||
|
|
||||||
/// Calculate f(x)
|
_ => match self.nth_derivative.get(&derivative) {
|
||||||
pub fn get(&self, x: f64) -> f64 { self.function.eval(&[x]) }
|
Some(func) => func.eval(&[x]),
|
||||||
|
None => {
|
||||||
/// Calculate f'(x)
|
let new_func = self.function.partial_iter(derivative);
|
||||||
pub fn get_derivative_1(&self, x: f64) -> f64 { self.derivative_1.eval(&[x]) }
|
self.nth_derivative.insert(derivative, new_func.clone());
|
||||||
|
new_func.eval(&[x])
|
||||||
/// Calculate f''(x)
|
|
||||||
pub fn get_derivative_2(&self, x: f64) -> f64 { self.derivative_2.eval(&[x]) }
|
|
||||||
|
|
||||||
/// Get string relating to the nth derivative
|
|
||||||
pub fn get_nth_derivative_str(&self) -> &str {
|
|
||||||
self.nth_derivative
|
|
||||||
.as_ref()
|
|
||||||
.map(|a| a.2.as_str())
|
|
||||||
.unwrap_or("")
|
|
||||||
}
|
|
||||||
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let new_func = self.function.partial_iter(n);
|
},
|
||||||
|
|
||||||
self.nth_derivative = Some((
|
|
||||||
n,
|
|
||||||
new_func.clone(),
|
|
||||||
prettyify_function_str(new_func.get_string()),
|
|
||||||
));
|
|
||||||
new_func.eval(&[x])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ pub fn split_function(input: &str, split: SplitType) -> Vec<String> {
|
|||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specifies how to split a function
|
||||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||||
pub enum SplitType {
|
pub enum SplitType {
|
||||||
Multiplication,
|
Multiplication,
|
||||||
|
|||||||
@ -31,7 +31,7 @@ impl fmt::Display for Riemann {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FunctionEntry {
|
pub struct FunctionEntry {
|
||||||
/// The `BackingFunction` instance that is used to generate `f(x)`, `f'(x)`, and `f''(x)`
|
/// The `BackingFunction` instance that is used to generate `f(x)`, `f'(x)`, and `f''(x)`
|
||||||
function: BackingFunction,
|
function: BackingFunction<'static>,
|
||||||
|
|
||||||
/// Stores a function string (that hasn't been processed via `process_func_str`) to display to the user
|
/// Stores a function string (that hasn't been processed via `process_func_str`) to display to the user
|
||||||
pub raw_func_str: String,
|
pub raw_func_str: String,
|
||||||
@ -121,28 +121,10 @@ impl<'de> Deserialize<'de> for FunctionEntry {
|
|||||||
|
|
||||||
impl const Default for FunctionEntry {
|
impl const Default for FunctionEntry {
|
||||||
/// Creates default FunctionEntry instance (which is empty)
|
/// Creates default FunctionEntry instance (which is empty)
|
||||||
fn default() -> FunctionEntry { FunctionEntry::EMPTY }
|
fn default() -> FunctionEntry {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionEntry {
|
impl FunctionEntry {
|
||||||
pub const EMPTY: FunctionEntry = FunctionEntry {
|
|
||||||
function: BackingFunction::EMPTY,
|
|
||||||
raw_func_str: String::new(),
|
|
||||||
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::EMPTY,
|
|
||||||
test_result: None,
|
|
||||||
curr_nth: 3,
|
|
||||||
settings_opened: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const fn is_some(&self) -> bool { !self.function.is_none() }
|
pub const fn is_some(&self) -> bool { !self.function.is_none() }
|
||||||
|
|
||||||
pub fn settings_window(&mut self, ctx: &Context) {
|
pub fn settings_window(&mut self, ctx: &Context) {
|
||||||
@ -216,10 +198,10 @@ impl FunctionEntry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let y = match sum {
|
let y = match sum {
|
||||||
Riemann::Left => self.function.get(left_x),
|
Riemann::Left => self.function.get(0, left_x),
|
||||||
Riemann::Right => self.function.get(right_x),
|
Riemann::Right => self.function.get(0, right_x),
|
||||||
Riemann::Middle => {
|
Riemann::Middle => {
|
||||||
(self.function.get(left_x) + self.function.get(right_x)) / 2.0
|
(self.function.get(0, left_x) + self.function.get(0, right_x)) / 2.0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -242,22 +224,22 @@ impl FunctionEntry {
|
|||||||
threshold,
|
threshold,
|
||||||
range,
|
range,
|
||||||
self.back_data.as_slice(),
|
self.back_data.as_slice(),
|
||||||
&|x: f64| self.function.get(x),
|
&|x: f64| self.function.get(0, x),
|
||||||
&|x: f64| self.function.get_derivative_1(x),
|
&|x: f64| self.function.get(1, x),
|
||||||
),
|
),
|
||||||
1 => newtons_method_helper(
|
1 => newtons_method_helper(
|
||||||
threshold,
|
threshold,
|
||||||
range,
|
range,
|
||||||
self.derivative_data.as_slice(),
|
self.derivative_data.as_slice(),
|
||||||
&|x: f64| self.function.get_derivative_1(x),
|
&|x: f64| self.function.get(1, x),
|
||||||
&|x: f64| self.function.get_derivative_2(x),
|
&|x: f64| self.function.get(2, x),
|
||||||
),
|
),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
newtons_method_output
|
newtons_method_output
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| PlotPoint::new(x, self.function.get(x)))
|
.map(|x| PlotPoint::new(x, self.function.get(0, x)))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +273,7 @@ impl FunctionEntry {
|
|||||||
let data: Vec<PlotPoint> = resolution_iter
|
let data: Vec<PlotPoint> = resolution_iter
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| PlotPoint::new(x, self.function.get(x)))
|
.map(|x| PlotPoint::new(x, self.function.get(0, x)))
|
||||||
.collect();
|
.collect();
|
||||||
debug_assert_eq!(data.len(), settings.plot_width + 1);
|
debug_assert_eq!(data.len(), settings.plot_width + 1);
|
||||||
|
|
||||||
@ -302,7 +284,7 @@ impl FunctionEntry {
|
|||||||
let data: Vec<PlotPoint> = resolution_iter
|
let data: Vec<PlotPoint> = resolution_iter
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| PlotPoint::new(x, self.function.get_derivative_1(x)))
|
.map(|x| PlotPoint::new(x, self.function.get(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 = data;
|
self.derivative_data = data;
|
||||||
@ -311,7 +293,7 @@ impl FunctionEntry {
|
|||||||
if self.nth_derviative && self.nth_derivative_data.is_none() {
|
if self.nth_derviative && self.nth_derivative_data.is_none() {
|
||||||
let data: Vec<PlotPoint> = resolution_iter
|
let data: Vec<PlotPoint> = resolution_iter
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| PlotPoint::new(x, self.function.get_nth_derivative(self.curr_nth, x)))
|
.map(|x| PlotPoint::new(x, self.function.get(self.curr_nth, x)))
|
||||||
.collect();
|
.collect();
|
||||||
debug_assert_eq!(data.len(), settings.plot_width + 1);
|
debug_assert_eq!(data.len(), settings.plot_width + 1);
|
||||||
self.nth_derivative_data = Some(data);
|
self.nth_derivative_data = Some(data);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user