Skip to content

Add five families of standard integrals (#233) - #675

Merged
Happypig375 merged 3 commits into
ASC-Community:masterfrom
Rafael-SOWNet:feat/inverse-trig-integrals
Aug 4, 2026
Merged

Happypig375 merged 3 commits into
ASC-Community:masterfrom
Rafael-SOWNet:feat/inverse-trig-integrals

Conversation

@Rafael-SOWNet

@Rafael-SOWNet Rafael-SOWNet commented Aug 3, 2026 •

Copy link
Copy Markdown
Member

Towards #233. Three categories
of my integral corpus sat at 0%, and none of them needed new machinery — each is a table
entry that was simply missing.

k / sqrt(a x² + b x + c)

Nothing integrated 1 / sqrt(1 - x^2) at all. It is an arcsine where a < 0 and a
logarithm where a > 0, returned as a piecewise on that sign, the way the rational
quadratic beside it in the table already is.

∫ 1/√(1 − x²) dx     ∫ 2/√(9 − x²) dx     ∫ 1/√(x² + 1) dx
∫ 1/√(x² − 1) dx     ∫ 1/√(2x + 3) dx  ← the a = 0 branch

sqrt(a x² + b x + c)

sqrt(1 - x^2) and sqrt(x^2 + 1) had no antiderivative either. Integrating by parts
once leaves the reciprocal form above, so it is written in terms of that rather than
worked out again. Only where the leading coefficient is a number other than zero — with
a = 0 this is the square root of something linear, which the power rule already
integrates, and there is a test that it is left alone.

An exponential times a sine or cosine

Integrating by parts twice returns the integral it started from, so the general solver
cycles rather than terminating. Solving that equation for the integral once gives a
closed form. The rate is read off B^(px + q) as p · ln(B), so any base and any linear
argument work — 2^x · cos(x) and e^(2x) · sin(3x) as much as e^x · sin(x).

The inverse trigonometric functions

Each is integration by parts against 1. The by-parts solver looks for a product to
split, so it never saw them.

∫ arcsin(x) dx   ∫ arccos(x) dx   ∫ arctan(x) dx   ∫ arccotan(x) dx

Any whole power of sine times any whole power of cosine

sin(x)^3 and sin(x)^2 * cos(x)^2 had no antiderivative, and sin(x)^2 and
cos(x)^2 each had one written out by hand. There are two cases and this does both:

  • An odd power gives a factor to peel off as the differential —
    sin^(2k+1) = sin · (1 - cos²)^k — leaving a polynomial in the other function, so the
    integral is a finite sum.
  • Both even, and there is no such factor, so the halved-angle identities go in and
    the result is integrated again. The total power halves each time, so it ends.

That subsumes the two hand-written squares, which are gone. Where both powers are odd
either substitution serves and the answers differ by a constant; the sine one is tried
first, because sin(x)cos(x) is written sin(x)^2/2 rather than the equally correct
-cos(x)^2/2, and two existing tests say so.

A skipped test that is no longer skipped

TestIntegrationByPartsNonPolynomial carried Skip = "TODO: integration by parts multiple times". Five of its six cases pass now — both exponential-times-wave ones and all
three inverse trigonometric ones — so the theory runs. The sixth, ln|x|^3, wants by
parts three times over; it is split into its own skipped test rather than holding the
other five back.

I kept that test's arctan expectation working by writing the answer with ln(abs(...))
rather than ln(...). The argument 1 + x² is positive so the abs is redundant, but it
matches both that expectation and the convention the rest of the table already uses.

Result

On the 117-problem corpus: 82 → 92 solved. Three categories go to 100% --
int:arcsin-form and int:by-parts-cyclic from 0%, int:trig-powers from 50% --
and int:trig-sub from 0% to 67%. No integral category is left at 0%. What remains
in trig-sub is 1/(x^2 sqrt(x^2 - 1)), which wants a substitution rather than a table
entry.

Testing

UnitTests 3889 passed / 0 failed, FSharpWrapperUnitTests 127 passed / 0 failed, both
netstandard2.0 and net7.0 build.

43 new tests. Every one checks by differentiating the answer back and comparing at
points, rather than against a printed form — and at points inside each integrand's own
domain
: 1/sqrt(x^2 - 1) is imaginary on (-1, 1), so testing it there would say
nothing about whether the answer is right. The last group asserts that the neighbouring
table entries are unaffected.

🤖 Generated with Claude Code

Three categories of the integral corpus sat at 0%. None of them needed new
machinery; each is a table entry that was missing.

  k / sqrt(a x^2 + b x + c). An arcsine where a < 0 and a logarithm where a > 0,
  returned as a piecewise on that sign the way the rational quadratic beside it
  already is. Nothing integrated 1 / sqrt(1 - x^2) at all before.

  An exponential times a sine or cosine. Integrating by parts twice returns the
  integral it started from, so the general solver cycles rather than terminating.
  Solving that equation for the integral once gives a closed form, and the rate is
  read off B^(px + q) as p * ln(B), so any base and any linear argument work.

  The inverse trigonometric functions. Each is integration by parts against 1, and
  the by-parts solver looks for a product to split, so it never saw them.

TestIntegrationByPartsNonPolynomial was skipped with "TODO: integration by parts
multiple times". Five of its six cases pass now -- both exponential-times-wave ones
and all three inverse trigonometric ones -- so it is no longer skipped. The sixth
wants by parts three times over and is split out into its own skipped test rather
than holding the rest back.

On the 117-problem corpus: 82 -> 88 solved. int:arcsin-form and int:by-parts-cyclic
go from 0% to 100%.

Every one of the 25 new tests checks by differentiating the answer back at points
inside the integrand's own domain -- 1/sqrt(x^2 - 1) is imaginary on (-1, 1), and
testing it there would say nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Aug 3, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.32%. Comparing base (90c00a8) to head (0be8877).
⚠️ Report is 51 commits behind head on master.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #675      +/-   ##
==========================================
- Coverage   80.99%   80.32%   -0.68%     
==========================================
  Files         155      156       +1     
  Lines       13687    12780     -907     
  Branches     1957     2088     +131     
==========================================
- Hits        11086    10265     -821     
+ Misses       1990     1916      -74     
+ Partials      611      599      -12     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

sin(x)^3 and sin(x)^2 * cos(x)^2 had no antiderivative; sin(x)^2 and cos(x)^2 each
had one written out by hand.

There are two cases and this does both. With an odd power there is a factor to peel
off as the differential -- sin^(2k+1) = sin * (1 - cos^2)^k -- which leaves a
polynomial in the other function, so the integral is a finite sum. With both powers
even there is no such factor, so the halved-angle identities go in and the result is
integrated again; the total power halves each time, so it ends.

That subsumes the two hand-written squares, which are gone.

Where both powers are odd either substitution serves and the two answers differ by a
constant. The sine one is tried first, because sin(x)cos(x) is written sin(x)^2/2
rather than -cos(x)^2/2, and two existing tests say so.

On the corpus: 88 -> 90 solved, int:trig-powers from 50% to 100%.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Rafael-SOWNet Rafael-SOWNet changed the title Add three families of standard integrals (#233) Add four families of standard integrals (#233) Aug 3, 2026
sqrt(1 - x^2) and sqrt(x^2 + 1) had no antiderivative. Integrating by parts once
leaves the reciprocal form this branch already added, so it is written in terms of
that rather than worked out again:

    integral sqrt(Q) = (2ax + b) sqrt(Q) / (4a) + (4ac - b^2)/(8a) * integral 1/sqrt(Q)

Only where the leading coefficient is a number other than zero. With a = 0 this is
the square root of something linear, which the power rule already integrates and
which dividing by a would break; there is a test that it is left alone.

On the corpus: 90 -> 92 solved, int:trig-sub from 0% to 67%. No integral category is
left at 0%. What remains there is 1/(x^2 sqrt(x^2 - 1)), which wants a substitution
rather than a table entry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Rafael-SOWNet Rafael-SOWNet changed the title Add four families of standard integrals (#233) Add five families of standard integrals (#233) Aug 3, 2026
@Happypig375
Happypig375 merged commit 70e39b2 into ASC-Community:master Aug 4, 2026
24 checks passed
@Rafael-SOWNet
Rafael-SOWNet deleted the feat/inverse-trig-integrals branch August 4, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants