use crate::kernel::{ExprData, ExprId, ExprPool};
use rug::Integer;
pub fn is_zero_expr(expr: ExprId, pool: &ExprPool) -> bool {
match pool.get(expr) {
ExprData::Integer(n) => n.0 == 0,
ExprData::Rational(r) => r.0 == 0,
_ => false,
}
}
pub fn is_free_of_subexpr(expr: ExprId, sub: ExprId, pool: &ExprPool) -> bool {
if expr == sub {
return false;
}
let children: Vec<ExprId> = pool.with(expr, |data| match data {
ExprData::Add(args) | ExprData::Mul(args) => args.clone(),
ExprData::Pow { base, exp } => vec![*base, *exp],
ExprData::Func { args, .. } => args.clone(),
_ => vec![],
});
children.iter().all(|&c| is_free_of_subexpr(c, sub, pool))
}
pub fn is_free_of(expr: ExprId, var: ExprId, pool: &ExprPool) -> bool {
is_free_of_subexpr(expr, var, pool)
}
pub fn poly_degree_in(expr: ExprId, var: ExprId, pool: &ExprPool) -> Option<u32> {
if expr == var {
return Some(1);
}
if is_free_of(expr, var, pool) {
return Some(0);
}
match pool.get(expr) {
ExprData::Add(args) => {
let mut max_d = 0u32;
for a in &args {
let d = poly_degree_in(*a, var, pool)?;
max_d = max_d.max(d);
}
Some(max_d)
}
ExprData::Mul(args) => {
let mut total = 0u32;
for a in &args {
let d = poly_degree_in(*a, var, pool)?;
total = total.checked_add(d)?;
}
Some(total)
}
ExprData::Pow { base, exp } if base == var => match pool.get(exp) {
ExprData::Integer(n) => {
let k: Option<u32> = n.0.to_u32();
k
}
_ => None,
},
ExprData::Pow { base, exp } if is_free_of(base, var, pool) => {
if is_free_of(exp, var, pool) {
Some(0)
} else {
None
}
}
_ => None,
}
}
pub fn as_integer(expr: ExprId, pool: &ExprPool) -> Option<i64> {
match pool.get(expr) {
ExprData::Integer(n) => n.0.to_i64(),
_ => None,
}
}
pub fn as_linear(expr: ExprId, var: ExprId, pool: &ExprPool) -> Option<(ExprId, ExprId)> {
use crate::poly::UniPoly;
let up = UniPoly::from_symbolic(expr, var, pool).ok()?;
let cs = up.coefficients();
let a_int = cs.get(1)?;
if *a_int == 0 {
return None;
}
let b_int = cs.first().cloned().unwrap_or_else(|| Integer::from(0));
let a = pool.integer(a_int.clone());
let b = pool.integer(b_int);
Some((a, b))
}
pub fn as_quadratic(
expr: ExprId,
var: ExprId,
pool: &ExprPool,
) -> Option<(ExprId, ExprId, ExprId)> {
use crate::poly::UniPoly;
let up = UniPoly::from_symbolic(expr, var, pool).ok()?;
let cs = up.coefficients();
let a_int = cs.get(2)?;
if *a_int == 0 {
return None;
}
let b_int = cs.get(1).cloned().unwrap_or_else(|| Integer::from(0));
let c_int = cs.first().cloned().unwrap_or_else(|| Integer::from(0));
let a = pool.integer(a_int.clone());
let b = pool.integer(b_int);
let c = pool.integer(c_int);
Some((a, b, c))
}
pub fn poly_int_coeffs(expr: ExprId, var: ExprId, pool: &ExprPool) -> Option<Vec<Integer>> {
use crate::poly::UniPoly;
let up = UniPoly::from_symbolic(expr, var, pool).ok()?;
Some(up.coefficients())
}