refactor progress

This commit is contained in:
Simon Gardling
2023-12-04 10:02:16 -05:00
parent f86d0b62d5
commit 159bb1122b
4 changed files with 64 additions and 118 deletions

View File

@@ -1,21 +1,31 @@
use exmex::prelude::*;
use std::collections::HashMap;
#[derive(Clone, PartialEq)]
pub(crate) struct FlatExWrapper {
pub(crate) struct FlatExWrapper<'a> {
func: Option<FlatEx<f64>>,
func_str: Option<&'a str>,
}
impl FlatExWrapper {
const EMPTY: FlatExWrapper = FlatExWrapper { func: None };
impl<'a> FlatExWrapper<'a> {
const EMPTY: FlatExWrapper<'a> = FlatExWrapper {
func: None,
func_str: None,
};
#[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]
const fn is_none(&self) -> bool { self.func.is_none() }
#[inline]
fn eval(&self, x: &[f64]) -> f64 {
fn eval(&'a self, x: &[f64]) -> f64 {
self.func
.as_ref()
.map(|f| f.eval(x).unwrap_or(f64::NAN))
@@ -23,7 +33,7 @@ impl FlatExWrapper {
}
#[inline]
fn partial(&self, x: usize) -> Self {
fn partial(&'a self, x: usize) -> Self {
self.func
.as_ref()
.map(|f| f.clone().partial(x).map(Self::new).unwrap_or(Self::EMPTY))
@@ -31,10 +41,17 @@ impl FlatExWrapper {
}
#[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]
fn partial_iter(&self, n: usize) -> Self {
fn partial_iter(&'a self, n: usize) -> Self {
self.func
.as_ref()
.map(|f| {
@@ -47,45 +64,29 @@ impl FlatExWrapper {
}
}
impl const Default for FlatExWrapper {
fn default() -> FlatExWrapper { FlatExWrapper::EMPTY }
impl<'a> const Default for FlatExWrapper<'a> {
fn default() -> FlatExWrapper<'a> { FlatExWrapper::EMPTY }
}
/// Function that includes f(x), f'(x), f'(x)'s string representation, and f''(x)
#[derive(Clone, PartialEq)]
pub struct BackingFunction {
pub struct BackingFunction<'a> {
/// f(x)
function: FlatExWrapper,
/// f'(x)
derivative_1: FlatExWrapper,
/// Mathematical representation of f'(x)
derivative_1_str: String,
/// f''(x)
derivative_2: FlatExWrapper,
function: FlatExWrapper<'a>,
/// Temporary cache for nth derivative
nth_derivative: Option<(usize, FlatExWrapper, String)>,
nth_derivative: HashMap<usize, FlatExWrapper<'a>>,
}
impl BackingFunction {
/// 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,
};
impl<'a> BackingFunction<'a> {
pub const fn is_none(&self) -> bool { self.function.is_none() }
/// Create new [`BackingFunction`] instance
pub fn new(func_str: &str) -> Result<Self, String> {
if func_str.is_empty() {
return Ok(Self::EMPTY);
return Ok(Self {
function: FlatExWrapper::EMPTY,
nth_derivative: HashMap::new(),
});
}
let function = FlatExWrapper::new({
@@ -93,10 +94,8 @@ impl BackingFunction {
match &parse_result {
Err(e) => return Err(e.to_string()),
Ok(_) => {
let var_names = unsafe { parse_result.as_ref().unwrap_unchecked() }
.var_names()
.to_vec();
Ok(ok_result) => {
let var_names = ok_result.var_names().to_vec();
if var_names != ["x"] {
let var_names_not_x: Vec<&String> = var_names
@@ -117,61 +116,25 @@ impl BackingFunction {
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 {
function,
derivative_1,
derivative_1_str,
derivative_2,
nth_derivative: None,
nth_derivative: HashMap::new(),
})
}
/// Returns Mathematical representation of the function's derivative
pub fn get_derivative_str(&self) -> &str { &self.derivative_1_str }
pub fn get(&'a mut self, derivative: usize, x: f64) -> f64 {
match derivative {
0 => self.function.eval(&[x]),
/// Calculate f(x)
pub fn get(&self, x: f64) -> f64 { self.function.eval(&[x]) }
/// Calculate f'(x)
pub fn get_derivative_1(&self, x: f64) -> f64 { self.derivative_1.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]);
}
_ => match self.nth_derivative.get(&derivative) {
Some(func) => func.eval(&[x]),
None => {
let new_func = self.function.partial_iter(derivative);
self.nth_derivative.insert(derivative, new_func.clone());
new_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])
}
},
}
}
}

View File

@@ -15,6 +15,7 @@ pub fn split_function(input: &str, split: SplitType) -> Vec<String> {
.collect::<Vec<String>>()
}
// Specifies how to split a function
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum SplitType {
Multiplication,