use crate::symbolic::symbolic_engine::Expr;
use std::collections::BTreeMap;
impl Expr {
#[allow(dead_code)]
fn nozeros(&self) -> Expr {
match self {
Expr::Var(_) => self.clone(),
Expr::Const(_) => self.clone(),
Expr::Add(lhs, rhs) => {
let simplified_lhs = lhs.nozeros();
let simplified_rhs = rhs.nozeros();
if simplified_lhs == Expr::Const(0.0) && simplified_rhs == Expr::Const(0.0) {
Expr::Const(0.0)
} else {
Expr::Add(Box::new(simplified_lhs), Box::new(simplified_rhs))
}
}
Expr::Sub(lhs, rhs) => {
let simplified_lhs = lhs.nozeros();
let simplified_rhs = rhs.nozeros();
if simplified_lhs == Expr::Const(0.0) && simplified_rhs == Expr::Const(0.0) {
Expr::Const(0.0)
} else {
Expr::Sub(Box::new(simplified_lhs), Box::new(simplified_rhs))
}
}
Expr::Mul(lhs, rhs) => {
let simplified_lhs = lhs.nozeros();
let simplified_rhs = rhs.nozeros();
if simplified_lhs == Expr::Const(0.0) || simplified_rhs == Expr::Const(0.0) {
Expr::Const(0.0)
} else {
Expr::Mul(Box::new(simplified_lhs), Box::new(simplified_rhs))
}
}
Expr::Div(lhs, rhs) => {
let simplified_lhs = lhs.nozeros();
let simplified_rhs = rhs.nozeros();
if simplified_lhs == Expr::Const(0.0) {
Expr::Const(0.0)
} else {
Expr::Div(Box::new(simplified_lhs), Box::new(simplified_rhs))
}
}
Expr::Pow(base, exp) => Expr::Pow(Box::new(base.nozeros()), Box::new(exp.nozeros())),
Expr::Exp(expr) => Expr::Exp(Box::new(expr.nozeros())),
Expr::Ln(expr) => Expr::Ln(Box::new(expr.nozeros())),
Expr::sin(expr) => Expr::sin(Box::new(expr.nozeros())),
Expr::cos(expr) => Expr::cos(Box::new(expr.nozeros())),
Expr::tg(expr) => Expr::tg(Box::new(expr.nozeros())),
Expr::ctg(expr) => Expr::ctg(Box::new(expr.nozeros())),
Expr::arcsin(expr) => Expr::arcsin(Box::new(expr.nozeros())),
Expr::arccos(expr) => Expr::arccos(Box::new(expr.nozeros())),
Expr::arctg(expr) => Expr::arctg(Box::new(expr.nozeros())),
Expr::arcctg(expr) => Expr::arcctg(Box::new(expr.nozeros())),
}
}
pub(crate) fn normalize_add_pair(lhs: Expr, rhs: Expr) -> Expr {
match (&lhs, &rhs) {
(Expr::Const(a), Expr::Const(b)) => Expr::Const(a + b),
(Expr::Const(0.0), _) => rhs,
(_, Expr::Const(0.0)) => lhs,
_ => {
let expr = Expr::Add(Box::new(lhs), Box::new(rhs));
let normalized = Self::simplify_polynomial(&expr).unwrap_or(expr);
Self::canonicalize_addition(normalized)
}
}
}
pub(crate) fn normalize_sub_pair(lhs: Expr, rhs: Expr) -> Expr {
match (&lhs, &rhs) {
(Expr::Const(a), Expr::Const(b)) => Expr::Const(a - b),
(_, Expr::Const(0.0)) => lhs,
_ if lhs == rhs => Expr::Const(0.0),
_ => {
let neg_rhs = Expr::Mul(Box::new(Expr::Const(-1.0)), Box::new(rhs)).simplify_();
let add_expr = Expr::Add(Box::new(lhs), Box::new(neg_rhs));
let normalized = Self::simplify_polynomial(&add_expr).unwrap_or(add_expr);
Self::normalize_basic(normalized)
}
}
}
pub(crate) fn normalize_mul_pair(lhs: Expr, rhs: Expr) -> Expr {
match (&lhs, &rhs) {
(Expr::Const(a), Expr::Const(b)) => Expr::Const(a * b),
(Expr::Const(0.0), _) | (_, Expr::Const(0.0)) => Expr::Const(0.0),
(Expr::Const(1.0), _) => rhs,
(_, Expr::Const(1.0)) => lhs,
_ => Self::normalize_basic(Expr::Mul(Box::new(lhs), Box::new(rhs))),
}
}
pub(crate) fn normalize_div_pair(lhs: Expr, rhs: Expr) -> Expr {
match (&lhs, &rhs) {
(Expr::Const(a), Expr::Const(b)) if *b != 0.0 => Expr::Const(a / b),
(Expr::Const(0.0), _) => Expr::Const(0.0),
(_, Expr::Const(1.0)) => lhs,
_ if lhs == rhs => Expr::Const(1.0),
_ => {
let (lhs_coeff, mut lhs_factors) = collect_factor_powers(&lhs);
let (rhs_coeff, rhs_factors) = collect_factor_powers(&rhs);
if rhs_coeff == 0.0 {
return Expr::Div(Box::new(lhs), Box::new(rhs));
}
let mut denominator_factors = Vec::new();
let mut cancelled_anything = lhs_coeff != 1.0 || rhs_coeff != 1.0;
for (rhs_base, rhs_exp) in rhs_factors {
if let Some((_, lhs_exp)) = lhs_factors
.iter_mut()
.find(|(lhs_base, _)| *lhs_base == rhs_base)
{
*lhs_exp = Self::normalize_sub_pair(lhs_exp.clone(), rhs_exp);
cancelled_anything = true;
} else {
denominator_factors.push((rhs_base, rhs_exp));
}
}
if !cancelled_anything {
return Expr::Div(Box::new(lhs), Box::new(rhs));
}
let numerator = Self::build_factor_product(lhs_coeff / rhs_coeff, lhs_factors);
let denominator = Self::build_factor_product(1.0, denominator_factors);
match denominator {
Expr::Const(1.0) => numerator,
_ => Expr::Div(Box::new(numerator), Box::new(denominator)),
}
}
}
}
pub(crate) fn normalize_pow_pair(base: Expr, exp: Expr) -> Expr {
match (&base, &exp) {
(Expr::Const(a), Expr::Const(b)) => Expr::Const(a.powf(*b)),
(_, Expr::Const(0.0)) => Expr::Const(1.0),
(_, Expr::Const(1.0)) => base,
(Expr::Const(0.0), _) => Expr::Const(0.0),
(Expr::Const(1.0), _) => Expr::Const(1.0),
(Expr::Pow(inner_base, inner_exp), _) => {
let new_exp = Self::normalize_mul_pair(inner_exp.as_ref().clone(), exp);
Self::normalize_pow_pair(inner_base.as_ref().clone(), new_exp)
}
_ => Expr::Pow(Box::new(base), Box::new(exp)),
}
}
pub(crate) fn normalize_basic(expr: Expr) -> Expr {
match expr {
Expr::Add(lhs, rhs) => Self::normalize_add_pair(*lhs, *rhs),
Expr::Sub(lhs, rhs) => Self::normalize_sub_pair(*lhs, *rhs),
Expr::Mul(_, _) => Self::canonicalize_multiplication(expr),
Expr::Div(lhs, rhs) => Self::normalize_div_pair(*lhs, *rhs),
Expr::Pow(base, exp) => Self::normalize_pow_pair(*base, *exp),
other => other,
}
}
fn canonicalize_addition(expr: Expr) -> Expr {
let mut terms = Vec::new();
flatten_add(&expr, &mut terms);
let mut constant_sum = 0.0;
let mut non_constant_terms = Vec::new();
for term in terms {
match term {
Expr::Const(value) => constant_sum += value,
other => non_constant_terms.push(other),
}
}
non_constant_terms.retain(|term| *term != Expr::Const(0.0));
non_constant_terms.sort_by_key(add_term_sort_key);
if constant_sum != 0.0 || non_constant_terms.is_empty() {
non_constant_terms.push(Expr::Const(constant_sum));
}
Self::build_addition_chain(non_constant_terms)
}
fn build_addition_chain(terms: Vec<Expr>) -> Expr {
let mut iter = terms.into_iter();
let mut result = iter.next().unwrap_or(Expr::Const(0.0));
for term in iter {
if let Some(positive_term) = extract_negative_term(&term) {
result = Expr::Sub(Box::new(result), Box::new(positive_term));
} else {
result = Expr::Add(Box::new(result), Box::new(term));
}
}
result
}
fn canonicalize_multiplication(expr: Expr) -> Expr {
let (coefficient, mut power_factors) = collect_factor_powers(&expr);
if coefficient == 0.0 {
return Expr::Const(0.0);
}
power_factors.sort_by_key(|(base, exp)| mul_factor_sort_key(base, exp));
let mut canonical_factors = Vec::new();
if coefficient != 1.0 || power_factors.is_empty() {
canonical_factors.push(Expr::Const(coefficient));
}
for (base, exp) in power_factors {
match exp {
Expr::Const(0.0) => {}
Expr::Const(1.0) => canonical_factors.push(base),
other_exp => canonical_factors.push(Self::normalize_pow_pair(base, other_exp)),
}
}
if canonical_factors.is_empty() {
Expr::Const(1.0)
} else {
canonical_factors
.into_iter()
.reduce(|lhs, rhs| Expr::Mul(Box::new(lhs), Box::new(rhs)))
.unwrap()
}
}
fn build_factor_product(coefficient: f64, mut power_factors: Vec<(Expr, Expr)>) -> Expr {
if coefficient == 0.0 {
return Expr::Const(0.0);
}
power_factors.retain(|(_, exp)| *exp != Expr::Const(0.0));
power_factors.sort_by_key(|(base, exp)| mul_factor_sort_key(base, exp));
let mut factors = Vec::new();
if coefficient != 1.0 || power_factors.is_empty() {
factors.push(Expr::Const(coefficient));
}
for (base, exp) in power_factors {
match exp {
Expr::Const(1.0) => factors.push(base),
other_exp => factors.push(Self::normalize_pow_pair(base, other_exp)),
}
}
factors
.into_iter()
.reduce(Self::normalize_mul_pair)
.unwrap_or(Expr::Const(1.0))
}
pub fn simplify_numbers(&self) -> Expr {
match self {
Expr::Var(_) => self.clone(),
Expr::Const(_) => self.clone(),
Expr::Add(lhs, rhs) => {
let lhs_simplified = lhs.simplify_numbers();
let rhs_simplified = rhs.simplify_numbers();
match (lhs_simplified, rhs_simplified) {
(Expr::Const(a), Expr::Const(b)) => Expr::Const(a + b),
(lhs, rhs) => Expr::Add(Box::new(lhs), Box::new(rhs)),
}
}
Expr::Sub(lhs, rhs) => {
let lhs_simplified = lhs.simplify_numbers();
let rhs_simplified = rhs.simplify_numbers();
match (lhs_simplified, rhs_simplified) {
(Expr::Const(a), Expr::Const(b)) => Expr::Const(a - b),
(lhs, rhs) => Expr::Sub(Box::new(lhs), Box::new(rhs)),
}
}
Expr::Mul(lhs, rhs) => {
let lhs_simplified = lhs.simplify_numbers();
let rhs_simplified = rhs.simplify_numbers();
match (lhs_simplified, rhs_simplified) {
(Expr::Const(a), Expr::Const(b)) => Expr::Const(a * b),
(lhs, rhs) => Expr::Mul(Box::new(lhs), Box::new(rhs)),
}
}
Expr::Div(lhs, rhs) => {
let lhs_simplified = lhs.simplify_numbers();
let rhs_simplified = rhs.simplify_numbers();
match (lhs_simplified, rhs_simplified) {
(Expr::Const(a), Expr::Const(b)) => Expr::Const(a / b),
(lhs, rhs) => Expr::Div(Box::new(lhs), Box::new(rhs)),
}
}
Expr::Pow(base, exp) => Expr::Pow(
Box::new(base.simplify_numbers()),
Box::new(exp.simplify_numbers()),
),
Expr::Exp(expr) => Expr::Exp(Box::new(expr.simplify_numbers())),
Expr::Ln(expr) => Expr::Ln(Box::new(expr.simplify_numbers())),
Expr::sin(expr) => Expr::sin(Box::new(expr.simplify_numbers())),
Expr::cos(expr) => Expr::cos(Box::new(expr.simplify_numbers())),
Expr::tg(expr) => Expr::tg(Box::new(expr.simplify_numbers())),
Expr::ctg(expr) => Expr::ctg(Box::new(expr.simplify_numbers())),
Expr::arcsin(expr) => Expr::arcsin(Box::new(expr.simplify_numbers())),
Expr::arccos(expr) => Expr::arccos(Box::new(expr.simplify_numbers())),
Expr::arctg(expr) => Expr::arctg(Box::new(expr.simplify_numbers())),
Expr::arcctg(expr) => Expr::arcctg(Box::new(expr.simplify_numbers())),
}
}
pub fn simplify_(&self) -> Expr {
match self {
Expr::Var(_) => self.clone(),
Expr::Const(_) => self.clone(),
Expr::Add(lhs, rhs) => Self::normalize_basic(Expr::Add(
Box::new(lhs.simplify_()),
Box::new(rhs.simplify_()),
)),
Expr::Sub(lhs, rhs) => Self::normalize_basic(Expr::Sub(
Box::new(lhs.simplify_()),
Box::new(rhs.simplify_()),
)),
Expr::Mul(lhs, rhs) => Self::normalize_basic(Expr::Mul(
Box::new(lhs.simplify_()),
Box::new(rhs.simplify_()),
)),
Expr::Div(lhs, rhs) => Self::normalize_basic(Expr::Div(
Box::new(lhs.simplify_()),
Box::new(rhs.simplify_()),
)),
Expr::Pow(base, exp) => Self::normalize_basic(Expr::Pow(
Box::new(base.simplify_()),
Box::new(exp.simplify_()),
)),
Expr::Exp(expr) => {
let expr = expr.simplify_();
match &expr {
Expr::Const(0.0) => Expr::Const(1.0),
_ => Expr::Exp(Box::new(expr)),
}
}
Expr::Ln(expr) => {
let expr = expr.simplify_();
match &expr {
Expr::Const(1.0) => Expr::Const(0.0),
_ => Expr::Ln(Box::new(expr)),
}
}
Expr::sin(expr) => {
let expr = expr.simplify_();
match &expr {
Expr::Const(0.0) => Expr::Const(0.0),
_ => Expr::sin(Box::new(expr)),
}
}
Expr::cos(expr) => {
let expr = expr.simplify_();
match &expr {
Expr::Const(0.0) => Expr::Const(1.0),
_ => Expr::cos(Box::new(expr)),
}
} Expr::tg(expr) => {
let expr = expr.simplify_();
match &expr {
Expr::Const(0.0) => Expr::Const(0.0),
_ => Expr::tg(Box::new(expr)),
}
} Expr::ctg(expr) => {
let expr = expr.simplify_();
match &expr {
_ => Expr::ctg(Box::new(expr)),
}
}
Expr::arcsin(expr) => {
let expr = expr.simplify_();
match &expr {
Expr::Const(0.0) => Expr::Const(0.0),
_ => Expr::arcsin(Box::new(expr)),
}
} Expr::arccos(expr) => {
let expr = expr.simplify_();
match &expr {
Expr::Const(1.0) => Expr::Const(0.0),
_ => Expr::arccos(Box::new(expr)),
}
} Expr::arctg(expr) => {
let expr = expr.simplify_();
match &expr {
Expr::Const(0.0) => Expr::Const(0.0),
_ => Expr::arctg(Box::new(expr)),
}
}
Expr::arcctg(expr) => {
let expr = expr.simplify_();
match &expr {
_ => Expr::arcctg(Box::new(expr)),
}
} }
}
pub(crate) fn simplify_polynomial(expr: &Expr) -> Option<Expr> {
let mut terms = Vec::new();
flatten_add(expr, &mut terms);
if terms.len() < 2 {
return None;
}
let mut has_non_poly = false;
for term in &terms {
let (_, coeff) = extract_monomial(term);
if coeff == 0.0 && !matches!(term, Expr::Const(0.0)) {
has_non_poly = true;
break;
}
}
if has_non_poly {
return None;
}
let poly_map = collect_add_terms(&terms);
if poly_map.len() == terms.len() {
return None;
}
let mut result_terms = Vec::new();
for (monomial, coeff) in poly_map {
if coeff == 0.0 {
continue;
}
let term = Self::build_monomial_term(&monomial, coeff);
result_terms.push(term);
}
if result_terms.is_empty() {
Some(Expr::Const(0.0))
} else if result_terms.len() == 1 {
Some(result_terms.into_iter().next().unwrap())
} else {
Some(
result_terms
.into_iter()
.reduce(|a, b| Expr::Add(Box::new(a), Box::new(b)))
.unwrap(),
)
}
}
fn build_monomial_term(monomial: &MonomialKey, coeff: f64) -> Expr {
if monomial.0.is_empty() {
return Expr::Const(coeff);
}
let mut factors = Vec::new();
if coeff != 1.0 {
factors.push(Expr::Const(coeff));
}
for (var, exp) in &monomial.0 {
let var_expr = Expr::Var(var.clone());
if *exp == 1 {
factors.push(var_expr);
} else if *exp > 1 {
factors.push(Expr::Pow(
Box::new(var_expr),
Box::new(Expr::Const(*exp as f64)),
));
}
}
if factors.is_empty() {
Expr::Const(1.0)
} else if factors.len() == 1 {
factors.into_iter().next().unwrap()
} else {
factors
.into_iter()
.reduce(|a, b| Expr::Mul(Box::new(a), Box::new(b)))
.unwrap()
}
}
pub fn simplify(&self) -> Expr {
let zeros_proceeded = self.simplify_();
zeros_proceeded
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MonomialKey(pub BTreeMap<String, i32>);
fn flatten_add(expr: &Expr, out: &mut Vec<Expr>) {
match expr {
Expr::Add(a, b) => {
flatten_add(a, out);
flatten_add(b, out);
}
Expr::Sub(a, b) => {
flatten_add(a, out);
let neg_b = Expr::Mul(Box::new(Expr::Const(-1.0)), b.clone());
flatten_add(&neg_b, out);
}
Expr::Mul(lhs, rhs) => {
if let Expr::Const(-1.0) = lhs.as_ref() {
match rhs.as_ref() {
Expr::Add(a, b) => {
let neg_a = Expr::Mul(Box::new(Expr::Const(-1.0)), a.clone());
let neg_b = Expr::Mul(Box::new(Expr::Const(-1.0)), b.clone());
flatten_add(&neg_a, out); flatten_add(&neg_b, out); }
_ => out.push(expr.clone()), }
} else if let Expr::Const(-1.0) = rhs.as_ref() {
match lhs.as_ref() {
Expr::Add(a, b) => {
let neg_a = Expr::Mul(Box::new(Expr::Const(-1.0)), a.clone());
let neg_b = Expr::Mul(Box::new(Expr::Const(-1.0)), b.clone());
flatten_add(&neg_a, out);
flatten_add(&neg_b, out);
}
_ => out.push(expr.clone()), }
} else {
out.push(expr.clone());
}
}
_ => out.push(expr.clone()),
}
}
fn flatten_mul(expr: &Expr, out: &mut Vec<Expr>) {
match expr {
Expr::Mul(a, b) => {
flatten_mul(a, out);
flatten_mul(b, out);
}
_ => out.push(expr.clone()),
}
}
fn collect_add_terms(terms: &[Expr]) -> BTreeMap<MonomialKey, f64> {
let mut poly = BTreeMap::new();
for t in terms {
let (mon, coeff) = extract_monomial(t);
*poly.entry(mon).or_insert(0.0) += coeff;
}
poly
}
fn add_term_sort_key(expr: &Expr) -> (u8, i32, String) {
let (monomial, coeff) = extract_monomial(expr);
if coeff != 0.0 {
if monomial.0.is_empty() {
(2, 0, format!("{}", expr))
} else {
let degree = monomial.0.values().sum::<i32>();
(0, -degree, format!("{:?}", monomial))
}
} else {
(1, 0, format!("{}", expr))
}
}
fn split_power_factor(expr: Expr) -> (Expr, Expr) {
match expr {
Expr::Pow(base, exp) => (*base, *exp),
other => (other, Expr::Const(1.0)),
}
}
fn collect_factor_powers(expr: &Expr) -> (f64, Vec<(Expr, Expr)>) {
let mut factors = Vec::new();
flatten_mul(expr, &mut factors);
let mut coefficient = 1.0;
let mut power_factors = Vec::new();
for factor in factors {
match factor {
Expr::Const(value) => coefficient *= value,
other => {
let (base, exp) = split_power_factor(other);
merge_power_factor(&mut power_factors, base, exp);
}
}
}
(coefficient, power_factors)
}
fn merge_power_factor(power_factors: &mut Vec<(Expr, Expr)>, base: Expr, exp: Expr) {
if let Some((_, existing_exp)) = power_factors
.iter_mut()
.find(|(existing_base, _)| *existing_base == base)
{
*existing_exp = Expr::normalize_add_pair(existing_exp.clone(), exp);
} else {
power_factors.push((base, exp));
}
}
fn mul_factor_sort_key(base: &Expr, exp: &Expr) -> (u8, String, String) {
let class = match base {
Expr::Var(_) => 0,
Expr::Add(_, _) | Expr::Sub(_, _) => 2,
_ => 1,
};
(class, format!("{}", base), format!("{}", exp))
}
fn extract_negative_term(expr: &Expr) -> Option<Expr> {
match expr {
Expr::Const(value) if *value < 0.0 => Some(Expr::Const(-value)),
Expr::Mul(lhs, rhs) => match (lhs.as_ref(), rhs.as_ref()) {
(Expr::Const(value), other) if *value < 0.0 => {
if *value == -1.0 {
Some(other.clone())
} else {
Some(Expr::Mul(
Box::new(Expr::Const(-value)),
Box::new(other.clone()),
))
}
}
(other, Expr::Const(value)) if *value < 0.0 => {
if *value == -1.0 {
Some(other.clone())
} else {
Some(Expr::Mul(
Box::new(Expr::Const(-value)),
Box::new(other.clone()),
))
}
}
_ => None,
},
_ => None,
}
}
fn exponent_to_integer(exp: &Expr) -> Option<i32> {
match exp {
Expr::Const(value) if value.is_finite() && value.fract() == 0.0 => Some(*value as i32),
_ => None,
}
}
fn extract_monomial(expr: &Expr) -> (MonomialKey, f64) {
match expr {
Expr::Const(c) => (MonomialKey(BTreeMap::new()), *c),
Expr::Var(v) => {
let mut m = BTreeMap::new();
m.insert(v.clone(), 1);
(MonomialKey(m), 1.0)
}
Expr::Mul(lhs, rhs) => match (lhs.as_ref(), rhs.as_ref()) {
(Expr::Const(-1.0), other) | (other, Expr::Const(-1.0)) => {
let (mon, coeff) = extract_monomial(other);
(mon, -coeff)
}
(Expr::Const(c), other) | (other, Expr::Const(c)) => {
let (mon, coeff) = extract_monomial(other);
(mon, c * coeff)
}
_ => {
let (coeff, power_factors) = collect_factor_powers(expr);
let mut map = BTreeMap::new();
let mut has_non_poly = false;
for (base, exp) in power_factors {
match (base, exponent_to_integer(&exp)) {
(Expr::Var(v), Some(power)) => *map.entry(v).or_insert(0) += power,
_ => has_non_poly = true,
}
}
if has_non_poly {
(MonomialKey(BTreeMap::new()), 0.0)
} else {
(MonomialKey(map), coeff)
}
}
},
Expr::Pow(base, exp) => {
if let (Expr::Var(v), Some(power)) = (base.as_ref(), exponent_to_integer(exp.as_ref()))
{
let mut m = BTreeMap::new();
m.insert(v.clone(), power);
(MonomialKey(m), 1.0)
} else {
(MonomialKey(BTreeMap::new()), 0.0)
}
}
_ => (MonomialKey(BTreeMap::new()), 0.0),
}
}
#[allow(dead_code)]
fn horner_univariate(var: &str, terms: Vec<(i32, f64)>) -> Expr {
use Expr::*;
if terms.is_empty() {
return Const(0.0);
}
let max_deg = terms.iter().map(|(e, _)| *e).max().unwrap();
let mut coeffs = vec![0.0; (max_deg + 1) as usize];
for (exp, c) in terms {
if exp >= 0 {
coeffs[exp as usize] += c; }
}
let mut i = coeffs.len() - 1;
while i > 0 && coeffs[i] == 0.0 {
i -= 1;
}
let mut acc = Const(coeffs[i]);
let x = Var(var.to_string());
while i > 0 {
acc = Add(
Box::new(Mul(Box::new(acc), Box::new(x.clone()))),
Box::new(Const(coeffs[i - 1])),
);
i -= 1;
}
acc
}