Skip to content

Fix remaining CI failures: downstream MATLAB ordering & SymPy PyCall setup#1880

Merged
ChrisRackauckas merged 3 commits into
JuliaSymbolics:masterfrom
ChrisRackauckas-Claude:fix-ci-sympy-downstream
May 30, 2026
Merged

Fix remaining CI failures: downstream MATLAB ordering & SymPy PyCall setup#1880
ChrisRackauckas merged 3 commits into
JuliaSymbolics:masterfrom
ChrisRackauckas-Claude:fix-ci-sympy-downstream

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented May 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the remaining failing CI jobs on master (other than the Core reference tests handled in #1878).

1. test (Downstream, 1) — MATLAB target regression test

test/downstream/ParameterizedFunctions_MATLAB.jl compared the generated MATLAB string byte-for-byte. The order of operands within a commutative * follows SymbolicUtils' argument sort, which is benign but version-dependent: the expected string has u(1) * u(2) while current stable Julia (1.12) emits u(2) * u(1). (The test already looked up parameter indices to stay stable across parameter reorderings — this extends the same robustness to factor ordering.)

Fix: compare the two RHS rows modulo commutative +/* operand ordering (mirrors the build_targets tests from #1878).

Verified: passes locally 2/2 on Julia 1.12, and the Downstream CI job is green on this PR.

2. test (SymPy, 1) — PyCall/sympy precompilation

The SymPy group failed with ModuleNotFoundError: No module named 'sympy'. PyCall defaulted to the runner's system Python (/usr/bin/python3), which has no sympy, so SymbolicsSymPyExt failed to precompile. sympy.jl already tried ENV["PYTHON"]="" + Pkg.build("PyCall") to switch to the Conda.jl Python, but it ran after Pkg.instantiate() had already precompiled the extension against the system Python — too late, since PyCall's Python is fixed at load time.

Fix: set ENV["PYTHON"]="" before instantiation in activate_sympy_env (CI only), so PyCall builds against the Conda Python and SymPy's pyimport_conda installs sympy. CI logs confirm this now works (Installing sympy via the Conda sympy package... sympy-1.14.0, extension precompiles).

3. SymPy solver bug uncovered by fix #2 (sympy.jl:97)

Fixing the precompilation exposed a latent correctness bug that had been masked by the precompile failure. integrating_factor_solve guarded against SymPy returning an unevaluated Integral(...) with get_variables(solution, variable(:Integral)) — but the unevaluated integral comes back as an operation, not a variable, so the guard never fired and sympy_simplify mangled it into a wrong closed form.

Concretely symbolic_solve_ode(Dt(x) + sqrt(t)*x ~ sin(4t)*x^3, x, t) returned 1/sqrt(-2sin(4t) + C₁*exp((4//3)*t^(3//2))) (which does not satisfy the ODE — I verified the residual is non-zero) instead of nothing.

Fix: detect the unevaluated integral on the printed form of the solution and return nothing, so such ODEs correctly report no closed-form solution.

Verified: test/sympy.jl passes locally 16 passed / 1 broken (pre-existing) / 0 failed on Julia 1.12 with sympy 1.14.0, against a dev build of this branch (the solvable Bernoulli cases still solve correctly — no regression).

Not addressed here

  • benchmark: this job's benchmarks run fine; only the final PR-comment step fails with 403 Resource not accessible by integration, because GITHUB_TOKEN is read-only for fork PRs (a GitHub security restriction, independent of the permissions: block). It does not run on master and is not a code/test failure, so I left the workflow unchanged rather than risk masking real benchmark regressions. It will show red on this PR for the same fork-token reason.

Please ignore until reviewed by @ChrisRackauckas.

🤖 Generated with Claude Code

ChrisRackauckas and others added 2 commits May 29, 2026 22:52
The ParameterizedFunctions MATLABDiffEq regression test compared the generated
MATLAB string byte-for-byte. The order of operands within a commutative `*`
follows SymbolicUtils' argument sort, which is benign but version-dependent: the
expected string has `u(1) * u(2)` while current stable Julia (1.12) emits
`u(2) * u(1)`, so the test fails on master CI.

Compare the two RHS rows modulo commutative `+`/`*` operand ordering (the test
already looks up parameter indices to stay stable across parameter reorderings;
this extends the same robustness to factor ordering). Mirrors the build_targets
tests.

Verified test/downstream/ParameterizedFunctions_MATLAB.jl passes 2/2 on Julia 1.12.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The SymPy test group failed on CI with `ModuleNotFoundError: No module named
'sympy'`: PyCall defaulted to the runner's system Python (/usr/bin/python3),
which has no sympy, so SymbolicsSymPyExt failed to precompile.

sympy.jl already set `ENV["PYTHON"] = ""` + `Pkg.build("PyCall")` to switch to
the Conda.jl Python (where SymPy's `pyimport_conda` would install sympy), but it
ran too late — after `Pkg.instantiate()` had already precompiled the extension
against the system Python, and PyCall's Python config is fixed at load time.

Set `ENV["PYTHON"] = ""` before instantiation in `activate_sympy_env` (CI only)
so PyCall builds against the Conda Python from the start and the extension
precompiles successfully.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented May 30, 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 24.87%. Comparing base (c736678) to head (f60de33).
⚠️ Report is 107 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    #1880      +/-   ##
==========================================
- Coverage   26.12%   24.87%   -1.25%     
==========================================
  Files          56       57       +1     
  Lines        5356     5589     +233     
==========================================
- Hits         1399     1390       -9     
- Misses       3957     4199     +242     

☔ View full report in Codecov by Sentry.
📢 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.

…solve

When SymPy cannot find a closed-form antiderivative it returns an unevaluated
`Integral(...)`. In `integrating_factor_solve` this comes back through
`sympy_integrate` as a symbolic *operation* (function application), but the
guard tested `get_variables(solution, variable(:Integral))`, which only matches
a *variable* named `Integral` and so never fired. The unevaluated integral was
then mangled by `sympy_simplify` into a wrong closed form.

Concretely, `symbolic_solve_ode(Dt(x) + sqrt(t)*x ~ sin(4t)*x^3, x, t)` (a
Bernoulli equation whose linearization needs the non-elementary
∫ sin(4t) exp(-(4/3) t^(3/2)) dt) returned
`1 / sqrt(-2sin(4t) + C₁*exp((4//3)*t^(3//2)))`, which does not satisfy the ODE,
instead of `nothing`.

Detect the unevaluated integral on the printed form of the solution and bail
out, so such ODEs correctly report no closed-form solution. This was previously
masked on CI because the SymPy extension failed to precompile (see the PyCall
Conda fix); test/sympy.jl line 97 now passes for the right reason.

Verified test/sympy.jl passes locally (16 passed, 1 broken, 0 failed) on Julia
1.12 with sympy 1.14.0.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisRackauckas ChrisRackauckas marked this pull request as ready for review May 30, 2026 08:24
@ChrisRackauckas ChrisRackauckas merged commit 6dc4804 into JuliaSymbolics:master May 30, 2026
21 of 24 checks passed
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.

Simplify exp(x/2)^2

3 participants