| 448 | // ∫(1+x²+x³)/((x−1)x(1+x²)²(1+x+x²)) previously returned a WRONG 0; the |
| 449 | // others returned an inert integral. Verify D(F) = integrand numerically. |
| 450 | describe('repeated-factor rational integration', () => { |
| 451 | const verify = (latex: string) => { |
| 452 | const integrand = engine.parse(latex); |
| 453 | const F = engine.expr(['Integrate', integrand, 'x']).evaluate(); |
| 454 | expect(F.has('Integrate')).toBe(false); // a closed form, not inert |
| 455 | expect(F.is(0)).toBe(false); // never the spurious 0 |
| 456 | const dF = engine.expr(['D', F, 'x']).evaluate(); |
| 457 | for (const x of [0.3, 1.7, -0.6, 2.3]) { |
| 458 | const a = dF.subs({ x }).N().re; |
| 459 | const b = integrand.subs({ x }).N().re; |
| 460 | if (a === undefined || b === undefined) continue; |
| 461 | expect(a).toBeCloseTo(b, 6); |
| 462 | } |
| 463 | }; |
| 464 | test('∫1/(x²(x+1)) dx', () => verify('\\frac{1}{x^2(x+1)}')); |
| 465 | test('∫1/(x(1+x²)²) dx', () => verify('\\frac{1}{x(1+x^2)^2}')); |
| 466 | test('∫(1+x²+x³)/((x-1)x(1+x²)²(1+x+x²)) dx (was wrongly 0)', () => |
| 467 | verify('\\frac{1+x^2+x^3}{(x-1)x(1+x^2)^2(1+x+x^2)}')); |
| 468 | }); |
| 469 | |
| 470 | // ∫xᵐ·(a+bx)^p — a radical or power of a linear function (Sqrt and Power |
| 471 | // forms, bare or explicit x-coefficient). Canonical √ is a `Sqrt` node, which |