use crate::core::{Expression, Number, Symbol};
use crate::simplify::Simplify;
pub fn integrate_repeated_quadratic(
numerator: &Expression,
denominator: &Expression,
p: &Expression,
q: &Expression,
power: i64,
var: &Symbol,
) -> Option<Expression> {
let d = Expression::add(vec![
Expression::pow(Expression::symbol(var.clone()), Expression::integer(2)),
Expression::mul(vec![p.clone(), Expression::symbol(var.clone())]),
q.clone(),
]);
if power != 2 {
return None;
}
let (coeff_a, coeff_b) = extract_linear_coefficients(numerator, var)?;
let denom_expr = Expression::add(vec![
Expression::mul(vec![Expression::integer(4), q.clone()]),
Expression::mul(vec![
Expression::integer(-1),
Expression::pow(p.clone(), Expression::integer(2)),
]),
])
.simplify();
if denom_expr.is_zero() {
return None;
}
let a = Expression::mul(vec![
Expression::add(vec![
Expression::mul(vec![Expression::integer(2), coeff_b]),
Expression::mul(vec![Expression::integer(-1), coeff_a.clone(), p.clone()]),
]),
Expression::pow(denom_expr, Expression::integer(-1)),
])
.simplify();
let b = Expression::mul(vec![
Expression::rational(1, 2),
Expression::add(vec![
Expression::mul(vec![a.clone(), p.clone()]),
Expression::mul(vec![Expression::integer(-1), coeff_a]),
]),
])
.simplify();
let h_coeff = a.clone();
let g = Expression::add(vec![
Expression::mul(vec![a, Expression::symbol(var.clone())]),
b,
]);
let rational_part = Expression::mul(vec![g, Expression::pow(d, Expression::integer(-1))]);
let transcendental_part = integrate_simple_quadratic(&h_coeff, denominator, p, q, var)?;
Some(Expression::add(vec![rational_part, transcendental_part]).simplify())
}
pub fn extract_linear_coefficients(
expr: &Expression,
var: &Symbol,
) -> Option<(Expression, Expression)> {
match expr {
Expression::Number(_) => Some((Expression::integer(0), expr.clone())),
Expression::Symbol(s) if *s == *var => {
Some((Expression::integer(1), Expression::integer(0)))
}
Expression::Mul(factors) => {
let mut coeff = Vec::new();
let mut has_var = false;
for factor in factors.iter() {
if let Expression::Symbol(s) = factor {
if *s == *var {
has_var = true;
continue;
}
}
coeff.push(factor.clone());
}
if has_var {
let a = if coeff.is_empty() {
Expression::integer(1)
} else {
Expression::mul(coeff)
};
Some((a, Expression::integer(0)))
} else {
None
}
}
Expression::Add(terms) => {
let mut a = Expression::integer(0);
let mut b = Expression::integer(0);
for term in terms.iter() {
match term {
Expression::Symbol(s) if *s == *var => {
a = Expression::add(vec![a, Expression::integer(1)]);
}
Expression::Mul(_) => {
if term.contains_variable(var) {
let (term_a, term_b) = extract_linear_coefficients(term, var)?;
a = Expression::add(vec![a, term_a]);
b = Expression::add(vec![b, term_b]);
} else {
b = Expression::add(vec![b, term.clone()]);
}
}
_ => {
if !term.contains_variable(var) {
b = Expression::add(vec![b, term.clone()]);
} else {
return None;
}
}
}
}
Some((a.simplify(), b.simplify()))
}
_ => None,
}
}
pub fn integrate_simple_quadratic(
_numerator: &Expression,
_denominator: &Expression,
p: &Expression,
q: &Expression,
var: &Symbol,
) -> Option<Expression> {
let discriminant = Expression::add(vec![
Expression::pow(p.clone(), Expression::integer(2)),
Expression::mul(vec![Expression::integer(-4), q.clone()]),
])
.simplify();
if let Expression::Number(Number::Integer(d)) = discriminant {
if d >= 0 {
return None;
}
}
let a_squared = Expression::add(vec![
q.clone(),
Expression::mul(vec![
Expression::rational(-1, 4),
Expression::pow(p.clone(), Expression::integer(2)),
]),
])
.simplify();
let a = Expression::function("sqrt", vec![a_squared]);
let shift = Expression::mul(vec![Expression::rational(1, 2), p.clone()]);
let x_shifted = Expression::add(vec![Expression::symbol(var.clone()), shift]).simplify();
Some(Expression::mul(vec![
Expression::pow(a.clone(), Expression::integer(-1)),
Expression::function(
"atan",
vec![Expression::mul(vec![
Expression::pow(a, Expression::integer(-1)),
x_shifted,
])],
),
]))
}