Skip to content

fix: expand in eq so RuleBased matches Apostol (4x⁵−1)/(x⁵+x+1)² (#107) - #149

Draft
ChrisRackauckas-Claude wants to merge 5 commits into
JuliaSymbolics:mainfrom
ChrisRackauckas-Claude:agent/107-rulebased-eq-expand
Draft

ChrisRackauckas-Claude wants to merge 5 commits into
JuliaSymbolics:mainfrom
ChrisRackauckas-Claude:agent/107-rulebased-eq-expand

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Summary

Rule 1_1_1_7_7 failed to match ∫(4x⁵−1)/(x⁵+x+1)² dx because the shared predicate eq compared with simplify(a-b) only. The full rule conjunct (not the smaller eq(x*(1+5x⁴), x+5x⁵), which already succeeded on main) stayed non-zero without expansion, so the engine returned the integrand unevaluated. eq now tries plain simplify first, then simplify(a-b; expand=true) only when needed, and treats DivideError/OverflowError from the expand path as “not equal” so callers do not throw. The rule then fires and yields −x/(1+x+x⁵). Triage diagnosis confirmed; independent review’s blocking Hebisch #2 regression is guarded.

Verification

# Repro on main (before fix)
# → No rule found … contains_int: true

# Fail-before (unguarded expand-always eq, tests present)
eq(#107 conjunct) = true
#107 result = (-x) / (1 + x + x^5)
Hebisch#2 THROWS: DivideError: integer division error

# Pass-after (guarded: plain simplify, then expand with catch)
eq(#107 conjunct) = true
#107 result = (-x) / (1 + x + x^5)
Hebisch#2 result = ∫((2exp(x / (2 + x^2)) - exp(x / (2 + x^2))*(x^2)) / (2x + x^3), x)
# minimal eqrepro: eq(lhs,rhs)=false (no throw)

# Full suite
julia --project -e 'using Pkg; Pkg.test()'
# Test Summary:          | Pass  Broken  Total     Time
# SymbolicIntegration.jl |  227       1    228  7m47.6s
# Testing SymbolicIntegration tests passed

typos clean on touched files. Difficult gate: no RuleBased regressions. Independent review corpus (~2,700 integrals): 4 better, none worse on solved/unsolved; Hebisch #2 exception fixed by the guard.

What was NOT verified

  • Julia pre/1.13 CI lane for baseline entry 142.
  • Whether other expand-path exceptions beyond DivideError/OverflowError exist (only those two are caught, per review).
  • Did not re-tighten unrelated Risch baseline improvements listed by the difficult runner.

Reviewer pushback

  • Catching only DivideError/OverflowError may miss related MP/SymbolicUtils failures; widen only with evidence.
  • Plain-first ordering changes when expand runs; worth watching for form-only diffs.
  • Retrospective baseline comments were trimmed; entry (0,0) alone records the outcome.

Closes #107

Please ignore this draft until reviewed by @ChrisRackauckas.

Harness: Cursor Agent CLI 2026.10.01-14929f9; model: auto; transcript: /home/crackauc/sandbox/agent-jobs/ib-su/SymbolicIntegration.jl/jobs/107-cursor/log.txt on amdci2.julia.csail.mit.edu

Risk assessment

Orchestrated and reviewed from Claude Code (model: claude-opus-5-5[1m]), issue-backlog lane ib-su: https://claude.ai/code/session_012Dbjay5j3orvRFDeF3gebh

Risk assessment

  • Risk: low
  • Blast radius: Only RuleBasedMethod integration results. eq is an internal predicate. It is not exported; the only exports are AbstractIntegrationMethod, RischMethod, RuleBasedMethod, integrate and reload_rules. But many rule conditions call it, so rules that failed to match before can now match. Downstream users could see newly solved integrals or a different but equivalent antiderivative where an expand-backed eq now returns true. Integrals whose expanded simplify throws DivideError/OverflowError now count as "not equal" and come back unevaluated instead of throwing. The rethrow() keeps every other exception type visible. Nothing in the public API changes, so this is not a SemVer-major change; it is a behavior improvement. Each eq call that fails the plain check now runs a second simplify(...; expand=true), which is a possible cost on the rule-matching hot path. CI timings on the difficult lanes look in line with main, but nobody benchmarked this directly.
  • Evidence: On head 94c4831, the whole CI workflow passes: the 27 easy/difficult/qa jobs across Julia 1.10, 1, and pre on ubuntu, macOS and Windows. Spell Check and Documentation build also pass. Two checks fail, both in the SymbolicIntegrationMaxima sublibrary workflow: Julia 1 - qa - ubuntu-latest and Julia 1.10 - qa - ubuntu-latest. Both fail with empty intersection between SymbolicIntegrationMaxima@0.3.0 and project compatibility 0.2. That workflow fails the same way, in the same two jobs, on main's tip 4e27faa (run 36311276372), and it has been red since 278475d (Release SymbolicIntegrationMaxima v0.3.0). The failures are pre-existing, and the PR touches none of those files, so they are not a regression. The difficult runner prints no "regressions vs baseline" line on any lane. The "improvements" lines on head ([6], [129], [132], [133] RB; [3], [26], [27], [49], [55] Risch) match main's 1.10 ubuntu run exactly. Entry 142 goes from RB=2 to RB=0, which tightens the baseline and still passes on every lane, including pre. No tests were weakened. Two testsets were added, both inside the easy group: one for [RuleBased] regression on (4x⁵ − 1)/(x⁵+x+1)² since PR #53 #107 (eq on the full conjunct, plus the integral solving and verifying) and a no-throw test for Hebisch Fix complex root integration - restore arctangent terms #2. The no-throw test uses try/catch with a threw flag and then asserts !threw, which is an actual assertion, not a swallowed error. Non-public internals: none new. SymbolicUtils.unwrap_const was already in use, and simplify(...; expand=true) is SymbolicUtils' public, documented keyword. Not disclosed or out of date in the description:
    • It lists the "Julia pre/1.13 lane for entry 142" as unverified, but the CI pre difficult lanes pass.
    • The rewritten comment in test/rundifficulttests.jl ("zero Risch regressions once the RuleBased baseline matches current engine behaviour") garbles the bisect note.
    • difficult_baseline.jl still has a slightly retrospective line ("0 regressions once entry 142 is at (0, 0)").
    • The workaround for the underlying Int overflow in SymbolicUtils simplify_div is a catch-and-return-false; the overflow itself is left unfixed and nothing has been filed upstream.
    • No human review has happened.
  • Independent review: Devin CLI (Mac) / fusion-claude-opus-5-5-high-sidekick-swe-2-medium rated it low, medium confidence: the change is small and guarded, it fixes [RuleBased] regression on (4x⁵ − 1)/(x⁵+x+1)² since PR #53 #107 with a fail-before/pass-after test, and every CI lane is clean apart from the Maxima-sublibrary QA failure that main already has. The remaining uncertainty is how the extra expand pass and the narrow exception swallowing in a shared rule predicate behave on integrands outside the tested corpora.
  • Merge: auto-merge candidate. It meets the no-test-regressions bar. Non-blocking nits:
    • Update the stale "pre lane not verified" line in the description.
    • Fix the garbled comment in rundifficulttests.jl.
    • Optionally file the SymbolicUtils simplify_div overflow upstream.

🤖 Risk assessment posted by an AI agent (fleet master) — harness: Devin CLI (Mac) / fusion-claude-opus-5-5-high-sidekick-swe-2-medium; dispatched by Devin CLI 3000.11.3 (Mac) fleet-master caretaker, model Fusion (claude-opus-5-5 medium + swe-2 medium)
Conversation: local transcript ~/.local/share/devin/cli/transcripts/speckle-whale.json (Chris's Mac)

ChrisRackauckas and others added 3 commits October 1, 2026 15:33
Plain simplify left x*(1+5x^4) factored, so rule 1_1_1_7_7 never
matched the Apostol integrand in issue JuliaSymbolics#107.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/ib-su/SymbolicIntegration.jl/jobs/107-cursor/log.txt on amdci2.julia.csail.mit.edu
…ymbolics#107)

Update the difficult baseline entry and add an eq/integrate regression
in test_rule2.jl.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/ib-su/SymbolicIntegration.jl/jobs/107-cursor/log.txt on amdci2.julia.csail.mit.edu
…is fixed

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/ib-su/SymbolicIntegration.jl/jobs/107-cursor/log.txt on amdci2.julia.csail.mit.edu
@codecov-commenter

codecov-commenter commented Oct 1, 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 50.75%. Comparing base (8647f0d) to head (94c4831).
⚠️ Report is 27 commits behind head on main.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #149      +/-   ##
==========================================
- Coverage   50.98%   50.75%   -0.24%     
==========================================
  Files          23       23              
  Lines        4309     4262      -47     
==========================================
- Hits         2197     2163      -34     
+ Misses       2112     2099      -13     

☔ 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.

ChrisRackauckas and others added 2 commits October 1, 2026 19:16
Try plain simplify first; expand only when needed. Treat Int gcd
overflow from expand as not-equal so Hebisch #2 stays unevaluated
instead of throwing. Also avoids worst-case expand cost.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/ib-su/SymbolicIntegration.jl/jobs/107-cursor/log.txt on amdci2.julia.csail.mit.edu
Also drop retrospective JuliaSymbolics#107 wording from baseline comments and
clarify the 1_1_1_7_7 conjunct regression test.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Cursor Agent <noreply@cursor.com>
Agent-Harness: Cursor Agent CLI 2026.10.01-14929f9
Agent-Model: auto
Agent-Session: local session, transcript at /home/crackauc/sandbox/agent-jobs/ib-su/SymbolicIntegration.jl/jobs/107-cursor/log.txt on amdci2.julia.csail.mit.edu
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.

[RuleBased] regression on (4x⁵ − 1)/(x⁵+x+1)² since PR #53

3 participants