use std::sync::Arc;
use mathhook_core::calculus::integrals::strategy::integrate_with_strategy;
use mathhook_core::core::{Expression, Symbol};
use std::time::{Duration, Instant};
fn symbol(name: &str) -> Symbol {
Symbol::scalar(name)
}
fn x() -> Symbol {
symbol("x")
}
fn integer(n: i64) -> Expression {
Expression::integer(n)
}
fn add(terms: Vec<Expression>) -> Expression {
Expression::Add(Arc::new(terms))
}
fn mul(factors: Vec<Expression>) -> Expression {
Expression::Mul(Arc::new(factors))
}
fn pow(base: Expression, exp: Expression) -> Expression {
Expression::Pow(Arc::new(base), Box::new(exp))
}
fn sin(arg: Expression) -> Expression {
Expression::function("sin", vec![arg])
}
fn cos(arg: Expression) -> Expression {
Expression::function("cos", vec![arg])
}
fn exp(arg: Expression) -> Expression {
Expression::function("exp", vec![arg])
}
fn ln(arg: Expression) -> Expression {
Expression::function("ln", vec![arg])
}
const SIMPLE_THRESHOLD: Duration = Duration::from_millis(1);
const MODERATE_THRESHOLD: Duration = Duration::from_millis(10);
const COMPLEX_THRESHOLD: Duration = Duration::from_millis(100);
const VERY_COMPLEX_THRESHOLD: Duration = Duration::from_secs(1);
#[test]
fn test_simple_polynomial_fast() {
let var = x();
let expr = pow(Expression::Symbol(var.clone()), integer(2));
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < SIMPLE_THRESHOLD,
"Simple polynomial integration took {:?}, expected < {:?}",
duration,
SIMPLE_THRESHOLD
);
}
#[test]
fn test_simple_trig_fast() {
let var = x();
let expr = sin(Expression::Symbol(var.clone()));
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < SIMPLE_THRESHOLD,
"Simple trig integration took {:?}, expected < {:?}",
duration,
SIMPLE_THRESHOLD
);
}
#[test]
fn test_simple_exponential_fast() {
let var = x();
let expr = exp(Expression::Symbol(var.clone()));
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < SIMPLE_THRESHOLD,
"Simple exponential integration took {:?}, expected < {:?}",
duration,
SIMPLE_THRESHOLD
);
}
#[test]
fn test_polynomial_sum_linear_time() {
let var = x();
let terms: Vec<Expression> = (1..=20)
.map(|i| pow(Expression::Symbol(var.clone()), integer(i)))
.collect();
let expr = add(terms);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < MODERATE_THRESHOLD,
"20-term polynomial integration took {:?}, expected < {:?}",
duration,
MODERATE_THRESHOLD
);
}
#[test]
fn test_rational_function_reasonable_time() {
let var = x();
let expr = mul(vec![
integer(1),
pow(
add(vec![
pow(Expression::Symbol(var.clone()), integer(2)),
integer(1),
]),
integer(-1),
),
]);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < MODERATE_THRESHOLD,
"Simple rational integration took {:?}, expected < {:?}",
duration,
MODERATE_THRESHOLD
);
}
#[test]
fn test_partial_fractions_moderate_time() {
let var = x();
let denominator = mul(vec![
add(vec![Expression::Symbol(var.clone()), integer(-1)]),
add(vec![Expression::Symbol(var.clone()), integer(-2)]),
add(vec![Expression::Symbol(var.clone()), integer(-3)]),
]);
let expr = mul(vec![integer(1), pow(denominator, integer(-1))]);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < MODERATE_THRESHOLD,
"Partial fractions integration took {:?}, expected < {:?}",
duration,
MODERATE_THRESHOLD
);
}
#[test]
fn test_trig_power_reduction_fast() {
let var = x();
let expr = pow(sin(Expression::Symbol(var.clone())), integer(2));
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < MODERATE_THRESHOLD,
"Trig power reduction took {:?}, expected < {:?}",
duration,
MODERATE_THRESHOLD
);
}
#[test]
fn test_by_parts_reasonable_time() {
let var = x();
let expr = mul(vec![
Expression::Symbol(var.clone()),
ln(Expression::Symbol(var.clone())),
]);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < MODERATE_THRESHOLD,
"Integration by parts took {:?}, expected < {:?}",
duration,
MODERATE_THRESHOLD
);
}
#[test]
fn test_substitution_fast() {
let var = x();
let expr = mul(vec![
Expression::Symbol(var.clone()),
sin(pow(Expression::Symbol(var.clone()), integer(2))),
]);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < MODERATE_THRESHOLD,
"U-substitution took {:?}, expected < {:?}",
duration,
MODERATE_THRESHOLD
);
}
#[test]
fn test_trig_product_moderate_time() {
let var = x();
let expr = mul(vec![
pow(sin(Expression::Symbol(var.clone())), integer(3)),
pow(cos(Expression::Symbol(var.clone())), integer(2)),
]);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < COMPLEX_THRESHOLD,
"Complex trig product took {:?}, expected < {:?}",
duration,
COMPLEX_THRESHOLD
);
}
#[test]
fn test_exponential_polynomial_product() {
let var = x();
let expr = mul(vec![
pow(Expression::Symbol(var.clone()), integer(3)),
exp(Expression::Symbol(var.clone())),
]);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < COMPLEX_THRESHOLD,
"Exponential polynomial product took {:?}, expected < {:?}",
duration,
COMPLEX_THRESHOLD
);
}
#[test]
fn test_does_not_hang_on_complex_integral() {
let var = x();
let expr = exp(pow(Expression::Symbol(var.clone()), integer(2)));
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < VERY_COMPLEX_THRESHOLD,
"Non-elementary integral took {:?}, expected < {:?} (possible hang)",
duration,
VERY_COMPLEX_THRESHOLD
);
}
#[test]
fn test_does_not_hang_on_non_integrable() {
let var = x();
let expr = mul(vec![
sin(Expression::Symbol(var.clone())),
pow(Expression::Symbol(var.clone()), integer(-1)),
]);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < VERY_COMPLEX_THRESHOLD,
"Non-elementary sine integral took {:?}, expected < {:?}",
duration,
VERY_COMPLEX_THRESHOLD
);
}
#[test]
fn test_table_lookup_instant() {
let var = x();
let test_cases = vec![
sin(Expression::Symbol(var.clone())),
cos(Expression::Symbol(var.clone())),
exp(Expression::Symbol(var.clone())),
pow(Expression::Symbol(var.clone()), integer(-1)), ];
for expr in test_cases {
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < SIMPLE_THRESHOLD,
"Table lookup took {:?}, expected < {:?}",
duration,
SIMPLE_THRESHOLD
);
}
}
#[test]
fn test_strategy_fallthrough_not_exponential() {
let var = x();
let expr = mul(vec![
integer(1),
pow(
add(vec![
pow(Expression::Symbol(var.clone()), integer(2)),
mul(vec![integer(2), Expression::Symbol(var.clone())]),
integer(1),
]),
integer(-1),
),
]);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < MODERATE_THRESHOLD,
"Strategy fallthrough took {:?}, expected < {:?}",
duration,
MODERATE_THRESHOLD
);
}
#[test]
fn test_large_sum_linear_scaling() {
let var = x();
let terms = vec![
sin(Expression::Symbol(var.clone())),
cos(Expression::Symbol(var.clone())),
exp(Expression::Symbol(var.clone())),
ln(Expression::Symbol(var.clone())),
pow(Expression::Symbol(var.clone()), integer(2)),
pow(Expression::Symbol(var.clone()), integer(3)),
mul(vec![integer(2), Expression::Symbol(var.clone())]),
pow(Expression::Symbol(var.clone()), integer(-1)),
mul(vec![integer(3), sin(Expression::Symbol(var.clone()))]),
mul(vec![integer(5), cos(Expression::Symbol(var.clone()))]),
];
let expr = add(terms);
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < MODERATE_THRESHOLD,
"10-term mixed integration took {:?}, expected < {:?}",
duration,
MODERATE_THRESHOLD
);
}
#[test]
fn test_risch_timeout_protection() {
let var = x();
let expr = exp(exp(Expression::Symbol(var.clone())));
let start = Instant::now();
let _result = integrate_with_strategy(&expr, var.clone(), 0);
let duration = start.elapsed();
assert!(
duration < VERY_COMPLEX_THRESHOLD,
"Risch algorithm took {:?}, expected < {:?} (possible timeout issue)",
duration,
VERY_COMPLEX_THRESHOLD
);
}
#[test]
fn test_multiple_integrations_no_memory_leak() {
let var = x();
let expr = pow(Expression::Symbol(var.clone()), integer(2));
let start = Instant::now();
for _ in 0..100 {
let _result = integrate_with_strategy(&expr, var.clone(), 0);
}
let duration = start.elapsed();
assert!(
duration < Duration::from_millis(100),
"100 simple integrations took {:?}, expected < 100ms (possible memory issue)",
duration
);
}