very very jank

This commit is contained in:
Simon Gardling 2022-05-05 01:44:26 -04:00
parent 7a109d5638
commit e170dee22a

View File

@ -1,69 +1,122 @@
use exmex::prelude::*; use exmex::prelude::*;
lazy_static::lazy_static! { #[derive(Clone)]
/// Function returns `f64::NaN` at every x value, which is not displayed. pub struct FlatExWrapper {
static ref EMPTY_FUNCTION: FlatEx<f64> = exmex::parse::<f64>("0/0").unwrap(); func: Option<FlatEx<f64>>,
} }
/// Function that includes f(x), f'(x), f'(x)'s string representation, and
/// f''(x) impl FlatExWrapper {
const EMPTY: FlatExWrapper = FlatExWrapper { func: None };
fn new(f: FlatEx<f64>) -> Self { Self { func: Some(f) } }
fn eval(&self, x: &[f64]) -> f64 {
if let Some(ref f) = self.func {
f.eval(x).unwrap_or(f64::NAN)
} else {
f64::NAN
}
}
fn partial(&self, x: usize) -> Self {
if let Some(ref f) = self.func {
match f.partial(x) {
Ok(a) => Self::new(a),
Err(_) => Self::EMPTY,
}
} else {
Self::EMPTY
}
}
fn get_string(&self) -> &str {
if let Some(ref f) = self.func {
f.unparse()
} else {
""
}
}
fn partial_iter(&self, x: &[usize]) -> Self {
if let Some(ref f) = self.func {
match f.partial_iter(x.iter()) {
Ok(a) => Self::new(a),
Err(_) => Self::EMPTY,
}
} else {
Self::EMPTY
}
}
}
impl const Default for FlatExWrapper {
fn default() -> FlatExWrapper { FlatExWrapper::EMPTY }
}
/// Function that includes f(x), f'(x), f'(x)'s string representation, and f''(x)
#[derive(Clone)] #[derive(Clone)]
pub struct BackingFunction { pub struct BackingFunction {
/// f(x) /// f(x)
function: FlatEx<f64>, function: FlatExWrapper,
/// f'(x) /// f'(x)
derivative_1: FlatEx<f64>, derivative_1: FlatExWrapper,
/// Mathematical representation of f'(x) /// Mathematical representation of f'(x)
derivative_1_str: String, derivative_1_str: String,
/// f''(x) /// f''(x)
derivative_2: FlatEx<f64>, derivative_2: FlatExWrapper,
nth_derivative: Option<(usize, FlatEx<f64>, String)>, nth_derivative: Option<(usize, FlatExWrapper, String)>,
} }
impl BackingFunction { impl BackingFunction {
const EMPTY: BackingFunction = BackingFunction {
function: FlatExWrapper::EMPTY,
derivative_1: FlatExWrapper::EMPTY,
derivative_1_str: String::new(),
derivative_2: FlatExWrapper::EMPTY,
nth_derivative: 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> {
let function = match func_str { if func_str.is_empty() {
"" => EMPTY_FUNCTION.clone(), return Ok(Self::EMPTY);
_ => { }
let parse_result = exmex::parse::<f64>(func_str);
match &parse_result { let function = FlatExWrapper::new({
Err(e) => return Err(e.to_string()), let parse_result = exmex::parse::<f64>(func_str);
Ok(_) => {
let var_names = unsafe { parse_result.as_ref().unwrap_unchecked() }
.var_names()
.to_vec();
if var_names != ["x"] { match &parse_result {
let var_names_not_x: Vec<&String> = var_names Err(e) => return Err(e.to_string()),
.iter() Ok(_) => {
.filter(|ele| ele != &"x") let var_names = unsafe { parse_result.as_ref().unwrap_unchecked() }
.collect::<Vec<&String>>(); .var_names()
.to_vec();
return Err(format!( if var_names != ["x"] {
"Error: invalid variable{}", let var_names_not_x: Vec<&String> = var_names
match var_names_not_x.len() { .iter()
1 => String::from(": ") + var_names_not_x[0].as_str(), .filter(|ele| ele != &"x")
_ => format!("s: {:?}", var_names_not_x), .collect::<Vec<&String>>();
}
)); return Err(format!(
} "Error: invalid variable{}",
match var_names_not_x.len() {
1 => String::from(": ") + var_names_not_x[0].as_str(),
_ => format!("s: {:?}", var_names_not_x),
}
));
} }
} }
unsafe { parse_result.unwrap_unchecked() }
} }
}; unsafe { parse_result.unwrap_unchecked() }
});
let derivative_1 = function let derivative_1 = function.partial(0);
.partial(0)
.unwrap_or_else(|_| EMPTY_FUNCTION.clone());
let derivative_1_str = prettyify_function_str(derivative_1.unparse()); let derivative_1_str = prettyify_function_str(derivative_1.get_string());
let derivative_2 = function let derivative_2 = derivative_1.partial(0);
.partial_iter([0, 0].iter())
.unwrap_or_else(|_| EMPTY_FUNCTION.clone());
Ok(Self { Ok(Self {
function, function,
@ -78,17 +131,13 @@ impl BackingFunction {
pub fn get_derivative_str(&self) -> &str { &self.derivative_1_str } pub fn get_derivative_str(&self) -> &str { &self.derivative_1_str }
/// Calculate f(x) /// Calculate f(x)
pub fn get(&self, x: f64) -> f64 { self.function.eval(&[x]).unwrap_or(f64::NAN) } pub fn get(&self, x: f64) -> f64 { self.function.eval(&[x]) }
/// Calculate f'(x) /// Calculate f'(x)
pub fn get_derivative_1(&self, x: f64) -> f64 { pub fn get_derivative_1(&self, x: f64) -> f64 { self.derivative_1.eval(&[x]) }
self.derivative_1.eval(&[x]).unwrap_or(f64::NAN)
}
/// Calculate f''(x) /// Calculate f''(x)
pub fn get_derivative_2(&self, x: f64) -> f64 { pub fn get_derivative_2(&self, x: f64) -> f64 { self.derivative_2.eval(&[x]) }
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_str(&self) -> &str { &self.nth_derivative.as_ref().unwrap().2 }
@ -100,20 +149,19 @@ impl BackingFunction {
_ => { _ => {
if let Some((curr_n, curr_n_func, _)) = &self.nth_derivative { if let Some((curr_n, curr_n_func, _)) = &self.nth_derivative {
if curr_n == &n { if curr_n == &n {
return curr_n_func.eval(&[x]).unwrap_or(f64::NAN); return curr_n_func.eval(&[x]);
} }
} }
let new_func = self let new_func = self
.function .function
.partial_iter((1..=n).map(|_| 0).collect::<Vec<usize>>().iter()) .partial_iter((1..=n).map(|_| 0).collect::<Vec<usize>>().as_slice());
.unwrap_or_else(|_| EMPTY_FUNCTION.clone());
self.nth_derivative = Some(( self.nth_derivative = Some((
n, n,
new_func.clone(), new_func.clone(),
prettyify_function_str(new_func.unparse()), prettyify_function_str(new_func.get_string()),
)); ));
new_func.eval(&[x]).unwrap_or(f64::NAN) new_func.eval(&[x])
} }
} }
} }