Repository: sympy/sympy
File: sympy/integrals/tests/test_manual.py (Python)

Code before:
    res_complex = manualintegrate(term_complex, x)
    assert simplify(diff(res_complex, x) - term_complex) == 0

    # 3. Recursive Case: n = -5
    # We match the EXACT output format here to avoid simplification issues
    # simplify().rewrite() struggles to equate sqrt((x**2 + 1)**3) with (x**2 + 1)**(3/2).
    term_n5 = 1/(x**2 + 1)**(S(5)/2)
    res_n5 = manualintegrate(term_n5, x)
    expected = x/(3*sqrt((x**2 + 1)**3)) + 2*x/(3*sqrt(x**2 + 1))
    assert res_n5 == expected

    assert manualintegrate(5/(x**2 + 1)**(S(5)/2), x) == 5*expected

    # 4. Symbolic Verification (General Case)
    # here as well, simplify cant be sure of a being nonzero
    # So I am declaring it as such because thats the only
    # case for quadratics anyways
    term_n3 = f/(a*x**2 + b*x + c)**(S(3)/2)
    res_n3 = manualintegrate(term_n3, x)
    assert simplify(diff(res_n3, x) - term_n3) == 0

    # The general recursive case (n = -5) generates a massive expression
    # that simplify() currently cannot reduce to zero.
    # term_n5 = f/(a*x**2 + b*x + c)**(S(5)/2)
    # res_n5 = manualintegrate(term_n5, x)
    # assert simplify(diff(res_n5, x) - term_n5) == 0

def test_mul_pow_derivative():
    assert_is_integral_of(x*sec(x)*tan(x), x*sec(x) - log(tan(x) + sec(x)))
    assert_is_integral_of(x*sec(x)**2, x*tan(x) + log(cos(x)))
    assert_is_integral_of(x**3*Derivative(f(x), (x, 4)),
                          x**3*Derivative(f(x), (x, 3)) - 3*x**2*Derivative(f(x), (x, 2)) +
                          6*x*Derivative(f(x), x) - 6*f(x))


Review comment (refactor):
In this case the formula comes out with this factor that does not simplify to zero:
```
In [20]: t = factor(manualintegrate(e, x).diff(x) - e, deep=True).args[-2]

In [21]: t
Out[21]: 
                                                                                 ___________________
        ________________          ________________        ________________      ╱                 3 
   2   ╱    2                    ╱    2                  ╱    2                ╱  ⎛   2          ⎞  
a⋅x ⋅╲╱  a⋅x  + b⋅x + c  + b⋅x⋅╲╱  a⋅x  + b⋅x + c  + c⋅╲╱  a⋅x  + b⋅x + c  - ╲╱   ⎝a⋅x  + b⋅x + c⎠  
```
We can bring that to a more recognisable form:
```python
In [27]: s = list(t.atoms(Pow))[-1]

In [29]: s
Out[29]: 
   ________________
  ╱    2           
╲╱  a⋅x  + b⋅x + c 

In [30]: t.collect(s)
Out[30]: 
                          ___________________
                3/2      ╱                 3 
⎛   2          ⎞        ╱  ⎛   2          ⎞  
⎝a⋅x  + b⋅x + c⎠    - ╲╱   ⎝a⋅x  + b⋅x + c⎠  

In [31]: simplify(t.collect(s))
Out[31]: 
                          ___________________
                3/2      ╱                 3 
⎛   2          ⎞        ╱  ⎛   2          ⎞  
⎝a⋅x  + b⋅x + c⎠    - ╲╱   ⎝a⋅x  + b⋅x + c⎠  
```
Now why does this not simplify? The issue is that `(x**3)**(1/2)` is not the same as `x**(3/2)` in general:
```python
In [34]: (S(-1)**3)**(S(1)/2)
Out[34]: ⅈ

In [35]: S(-1)**(S(3)/2)
Out[35]: -ⅈ
```
So these two expressions are not equivalent if the quadratic term is negative. That makes me wonder though whether this formula should be considered correct in general or if some restrictions are needed for it to be valid.

Here for example:
```python
In [45]: e2 = e.subs({f:1, a:-1, b:-1, c:-1})

In [46]: e2
Out[46]: 
        1        
─────────────────
              5/2
⎛   2        ⎞   
⎝- x  - x - 1⎠   

In [47]: E2 = manualintegrate(e2, x).diff(x)

In [48]: e2.subs(x, -1)
Out[48]: -ⅈ

In [49]: E2.subs(x, -1)
Out[49]: 
-7⋅ⅈ 
─────
  9 
```

Code after:

    # Complex Numeric Case (x^2 + 2x + 2)
    assert_is_integral_of(
        1/(x**2 + 2*x + 2)**(S(3)/2),
        (4*x + 4)/(4*(x**2 + 2*x + 2)**(S(1)/2))
    )

    # Recursive Case: n = -5
    assert_is_integral_of(
        1/(x**2 + 1)**(S(5)/2),
        x/(3*(x**2 + 1)**(S(3)/2)) + 2*x/(3*(x**2 + 1)**(S(1)/2))
    )
    assert_is_integral_of(
        5/(x**2 + 1)**(S(5)/2),
        5*x/(3*(x**2 + 1)**(S(3)/2)) + 10*x/(3*(x**2 + 1)**(S(1)/2))
    )

    # For even larger n
    assert_is_integral_of(
        1/(x**2 + 1)**(S(7)/2),
        x/(5*(x**2 + 1)**(S(5)/2)) +
        4*x/(15*(x**2 + 1)**(S(3)/2)) +
        8*x/(15*(x**2 + 1)**(S(1)/2))
    )

    # Symbolic Verification (General Case)
    term_n5 = f/(a*x**2 + b*x + c)**(S(5)/2)
    intg_result = manualintegrate(term_n5, x)
    assert factor(intg_result.diff(x) - term_n5) == 0

def test_mul_pow_derivative():
    assert_is_integral_of(x*sec(x)*tan(x), x*sec(x) - log(tan(x) + sec(x)))
    assert_is_integral_of(x*sec(x)**2, x*tan(x) + log(cos(x)))
    assert_is_integral_of(x**3*Derivative(f(x), (x, 4)),
                          x**3*Derivative(f(x), (x, 3)) - 3*x**2*Derivative(f(x), (x, 2)) +
                          6*x*Derivative(f(x), x) - 6*f(x))