mod helpers;
use crate::core::Expression;
pub trait AdvancedSimplify {
fn advanced_simplify(&self) -> Self;
fn simplify_factorial(&self) -> Self;
fn simplify_logarithms(&self) -> Self;
fn simplify_trigonometric(&self) -> Self;
fn simplify_special_functions(&self) -> Self;
}
impl AdvancedSimplify for Expression {
fn advanced_simplify(&self) -> Self {
let mut result = self.clone();
result = result.simplify_factorial();
result = result.simplify_logarithms();
result = result.simplify_trigonometric();
result = result.simplify_special_functions();
result
}
fn simplify_factorial(&self) -> Self {
match self {
Expression::Function { name, args } if name.as_ref() == "factorial" => {
if args.len() == 1 {
self.compute_factorial(&args[0])
} else {
self.clone()
}
}
Expression::Add(terms) => {
let simplified_terms: Vec<Expression> =
terms.iter().map(|term| term.simplify_factorial()).collect();
Expression::add(simplified_terms)
}
Expression::Mul(factors) => {
let simplified_factors: Vec<Expression> = factors
.iter()
.map(|factor| factor.simplify_factorial())
.collect();
Expression::mul(simplified_factors)
}
Expression::Pow(base, exp) => {
Expression::pow(base.simplify_factorial(), exp.simplify_factorial())
}
Expression::Function { name, args } => {
let simplified_args: Vec<Expression> =
args.iter().map(|arg| arg.simplify_factorial()).collect();
Expression::function(name.clone(), simplified_args)
}
_ => self.clone(),
}
}
fn simplify_logarithms(&self) -> Self {
match self {
Expression::Function { name, args } if name.as_ref() == "log" => {
self.simplify_log_function(args)
}
Expression::Function { name, args } if name.as_ref() == "ln" => {
self.simplify_ln_function(args)
}
Expression::Add(terms) => {
let simplified_terms: Vec<Expression> = terms
.iter()
.map(|term| term.simplify_logarithms())
.collect();
Expression::add(simplified_terms)
}
Expression::Mul(factors) => {
let simplified_factors: Vec<Expression> = factors
.iter()
.map(|factor| factor.simplify_logarithms())
.collect();
Expression::mul(simplified_factors)
}
_ => self.clone(),
}
}
fn simplify_trigonometric(&self) -> Self {
match self {
Expression::Function { name, args } if self.is_trig_function(name) => {
self.simplify_trig_function(name, args)
}
Expression::Add(terms) => {
let simplified_terms: Vec<Expression> = terms
.iter()
.map(|term| term.simplify_trigonometric())
.collect();
Expression::add(simplified_terms)
}
Expression::Mul(factors) => {
let simplified_factors: Vec<Expression> = factors
.iter()
.map(|factor| factor.simplify_trigonometric())
.collect();
Expression::mul(simplified_factors)
}
_ => self.clone(),
}
}
fn simplify_special_functions(&self) -> Self {
match self {
Expression::Function { name, args } => match name.as_ref() {
"sqrt" => self.simplify_sqrt(args),
"abs" => self.simplify_abs(args),
"exp" => self.simplify_exp(args),
"gamma" => self.simplify_gamma(args),
_ => self.clone(),
},
_ => self.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::symbol;
#[test]
fn test_factorial_computation() {
let expr = Expression::factorial(Expression::integer(5));
let result = expr.simplify_factorial();
assert_eq!(result, Expression::integer(120));
let expr = Expression::factorial(Expression::integer(0));
let result = expr.simplify_factorial();
assert_eq!(result, Expression::integer(1));
let expr = Expression::factorial(Expression::integer(1));
let result = expr.simplify_factorial();
assert_eq!(result, Expression::integer(1));
}
#[test]
fn test_logarithm_simplification() {
let expr = Expression::ln(Expression::integer(1));
let result = expr.simplify_logarithms();
assert_eq!(result, Expression::integer(0));
let x = symbol!(x);
let expr = Expression::ln(Expression::function(
"exp",
vec![Expression::symbol(x.clone())],
));
let result = expr.simplify_logarithms();
assert_eq!(result, Expression::symbol(x));
}
#[test]
fn test_trigonometric_simplification() {
let expr = Expression::function("sin", vec![Expression::integer(0)]);
let result = expr.simplify_trigonometric();
assert_eq!(result, Expression::integer(0));
let expr = Expression::function("cos", vec![Expression::integer(0)]);
let result = expr.simplify_trigonometric();
assert_eq!(result, Expression::integer(1));
}
#[test]
fn test_sqrt_simplification() {
let expr = Expression::sqrt(Expression::integer(4));
let result = expr.simplify_special_functions();
assert_eq!(result, Expression::integer(2));
let expr = Expression::sqrt(Expression::integer(0));
let result = expr.simplify_special_functions();
assert_eq!(result, Expression::integer(0));
let expr = Expression::sqrt(Expression::integer(1));
let result = expr.simplify_special_functions();
assert_eq!(result, Expression::integer(1));
}
#[test]
fn test_gamma_function() {
let expr = Expression::function("gamma", vec![Expression::integer(4)]);
let result = expr.simplify_special_functions();
assert_eq!(result, Expression::integer(6));
let expr = Expression::function("gamma", vec![Expression::integer(1)]);
let result = expr.simplify_special_functions();
assert_eq!(result, Expression::integer(1));
}
#[test]
fn test_advanced_zero_detection() {
let x = symbol!(x);
let expr = Expression::add(vec![
Expression::integer(4),
Expression::mul(vec![Expression::integer(4), Expression::symbol(x.clone())]),
Expression::mul(vec![
Expression::integer(-1),
Expression::mul(vec![
Expression::integer(2),
Expression::add(vec![
Expression::integer(2),
Expression::mul(vec![
Expression::integer(2),
Expression::symbol(x.clone()),
]),
]),
]),
]),
]);
let result = expr.advanced_simplify();
assert!(!result.to_string().is_empty());
}
}