Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/methods/rule_based/rules_utility_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,18 @@ s(u) = isa(SymbolicUtils.unwrap(u), SymbolicUtils.BasicSymbolic)
function eq(a, b)
a = SymbolicUtils.unwrap_const(a)
b = SymbolicUtils.unwrap_const(b)
return symbolic_iszero(SymbolicUtils.simplify(a - b))
d = a - b
# Plain simplify first (cheap). Expand only when needed so factored
# like-terms in larger rule conjuncts cancel. Expansion can hit Int
# gcd overflow in MultivariatePolynomials via SymbolicUtils.simplify_div;
# treat that as "not provably equal" instead of throwing.
symbolic_iszero(SymbolicUtils.simplify(d)) && return true
try
return symbolic_iszero(SymbolicUtils.simplify(d; expand = true))
catch err
err isa DivideError || err isa OverflowError || rethrow()
return false
end
end

symbolic_iszero(x) = begin
Expand Down
5 changes: 2 additions & 3 deletions test/difficult_baseline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
#
# Bisect against pre-PR-#53 (`e4fff44`):
# - Risch: 0 regressions. Long-standing engine domain limits only.
# - RuleBased: 1 regression on `(-1 + 4(x^5))/((1 + x + x^5)^2)` —
# issue #107.
# - RuleBased: 0 regressions once entry 142 is at (0, 0).
#
# Engine improvements should tighten the codes here on the same PR.

Expand Down Expand Up @@ -163,7 +162,7 @@ const DIFFICULT_BASELINE = NTuple{2,Int}[
(0, 1), # 139 1 / (-1 + x^4)
(1, 1), # 140 1 / (1 + x^4)
(0, 1), # 141 (x^2) / ((2 + 2x + x^2)^2)
(2, 0), # 142 (-1 + 4(x^5)) / ((1 + x + x^5)^2)
(0, 0), # 142 (-1 + 4(x^5)) / ((1 + x + x^5)^2)
(1, 1), # 143 1 / (5 + 2sin(x) - cos(x))
(2, 2), # 144 1 / (1 + a*cos(x))
(2, 1), # 145 1 / (1 + 2cos(x))
Expand Down
37 changes: 37 additions & 0 deletions test/methods/rule_based/test_rule2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,40 @@ end
@test eq(SymbolicIntegration.rule2(r8, (x) / (y*(2 + 2x)^3))[2], -3)
# denominator is a product
end

# Full conjunct of rule 1_1_1_7_7 needs expand-backed `eq`. See
# https://github.com/JuliaSymbolics/SymbolicIntegration.jl/issues/107
@testset "eq expands before compare (issue #107)" begin
@variables x
Pp = -1 + 4x^5
Qq = 1 + x + x^5
m = -2
lhs = (SymbolicIntegration.exponent_of(Pp, x) + m * SymbolicIntegration.exponent_of(Qq, x) + 1) *
SymbolicIntegration.ext_coeff(Qq, x, SymbolicIntegration.exponent_of(Qq, x)) * Pp
rhs = SymbolicIntegration.ext_coeff(Pp, x, SymbolicIntegration.exponent_of(Pp, x)) *
x^(SymbolicIntegration.exponent_of(Pp, x) - SymbolicIntegration.exponent_of(Qq, x)) *
((SymbolicIntegration.exponent_of(Pp, x) - SymbolicIntegration.exponent_of(Qq, x) + 1) * Qq +
(m + 1) * x * Symbolics.derivative(Qq, x))
@test eq(lhs, rhs)

expected = -x / (1 + x + x^5)
result = integrate((4x^5 - 1) / (x^5 + x + 1)^2, x, RuleBasedMethod())
@test !SymbolicIntegration.contains_int(result)
@test isequal(simplify(result - expected; expand = true), 0)
end

# Expanding in `eq` can DivideError via SymbolicUtils.simplify_div; the guard
# must keep RuleBased from throwing on Hebisch Problems #2.
# See https://github.com/JuliaSymbolics/SymbolicIntegration.jl/pull/149
@testset "eq expand path does not throw (Hebisch #2)" begin
@variables x
f = (2 - x^2) * exp(x / (x^2 + 2)) / (x^3 + 2x)
threw = false
try
integrate(f, x, RuleBasedMethod())
catch
threw = true
end
# Unevaluated is fine (main returned fail code 2); throwing is not.
@test !threw
end
4 changes: 2 additions & 2 deletions test/rundifficulttests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ close(output_io)
println("Test results saved to: ", output_file)

# Per-integral expected-outcome baseline. Bisect (commit-by-commit, against
# the pre-PR-#53 `e4fff44` snapshot) showed zero Risch regressions and a
# single RuleBased regression (issue #107). Everything else flagged
# the pre-PR-#53 `e4fff44` snapshot) showed zero Risch regressions once the
# RuleBased baseline matches current engine behaviour. Everything else flagged
# `[ fail ]` / `[ fail?]` is a long-standing engine domain limit, not a
# regression — see test/difficult_baseline.jl for the full list and the
# rationale. CI gates on regressions vs the baseline rather than the
Expand Down
Loading