use mathhook_core::calculus::integrals::rational::is_rational_function;
use mathhook_core::calculus::integrals::Integration;
use mathhook_core::core::Number;
use mathhook_core::{symbol, Expression};
use num_bigint::BigInt;
use num_rational::BigRational;
#[test]
fn test_basic_polynomial() {
let x = symbol!(x);
let expr = Expression::pow(Expression::symbol(x.clone()), Expression::integer(2));
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_simple_rational_function() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1)),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_with_linear_denominator() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(1)]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_proper_fraction() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::integer(1),
]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_improper_fraction() {
let x = symbol!(x);
let numerator = Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::mul(vec![Expression::integer(2), Expression::symbol(x.clone())]),
Expression::integer(3),
]);
let denominator = Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(1)]);
let expr = Expression::mul(vec![
numerator,
Expression::pow(denominator, Expression::integer(-1)),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_partial_fraction_decomposition() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::mul(vec![
Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(-1)]),
Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(-2)]),
]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_with_quadratic_factors() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::integer(-1),
]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_zero_numerator() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(0),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1)),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_constant_numerator() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(5),
Expression::pow(
Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(3)]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_complex_rational_function() {
let x = symbol!(x);
let numerator = Expression::add(vec![
Expression::mul(vec![Expression::integer(2), Expression::symbol(x.clone())]),
Expression::integer(3),
]);
let denominator = Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::mul(vec![Expression::integer(5), Expression::symbol(x.clone())]),
Expression::integer(6),
]);
let expr = Expression::mul(vec![
numerator,
Expression::pow(denominator, Expression::integer(-1)),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_non_rational_sqrt() {
let x = symbol!(x);
let expr = Expression::pow(Expression::symbol(x.clone()), Expression::rational(1, 2));
assert!(!is_rational_function(&expr, &x));
}
#[test]
fn test_non_rational_trig() {
let x = symbol!(x);
let expr = Expression::function("sin", vec![Expression::symbol(x.clone())]);
assert!(!is_rational_function(&expr, &x));
}
#[test]
fn test_non_rational_exp() {
let x = symbol!(x);
let expr = Expression::function("exp", vec![Expression::symbol(x.clone())]);
assert!(!is_rational_function(&expr, &x));
}
#[test]
fn test_rational_polynomial_over_polynomial() {
let x = symbol!(x);
let numerator = Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(3)),
Expression::mul(vec![
Expression::integer(-3),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
]),
Expression::mul(vec![Expression::integer(2), Expression::symbol(x.clone())]),
Expression::integer(-5),
]);
let denominator = Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::integer(-4),
]);
let expr = Expression::mul(vec![
numerator,
Expression::pow(denominator, Expression::integer(-1)),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_simple_substitution() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::pow(
Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::integer(1),
]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_degree_one_numerator() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::pow(
Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(-1)]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_repeated_linear_factor() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(-1)]),
Expression::integer(-2),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_with_irreducible_quadratic() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::symbol(x.clone()),
Expression::integer(1),
]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_numerator_equals_denominator_derivative() {
let x = symbol!(x);
let numerator = Expression::add(vec![
Expression::mul(vec![Expression::integer(2), Expression::symbol(x.clone())]),
Expression::integer(1),
]);
let denominator = Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::symbol(x.clone()),
Expression::integer(1),
]);
let expr = Expression::mul(vec![
numerator,
Expression::pow(denominator, Expression::integer(-1)),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_sum_integration() {
let x = symbol!(x);
let expr = Expression::add(vec![
Expression::mul(vec![
Expression::integer(1),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1)),
]),
Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::add(vec![Expression::symbol(x.clone()), Expression::integer(1)]),
Expression::integer(-1),
),
]),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_mixed_terms() {
let x = symbol!(x);
let expr = Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::mul(vec![
Expression::integer(1),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(-1)),
]),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_cubic_denominator() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(3)),
Expression::integer(-1),
]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_fourth_degree_denominator() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(4)),
Expression::integer(-1),
]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_complex_numerator_denominator() {
let x = symbol!(x);
let numerator = Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::mul(vec![Expression::integer(3), Expression::symbol(x.clone())]),
Expression::integer(2),
]);
let denominator = Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(3)),
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::mul(vec![Expression::integer(-2), Expression::symbol(x.clone())]),
]);
let expr = Expression::mul(vec![
numerator,
Expression::pow(denominator, Expression::integer(-1)),
]);
assert!(is_rational_function(&expr, &x));
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}
#[test]
fn test_rational_with_irreducible_quadratic_in_partial_fraction() {
let x = symbol!(x);
let expr = Expression::mul(vec![
Expression::integer(1),
Expression::pow(
Expression::mul(vec![
Expression::symbol(x.clone()),
Expression::add(vec![
Expression::pow(Expression::symbol(x.clone()), Expression::integer(2)),
Expression::integer(1),
]),
]),
Expression::integer(-1),
),
]);
assert!(is_rational_function(&expr, &x));
let integral = expr.integrate(x, 0);
let result_str = integral.to_string();
assert!(result_str.contains("ln") || result_str.contains("log") || result_str.contains("atan"));
}
#[test]
fn test_sqrt_x_integration_full() {
let x = symbol!(x);
let expr = Expression::pow(
Expression::symbol(x.clone()),
Expression::Number(Number::rational(BigRational::new(
BigInt::from(1),
BigInt::from(2),
))),
);
let result = expr.integrate(x, 0);
assert!(!matches!(result, Expression::Calculus(_)));
}