use std::sync::Arc;
use crate::core::{Expression, Number};
use crate::matrices::operations::MatrixOperations;
use num_traits::ToPrimitive;
pub mod arithmetic;
mod constants;
mod functions;
pub trait Simplify {
fn simplify(&self) -> Self;
}
impl Simplify for Expression {
#[inline(always)]
fn simplify(&self) -> Self {
match self {
Expression::Number(num) => Self::normalize_number(num),
Expression::Symbol(_) => self.clone(),
Expression::Add(terms) => arithmetic::simplify_addition(terms),
Expression::Mul(factors) => arithmetic::simplify_multiplication(factors),
Expression::Pow(base, exp) => arithmetic::simplify_power(base, exp),
Expression::Function { name, args } => functions::simplify_function(name, args),
Expression::Constant(constant) => constants::simplify_constant(constant),
Expression::Complex(_) => Expression::simplify_complex(self),
Expression::Matrix(_) => self.simplify_matrix(),
Expression::Relation(relation) => {
let simplified_left = relation.left.simplify();
let simplified_right = relation.right.simplify();
Expression::relation(simplified_left, simplified_right, relation.relation_type)
}
Expression::Piecewise(piecewise) => {
let simplified_pieces: Vec<_> = piecewise
.pieces
.iter()
.map(|piece| (piece.0.simplify(), piece.1.simplify()))
.collect();
let simplified_default = piecewise.default.as_ref().map(|expr| expr.simplify());
Expression::piecewise(simplified_pieces, simplified_default)
}
Expression::Set(set_elements) => {
let simplified_elements: Vec<_> =
set_elements.iter().map(|elem| elem.simplify()).collect();
Expression::set(simplified_elements)
}
Expression::Interval(interval) => {
let simplified_start = interval.start.simplify();
let simplified_end = interval.end.simplify();
Expression::interval(
simplified_start,
simplified_end,
interval.start_inclusive,
interval.end_inclusive,
)
}
Expression::Calculus(calc_op) => {
use crate::core::expression::data_types::CalculusData;
match calc_op.as_ref() {
CalculusData::Derivative {
expression,
variable,
order,
} => {
let simplified_expr = expression.simplify();
Expression::Calculus(Arc::new(CalculusData::Derivative {
expression: simplified_expr,
variable: variable.clone(),
order: *order,
}))
}
CalculusData::Integral {
integrand,
variable,
bounds,
} => {
let simplified_integrand = integrand.simplify();
let simplified_bounds = bounds
.as_ref()
.map(|(start, end)| (start.simplify(), end.simplify()));
Expression::Calculus(Arc::new(CalculusData::Integral {
integrand: simplified_integrand,
variable: variable.clone(),
bounds: simplified_bounds,
}))
}
CalculusData::Limit {
expression,
variable,
point,
direction,
} => {
let simplified_expr = expression.simplify();
let simplified_point = point.simplify();
Expression::Calculus(Arc::new(CalculusData::Limit {
expression: simplified_expr,
variable: variable.clone(),
point: simplified_point,
direction: *direction,
}))
}
CalculusData::Sum {
expression,
variable,
start,
end,
} => {
let simplified_expr = expression.simplify();
let simplified_start = start.simplify();
let simplified_end = end.simplify();
Expression::Calculus(Arc::new(CalculusData::Sum {
expression: simplified_expr,
variable: variable.clone(),
start: simplified_start,
end: simplified_end,
}))
}
CalculusData::Product {
expression,
variable,
start,
end,
} => {
let simplified_expr = expression.simplify();
let simplified_start = start.simplify();
let simplified_end = end.simplify();
Expression::Calculus(Arc::new(CalculusData::Product {
expression: simplified_expr,
variable: variable.clone(),
start: simplified_start,
end: simplified_end,
}))
}
}
}
Expression::MethodCall(method_data) => {
let simplified_object = method_data.object.simplify();
let simplified_args: Vec<Expression> =
method_data.args.iter().map(|arg| arg.simplify()).collect();
let method_call = Expression::method_call(
simplified_object,
&method_data.method_name,
simplified_args,
);
method_call.evaluate_method_call()
}
}
}
}
impl Expression {
fn normalize_number(num: &Number) -> Self {
match num {
Number::BigInteger(bi) => {
if let Some(i) = bi.to_i64() {
Expression::Number(Number::Integer(i))
} else {
Expression::Number(num.clone())
}
}
_ => Expression::Number(num.clone()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{expr, function};
#[test]
fn test_basic_simplification() {
let expr = expr!(2 + 3);
assert_eq!(expr.simplify(), expr!(5));
let expr = expr!(2 * 3);
assert_eq!(expr.simplify(), expr!(6));
let expr = expr!(x ^ 1);
assert_eq!(expr.simplify(), expr!(x));
}
#[test]
fn test_function_simplification() {
let expr = function!(sin, expr!(0));
assert_eq!(expr.simplify(), expr!(0));
let expr = function!(cos, expr!(0));
assert_eq!(expr.simplify(), expr!(1));
}
#[test]
fn test_zero_detection() {
let expr = expr!(0 * 5);
let result = expr.simplify();
assert_eq!(result, expr!(0));
}
}