use symplex::prelude::*;
fn assert_ftc(integrand: &Ex, var: &Ex, label: &str) {
let ctx = integrand.context();
let anti = integrand.integrate(var);
let s = format!("{anti}");
assert!(
!s.contains("Integral"),
"{label}: got unevaluated integral: {s}"
);
let deriv = anti.diff(var);
let test_point = ctx.rational(7, 10);
if let (Ok(o), Ok(d)) = (
integrand.subs(var, &test_point).eval_f64(),
deriv.subs(var, &test_point).eval_f64(),
) && o.is_finite()
&& d.is_finite()
{
assert!(
(o - d).abs() < 1e-6 * o.abs().max(1.0),
"{label}: FTC failed — integrand={o}, deriv={d}, diff={}",
(o - d).abs()
);
}
}
#[test]
fn integrate_sec_tan() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = &x.sin() / &x.cos().powi(2);
assert_ftc(&integrand, &x, "∫ sec(x)tan(x) dx");
}
#[test]
fn integrate_csc_cot() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = &x.cos() / &x.sin().powi(2);
assert_ftc(&integrand, &x, "∫ csc(x)cot(x) dx");
}
#[test]
fn integrate_1_over_sqrt_1_plus_x2() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = &ctx.int(1) / &(&x.powi(2) + 1).sqrt();
assert_ftc(&integrand, &x, "∫ 1/√(1+x²) dx");
}
#[test]
fn integrate_1_over_sqrt_4x2_plus_1() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = &ctx.int(1) / &(&(&x.powi(2) * &ctx.int(4)) + 1).sqrt();
assert_ftc(&integrand, &x, "∫ 1/√(4x²+1) dx");
}
#[test]
fn integrate_1_over_sqrt_quadratic_with_linear_term() {
let ctx = Context::new();
let x = ctx.symbol("x");
let quad = &(&x.powi(2) + &(&ctx.int(2) * &x)) + 5;
let integrand = &ctx.int(1) / &quad.sqrt();
assert_ftc(&integrand, &x, "∫ 1/√(x²+2x+5) dx");
}
#[test]
fn integrate_1_over_sqrt_quadratic_neg_a() {
let ctx = Context::new();
let x = ctx.symbol("x");
let quad = &ctx.int(3) - &(&x.powi(2) * &ctx.int(2));
let integrand = &ctx.int(1) / &quad.sqrt();
assert_ftc(&integrand, &x, "∫ 1/√(3-2x²) dx");
}
#[test]
fn integrate_x_over_sqrt_1_plus_x2() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = &x / &(&x.powi(2) + 1).sqrt();
assert_ftc(&integrand, &x, "∫ x/√(1+x²) dx");
}
#[test]
fn integrate_x_over_sqrt_quadratic_with_linear_term() {
let ctx = Context::new();
let x = ctx.symbol("x");
let quad = &(&x.powi(2) + &(&ctx.int(2) * &x)) + 5;
let integrand = &x / &quad.sqrt();
assert_ftc(&integrand, &x, "∫ x/√(x²+2x+5) dx");
}