use crate::core::Expression;
pub fn extract_denominator(expr: &Expression) -> Option<Expression> {
match expr {
Expression::Mul(factors) => {
let mut denominator_factors = Vec::new();
for factor in factors.iter() {
if let Expression::Pow(base, exp) = factor {
if let Expression::Number(crate::core::Number::Integer(exp_val)) = exp.as_ref()
{
if *exp_val < 0 {
let positive_exp = Expression::integer(-exp_val);
denominator_factors
.push(Expression::pow(base.as_ref().clone(), positive_exp));
}
}
}
}
if !denominator_factors.is_empty() {
Some(Expression::mul(denominator_factors))
} else {
None
}
}
Expression::Pow(base, exp) => {
if let Expression::Number(crate::core::Number::Integer(exp_val)) = exp.as_ref() {
if *exp_val < 0 {
let positive_exp = Expression::integer(-exp_val);
return Some(Expression::pow(base.as_ref().clone(), positive_exp));
}
}
None
}
_ => None,
}
}
pub fn is_expression_zero(expr: &Expression) -> bool {
match expr {
Expression::Number(n) => n.is_zero(),
Expression::Mul(factors) => factors.iter().any(is_expression_zero),
Expression::Add(terms) => terms.iter().all(is_expression_zero),
_ => false,
}
}
pub fn is_infinity(expr: &Expression) -> bool {
match expr {
Expression::Function { name, .. }
if name.as_ref() == "infinity" || name.as_ref() == "oo" =>
{
true
}
Expression::Mul(factors) if factors.len() == 2 => {
matches!(&factors[0], Expression::Number(n) if *n == crate::core::Number::Integer(-1))
&& is_infinity(&factors[1])
}
_ => false,
}
}
pub fn is_undefined(expr: &Expression) -> bool {
matches!(expr, Expression::Function { name, .. } if name.as_ref() == "undefined" || name.as_ref() == "nan")
}
pub fn is_finite(expr: &Expression) -> bool {
!is_infinity(expr) && !is_undefined(expr)
}