use crate::core::{Expression, Number, Symbol};
use crate::expr;
use num_bigint::BigInt;
use num_traits::{One, Zero};
impl Expression {
pub(super) fn extract_coefficient_and_power(
&self,
term: &Expression,
var: &Symbol,
) -> (BigInt, Expression) {
match term {
Expression::Number(Number::Integer(n)) => (BigInt::from(*n), Expression::integer(0)),
Expression::Symbol(s) if s == var => (BigInt::one(), Expression::integer(1)),
Expression::Symbol(_) => (BigInt::zero(), Expression::integer(0)),
Expression::Pow(base, exp) => {
if let Expression::Symbol(s) = base.as_ref() {
if s == var {
return (BigInt::one(), exp.as_ref().clone());
}
}
(BigInt::zero(), Expression::integer(0))
}
Expression::Mul(factors) => {
let mut coefficient = BigInt::one();
let mut power = expr!(0);
let mut has_var = false;
for factor in factors.iter() {
match factor {
Expression::Number(Number::Integer(n)) => {
coefficient *= BigInt::from(*n);
}
Expression::Symbol(s) if s == var => {
power = expr!(1);
has_var = true;
}
Expression::Pow(base, exp) => {
if let Expression::Symbol(s) = base.as_ref() {
if s == var {
power = exp.as_ref().clone();
has_var = true;
}
}
}
_ => {}
}
}
if has_var {
(coefficient, power)
} else {
(BigInt::zero(), expr!(0))
}
}
_ => (BigInt::zero(), expr!(0)),
}
}
pub(super) fn extract_coefficient_and_base(&self, expr: &Expression) -> (BigInt, Expression) {
match expr {
Expression::Number(Number::Integer(n)) => (BigInt::from(*n), expr!(1)),
Expression::Symbol(_) => (BigInt::one(), expr.clone()),
Expression::Mul(factors) => {
let mut coefficient = BigInt::one();
let mut non_numeric_factors = Vec::new();
for factor in factors.iter() {
if let Expression::Number(Number::Integer(n)) = factor {
coefficient *= BigInt::from(*n);
} else {
non_numeric_factors.push(factor.clone());
}
}
let base = if non_numeric_factors.is_empty() {
expr!(1)
} else if non_numeric_factors.len() == 1 {
non_numeric_factors[0].clone()
} else {
Expression::mul(non_numeric_factors)
};
(coefficient, base)
}
_ => (BigInt::one(), expr.clone()),
}
}
pub fn is_constant(&self) -> bool {
match self {
Expression::Number(_) => true,
Expression::Symbol(_) => false,
Expression::Add(terms) | Expression::Mul(terms) => {
terms.iter().all(|t| t.is_constant())
}
Expression::Pow(base, exp) => base.is_constant() && exp.is_constant(),
Expression::Function { args, .. } => args.iter().all(|a| a.is_constant()),
Expression::Complex(_) => true,
Expression::Matrix(_) => false,
Expression::Constant(_) => true,
Expression::Relation(_) => false,
Expression::Piecewise(_) => false,
Expression::Set(_) => false,
Expression::Interval(_) => true,
Expression::Calculus(_) => false,
Expression::MethodCall(method_data) => {
method_data.object.is_constant() && method_data.args.iter().all(|a| a.is_constant())
}
}
}
pub(super) fn same_factor_order(&self, expr1: &Expression, expr2: &Expression) -> bool {
match (expr1, expr2) {
(Expression::Mul(factors1), Expression::Mul(factors2)) => {
if factors1.len() != factors2.len() {
return false;
}
factors1
.iter()
.zip(factors2.iter())
.all(|(f1, f2)| f1 == f2)
}
_ => expr1 == expr2,
}
}
}