Skip to content

perf(metric): pre-apply cancel() before Simp.apply to fix SymPy 1.13 slowdown (#576)#591

Open
utiberious wants to merge 2 commits intopygae:masterfrom
utiberious:fix/issue-576-metric-cancel-prepass
Open

perf(metric): pre-apply cancel() before Simp.apply to fix SymPy 1.13 slowdown (#576)#591
utiberious wants to merge 2 commits intopygae:masterfrom
utiberious:fix/issue-576-metric-cancel-prepass

Conversation

@utiberious
Copy link
Copy Markdown
Contributor

@utiberious utiberious commented Apr 3, 2026

Summary

Fixes #576 at the library level by pre-applying cancel() before each Simp.apply() call in normalize_metric and Christoffel_symbols.

  • cancel() performs polynomial GCD cancellation to reduce expression size
  • This shrinks the expression tree before the expensive simplify() (or any user-configured mode) traverses it
  • SymPy 1.13 added a slow .replace() traversal in TR3/fu.py, triggered by both simplify() and trigsimp() -- reducing node count before that traversal cuts runtime dramatically

Affected call sites (~72 total during Ga.build(..., norm=True)):

  • normalize_metric: 18 calls (9 de entries + 9 g entries)
  • Christoffel_symbols mode 1: 27 calls
  • Christoffel_symbols mode 2: 27 calls

Relation to PR #590

PR #590 is a minimal fix scoped to the example file (curvi_linear_latex.py) that swaps simplify -> trigsimp(method='old') around the slow Ga.build call. This PR is the library-level complement ("option 2") that benefits all coordinate systems and user code, not just that one example.

Test plan

  • CI passes on Python 3.10 / 3.11 / 3.12
  • derivatives_in_prolate_spheroidal_coordinates() completes well within the 600 s notebook timeout
  • All existing nbval notebook outputs remain unchanged (canonical forms like sin(2η)/2 preserved -- cancel does not apply trig identities)

…c and Christoffel_symbols

SymPy 1.13 introduced a slow .replace() traversal in TR3/fu.py that is
triggered by both simplify() and trigsimp() (default method).  Simp.apply
is called ~72 times during Ga.build(..., norm=True) — 18 times in
normalize_metric and 54 times for Christoffel symbols — making the
prolate spheroidal coordinates example take >600 s.

Wrapping each expression with cancel() before passing it to Simp.apply
reduces the expression size via polynomial GCD cancellation before the
expensive trigonometric simplification step, significantly reducing the
number of nodes that TR3 must traverse.

This is the library-level fix for issue pygae#576 (option 2), complementing
the minimal example-file fix in PR pygae#590.
… change

cancel() on purely polynomial Christoffel symbol expressions can change
their representation (e.g. expanded 4G^2M^2 - 4GMc^2r + c^4r^2 becomes
4G^2M^2 + c^2r(-4GM + c^2r)) because cancel() uses Poly arithmetic
internally, which may normalize polynomials differently.  When simplify()
then runs on the altered form it produces a different output, breaking
the stored gr_metrics notebook output.

The cancel() pre-pass is retained only in normalize_metric, where the
inputs are genuine fractions (divided by e_norm) rather than polynomial
sums, so cancel() there reduces actual rational factors without changing
the polynomial normal form.
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.

Investigate CI slowdown since Python 3.12 bump

1 participant