symplex 0.2.0

Exact symbolic mathematics for Rust: calculus, summation, solving, linear algebra, transforms, compile-time dimensional analysis, and Rust/C code generation
Documentation
//! Tests for ∫ poly(x)/√(ax²+bx+c) dx and sec·tan / csc·cot integration forms.

use symplex::prelude::*;

/// Fundamental Theorem of Calculus check: differentiate the antiderivative
/// and compare numerically against the original integrand at a test point.
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()
        );
    }
}

// ═══════════════════════════════════════════════════════════════════════════
// Part 1: sec·tan and csc·cot
// ═══════════════════════════════════════════════════════════════════════════

#[test]
fn integrate_sec_tan() {
    let ctx = Context::new();
    // ∫ sin(x)/cos²(x) dx = sec(x)·tan(x) → 1/cos(x)
    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();
    // ∫ cos(x)/sin²(x) dx = csc(x)·cot(x) → -1/sin(x)
    let x = ctx.symbol("x");
    let integrand = &x.cos() / &x.sin().powi(2);
    assert_ftc(&integrand, &x, "∫ csc(x)cot(x) dx");
}

// ═══════════════════════════════════════════════════════════════════════════
// Part 2: ∫ 1/√(ax²+bx+c) dx — base cases (I₀)
// ═══════════════════════════════════════════════════════════════════════════

#[test]
fn integrate_1_over_sqrt_1_plus_x2() {
    let ctx = Context::new();
    // ∫ 1/√(1+x²) dx = asinh(x)
    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();
    // ∫ 1/√(4x²+1) dx — coefficient a=4, b=0, c=1
    // Should use completing-the-square path with a>0, d>0
    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();
    // ∫ 1/√(x²+2x+5) dx — completing the square yields (x+1)² + 4
    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();
    // ∫ 1/√(3-2x²) dx — a=-2, b=0, c=3 → asin form
    // Using test point x=0.7 gives 3-2*(0.49) = 2.02 > 0, good.
    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");
}

// ═══════════════════════════════════════════════════════════════════════════
// Part 3: ∫ x/√(ax²+bx+c) dx (I₁)
// ═══════════════════════════════════════════════════════════════════════════

#[test]
fn integrate_x_over_sqrt_1_plus_x2() {
    let ctx = Context::new();
    // ∫ x/√(1+x²) dx = √(1+x²)   (b=0, so just √R/a)
    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();
    // ∫ x/√(x²+2x+5) dx = √(x²+2x+5) - I₀ term
    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");
}