use symplex::prelude::*;
fn assert_ftc(integrand: &Ex, var: &Ex, label: &str) {
let ctx = integrand.context();
let anti = integrand.integrate(var);
let anti_str = format!("{anti}");
assert!(
!anti_str.contains("Integral"),
"{label}: got unevaluated integral: {anti_str}"
);
let deriv = anti.diff(var);
let test_point = ctx.rational(7, 10);
let orig_val = integrand.subs(var, &test_point).eval_f64();
let deriv_val = deriv.subs(var, &test_point).eval_f64();
if let (Ok(o), Ok(d)) = (orig_val, deriv_val)
&& o.is_finite()
&& d.is_finite()
{
let diff = (o - d).abs();
let tol = 1e-8 * o.abs().max(1.0);
assert!(
diff < tol,
"{label}: FTC violated — integrand={o:.10}, d/dx(antideriv)={d:.10}, diff={diff:.2e}"
);
}
}
#[test]
fn integrate_sin_first_power() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.sin();
assert_ftc(&integrand, &x, "∫sin(x)dx");
}
#[test]
fn integrate_cos_first_power() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.cos();
assert_ftc(&integrand, &x, "∫cos(x)dx");
}
#[test]
fn integrate_sin_squared() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.sin().powi(2);
assert_ftc(&integrand, &x, "∫sin²(x)dx");
}
#[test]
fn integrate_cos_squared() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.cos().powi(2);
assert_ftc(&integrand, &x, "∫cos²(x)dx");
}
#[test]
fn integrate_sin_fourth() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.sin().powi(4);
assert_ftc(&integrand, &x, "∫sin⁴(x)dx");
}
#[test]
fn integrate_cos_fourth() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.cos().powi(4);
assert_ftc(&integrand, &x, "∫cos⁴(x)dx");
}
#[test]
fn integrate_sin_cubed() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.sin().powi(3);
assert_ftc(&integrand, &x, "∫sin³(x)dx");
}
#[test]
fn integrate_cos_cubed() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.cos().powi(3);
assert_ftc(&integrand, &x, "∫cos³(x)dx");
}
#[test]
fn integrate_sin_fifth() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = x.sin().powi(5);
assert_ftc(&integrand, &x, "∫sin⁵(x)dx");
}
#[test]
fn integrate_sin2_cos() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = &x.sin().powi(2) * &x.cos();
assert_ftc(&integrand, &x, "∫sin²(x)·cos(x)dx");
}
#[test]
fn integrate_sin_cos2() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = &x.sin() * &x.cos().powi(2);
assert_ftc(&integrand, &x, "∫sin(x)·cos²(x)dx");
}
#[test]
fn integrate_sin2_cos2() {
let ctx = Context::new();
let x = ctx.symbol("x");
let integrand = &x.sin().powi(2) * &x.cos().powi(2);
assert_ftc(&integrand, &x, "∫sin²(x)·cos²(x)dx");
}