mathhook_core/algebra/collect/
coefficients.rs1use crate::core::{Expression, Number, Symbol};
4use crate::expr;
5use num_bigint::BigInt;
6use num_traits::{One, Zero};
7
8impl Expression {
9 pub(super) fn extract_coefficient_and_power(
11 &self,
12 term: &Expression,
13 var: &Symbol,
14 ) -> (BigInt, Expression) {
15 match term {
16 Expression::Number(Number::Integer(n)) => (BigInt::from(*n), Expression::integer(0)),
17
18 Expression::Symbol(s) if s == var => (BigInt::one(), Expression::integer(1)),
19
20 Expression::Symbol(_) => (BigInt::zero(), Expression::integer(0)),
21
22 Expression::Pow(base, exp) => {
23 if let Expression::Symbol(s) = base.as_ref() {
24 if s == var {
25 return (BigInt::one(), exp.as_ref().clone());
26 }
27 }
28 (BigInt::zero(), Expression::integer(0))
29 }
30
31 Expression::Mul(factors) => {
32 let mut coefficient = BigInt::one();
33 let mut power = expr!(0);
34 let mut has_var = false;
35
36 for factor in factors.iter() {
37 match factor {
38 Expression::Number(Number::Integer(n)) => {
39 coefficient *= BigInt::from(*n);
40 }
41 Expression::Symbol(s) if s == var => {
42 power = expr!(1);
43 has_var = true;
44 }
45 Expression::Pow(base, exp) => {
46 if let Expression::Symbol(s) = base.as_ref() {
47 if s == var {
48 power = exp.as_ref().clone();
49 has_var = true;
50 }
51 }
52 }
53 _ => {}
54 }
55 }
56
57 if has_var {
58 (coefficient, power)
59 } else {
60 (BigInt::zero(), expr!(0))
61 }
62 }
63
64 _ => (BigInt::zero(), expr!(0)),
65 }
66 }
67
68 pub(super) fn extract_coefficient_and_base(&self, expr: &Expression) -> (BigInt, Expression) {
70 match expr {
71 Expression::Number(Number::Integer(n)) => (BigInt::from(*n), expr!(1)),
72
73 Expression::Symbol(_) => (BigInt::one(), expr.clone()),
74
75 Expression::Mul(factors) => {
76 let mut coefficient = BigInt::one();
77 let mut non_numeric_factors = Vec::new();
78
79 for factor in factors.iter() {
80 if let Expression::Number(Number::Integer(n)) = factor {
81 coefficient *= BigInt::from(*n);
82 } else {
83 non_numeric_factors.push(factor.clone());
84 }
85 }
86
87 let base = if non_numeric_factors.is_empty() {
88 expr!(1)
89 } else if non_numeric_factors.len() == 1 {
90 non_numeric_factors[0].clone()
91 } else {
92 Expression::mul(non_numeric_factors)
93 };
94
95 (coefficient, base)
96 }
97
98 _ => (BigInt::one(), expr.clone()),
99 }
100 }
101
102 pub fn is_constant(&self) -> bool {
104 match self {
105 Expression::Number(_) => true,
106 Expression::Symbol(_) => false,
107 Expression::Add(terms) | Expression::Mul(terms) => {
108 terms.iter().all(|t| t.is_constant())
109 }
110 Expression::Pow(base, exp) => base.is_constant() && exp.is_constant(),
111 Expression::Function { args, .. } => args.iter().all(|a| a.is_constant()),
112 Expression::Complex(_) => true,
113 Expression::Matrix(_) => false,
114 Expression::Constant(_) => true,
115 Expression::Relation(_) => false,
116 Expression::Piecewise(_) => false,
117 Expression::Set(_) => false,
118 Expression::Interval(_) => true,
119 Expression::Calculus(_) => false,
120 Expression::MethodCall(method_data) => {
121 method_data.object.is_constant() && method_data.args.iter().all(|a| a.is_constant())
122 }
123 }
124 }
125 pub(super) fn same_factor_order(&self, expr1: &Expression, expr2: &Expression) -> bool {
129 match (expr1, expr2) {
130 (Expression::Mul(factors1), Expression::Mul(factors2)) => {
131 if factors1.len() != factors2.len() {
132 return false;
133 }
134 factors1
135 .iter()
136 .zip(factors2.iter())
137 .all(|(f1, f2)| f1 == f2)
138 }
139 _ => expr1 == expr2,
140 }
141 }
142}