very very jank
This commit is contained in:
parent
7a109d5638
commit
e170dee22a
@ -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])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user