Skip to content

refactor(SymplecticRK): migrate drift-kick methods to generic Symplec…#3473

Merged
ChrisRackauckas merged 5 commits intoSciML:masterfrom
singhharsh1708:symplectic-tableau-refactor
Apr 20, 2026
Merged

refactor(SymplecticRK): migrate drift-kick methods to generic Symplec…#3473
ChrisRackauckas merged 5 commits intoSciML:masterfrom
singhharsh1708:symplectic-tableau-refactor

Conversation

@singhharsh1708
Copy link
Copy Markdown
Contributor

🚀 SymplecticRK Refactor: Generic Tableau-Based Implementation

This PR introduces a major refactor of the Symplectic Runge-Kutta (SymplecticRK) implementation by replacing multiple per-method implementations with a generic, tableau-driven design.

The previous implementation had significant duplication across methods, with separate cache structs and perform_step! implementations for each algorithm. Since all symplectic methods follow the same drift–kick pattern, this refactor unifies them under a single abstraction.

At the core of this change is the introduction of a generic SymplecticTableau structure that stores method coefficients (a, b) as NTuples. This replaces all per-method constant cache structs while preserving the exact numerical behavior of each algorithm.

The caching system has been simplified by replacing multiple cache types (like Symplectic2Cache, Symplectic3Cache, etc.) with a single SymplecticGenericCache. This significantly reduces boilerplate and makes the system easier to maintain.

The biggest improvement comes from replacing ~20 different perform_step! implementations with just two generic versions (OOP and IIP). These implementations are fully driven by the tableau coefficients and follow a unified loop structure:

for i in 1:N
    u  += dt * b[i] * ku   # drift
    kdu = f1(du, u, ...)
    du += dt * a[i] * kdu  # kick
    ku  = f2(du, u, ...)
end

This abstraction captures the exact structure shared by all symplectic integrators, making the code both mathematically clear and extensible.

Additionally, algorithm dispatch has been simplified using lightweight _symplectic_tableau mappings, where each algorithm maps to its tableau in a single line.

A bug in the CandyRoz4 implementation was also fixed, where it previously used an incorrect cache (McAte4 instead of CandyRoz4).

Impact

  • symplectic_perform_step.jl reduced from ~2183 lines to ~340 lines
  • symplectic_caches.jl reduced from ~554 lines to ~175 lines
  • symplectic_tableaus.jl reduced from ~817 lines to ~430 lines

This results in a significant reduction in code duplication and improves readability, maintainability, and extensibility.

Testing

All tests pass successfully:

  • Convergence tests passing (with a few pre-existing broken cases)
  • SymplecticRK tests: 160/160 passing
  • JET tests passing
  • Aqua QA checks passing (including fix for unbound type parameters)

Pre-existing allocation test issues remain unchanged.

Summary

This refactor transforms the SymplecticRK implementation from a method-specific design into a fully generic, coefficient-driven system. It simplifies the codebase, removes redundancy, and aligns the implementation more closely with the mathematical structure of symplectic integrators.

Comment thread lib/OrdinaryDiffEqSymplecticRK/src/symplectic_caches.jl Outdated
Comment on lines +153 to +167
# Mapping from algorithm to tableau constructor
_symplectic_tableau(::PseudoVerletLeapfrog, T, T2) = PseudoVerletLeapfrogConstantCache(T, T2)
_symplectic_tableau(::McAte2, T, T2) = McAte2ConstantCache(T, T2)
_symplectic_tableau(::Ruth3, T, T2) = Ruth3ConstantCache(T, T2)
_symplectic_tableau(::McAte3, T, T2) = McAte3ConstantCache(T, T2)
_symplectic_tableau(::CandyRoz4, T, T2) = CandyRoz4ConstantCache(T, T2)
_symplectic_tableau(::McAte4, T, T2) = McAte4ConstantCache(T, T2)
_symplectic_tableau(::CalvoSanz4, T, T2) = CalvoSanz4ConstantCache(T, T2)
_symplectic_tableau(::McAte42, T, T2) = McAte42ConstantCache(T, T2)
_symplectic_tableau(::McAte5, T, T2) = McAte5ConstantCache(T, T2)
_symplectic_tableau(::Yoshida6, T, T2) = Yoshida6ConstantCache(T, T2)
_symplectic_tableau(::KahanLi6, T, T2) = KahanLi6ConstantCache(T, T2)
_symplectic_tableau(::McAte8, T, T2) = McAte8ConstantCache(T, T2)
_symplectic_tableau(::KahanLi8, T, T2) = KahanLi8ConstantCache(T, T2)
_symplectic_tableau(::SofSpa10, T, T2) = SofSpa10ConstantCache(T, T2)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not specialized

Comment thread lib/OrdinaryDiffEqSymplecticRK/src/symplectic_caches.jl Outdated
Comment thread lib/OrdinaryDiffEqSymplecticRK/src/symplectic_caches.jl Outdated
@ChrisRackauckas ChrisRackauckas merged commit 8597d06 into SciML:master Apr 20, 2026
83 of 89 checks passed
ChrisRackauckas-Claude pushed a commit to ChrisRackauckas-Claude/OrdinaryDiffEq.jl that referenced this pull request Apr 21, 2026
Runs Runic.format_file on the 5 files flagged by the runic CI check.
The formatting drift was introduced by recent merges (most notably
the SymplecticRK refactor in SciML#3473) and now blocks format-check on
every open PR.

No semantic changes.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
ChrisRackauckas added a commit that referenced this pull request Apr 21, 2026
Runs Runic.format_file on the 5 files flagged by the runic CI check.
The formatting drift was introduced by recent merges (most notably
the SymplecticRK refactor in #3473) and now blocks format-check on
every open PR.

No semantic changes.

Co-authored-by: ChrisRackauckas-Claude <accounts@chrisrackauckas.com>
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.

2 participants