use crate::ast::operator::DerivativeNotation;
use crate::ast::{
operator::{Derivative, Operator},
Ci, MathExpression,
MathExpression::{Mfrac, Mn, Mo, Mover, Mrow, Msub},
Mi, Type,
};
use crate::petri_net::{Polarity, Var};
pub fn recognize_leibniz_differential_operator<'a>(
numerator: &MathExpression,
denominator: &MathExpression,
) -> Result<(Operator, MathExpression), &'a str> {
let mut numerator_contains_d = false;
let mut denominator_contains_d = false;
let mut numerator_contains_partial = false;
let mut denominator_contains_partial = false;
let mut function_candidate: Option<MathExpression> = None;
if let MathExpression::Mrow(num_expressions) = numerator {
if let MathExpression::Mi(Mi(num_id)) = &num_expressions.0[0] {
if num_id == "d" {
numerator_contains_d = true;
}
if num_id == "∂" {
numerator_contains_partial = true;
}
function_candidate = Some(num_expressions.0[1].clone());
}
}
let mut denom_var = String::new();
if let MathExpression::Mrow(denom_expressions) = denominator {
if let MathExpression::Mi(Mi(denom_id)) = &denom_expressions.0[0] {
if denom_id == "d" {
denominator_contains_d = true;
}
if denom_id == "∂" {
denominator_contains_partial = true;
}
}
if let MathExpression::Mi(Mi(with_respect_to)) = &denom_expressions.0[1] {
denom_var.push_str(with_respect_to);
}
}
if numerator_contains_d && denominator_contains_d {
Ok((
Operator::new_derivative(Derivative::new(
1,
1,
Ci::new(
Some(Type::Real),
Box::new(MathExpression::Mi(Mi(denom_var.trim().to_string()))),
None,
None,
),
DerivativeNotation::LeibnizTotal,
)),
function_candidate.unwrap(),
))
} else if numerator_contains_partial && denominator_contains_partial {
Ok((
Operator::new_derivative(Derivative::new(
1,
1,
Ci::new(
Some(Type::Real),
Box::new(MathExpression::Mi(Mi(denom_var.trim().to_string()))),
None,
None,
),
DerivativeNotation::LeibnizPartialStandard,
)),
function_candidate.unwrap(),
))
} else {
Err("This Mfrac does not correspond to a derivative in Leibniz notation")
}
}
pub fn is_add_or_subtract_operator(element: &MathExpression) -> bool {
if let MathExpression::Mo(operator) = element {
return Operator::Add == *operator || Operator::Subtract == *operator;
}
false
}
pub fn get_polarity(element: &MathExpression) -> Polarity {
if let MathExpression::Mo(op) = element {
if *op == Operator::Subtract {
Polarity::Negative
} else if *op == Operator::Add {
Polarity::Positive
} else {
panic!("Unhandled operator!");
}
} else {
panic!("Element must be of type Mo!");
}
}
pub fn get_specie_var(expression: &MathExpression) -> Var {
match expression {
Mfrac(numerator, denominator) => {
if recognize_leibniz_differential_operator(numerator, denominator).is_ok() {
mfrac_leibniz_to_specie(numerator, denominator)
} else {
panic!("Expression is an mfrac but not a Leibniz differential operator!");
}
}
Mover(base, overscript) => {
if let Mo(id) = &**overscript {
if *id == Operator::Other("˙".to_string()) {
Var(*base.clone())
} else {
panic!("Overscript is not ˙, unhandled case!")
}
} else {
panic!("Found an overscript that is not an Mo, aborting!");
}
}
_ => panic!("Unhandled case!"),
}
}
pub fn is_var_candidate(element: &MathExpression) -> bool {
matches!(element, MathExpression::Mi(_) | Mn(_) | Msub(_, _))
}
fn mfrac_leibniz_to_specie(numerator: &MathExpression, _denominator: &MathExpression) -> Var {
if let Mrow(num_expressions) = numerator {
if num_expressions.0.len() == 2 {
let expression = &num_expressions.0[1];
Var(expression.clone())
} else {
panic!(
"More than two elements in the numerator, cannot extract specie from Leibniz differential operator!");
}
} else {
panic!("Unable to extract specie from Leibniz differential operator!");
}
}