Skip to content

Adding Symplectic Integrators#1411

Open
JacobHass8 wants to merge 9 commits into
boostorg:developfrom
JacobHass8:symplectic-integrators
Open

Adding Symplectic Integrators#1411
JacobHass8 wants to merge 9 commits into
boostorg:developfrom
JacobHass8:symplectic-integrators

Conversation

@JacobHass8

@JacobHass8 JacobHass8 commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Adds symplectic solvers for ODE systems with a conserved quantity (i.e. energy). This was a requested scipy feature (see #303 and scipy/scipy#12690). I'd ultimately like to merge this into scipy using cython. I'm still working on this and have a couple of features I'd like to add:

  • 6th order method from here
  • Kahan summation
  • Tests
    • Add 2d orbit test
  • Driver function which allows users to run a ode to a specific time with a specific method
  • Helper function for 1d integrator
  • Examples
  • Make sure the function signature is similar to other methods in boost

Does this seem like a good plan? I'd appreciate any input.

@NAThompson

Copy link
Copy Markdown
Collaborator

@JacobHass8 : I think a good test is to identify the conserved quantity you wish to be conserved, and show that quantity is much better preserved with a symplectic integrator than with (say) RK4.

I would also recommend an API for event detection and return a solution skeleton that can be interpolated as a Hermite spline, i.e., return ${t_k, y_k, dot{y}k}{k=0}^{n-1}$ rather than the typical solution skeleton {t_k, y_k, }_{k=0}^{n-1}.

@JacobHass8

JacobHass8 commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

@JacobHass8 : I think a good test is to identify the conserved quantity you wish to be conserved, and show that quantity is much better preserved with a symplectic integrator than with (say) RK4.

I've tried this on a harmonic oscillator and the energy fluctuations seem to be of order 1e-11 (for the 6th order method). I haven't checked RK4 (or any other method though!).

I would also recommend an API for event detection and return a solution skeleton that can be interpolated as a Hermite spline, i.e., return ${t_k, y_k, dot{y}k}{k=0}^{n-1}$ rather than the typical solution skeleton {t_k, y_k, }_{k=0}^{n-1}.

I'm not sure I totally understand what you mean. Are you saying return a third object that could be used to interpolate between different $t_k$?

@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.33333% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.37%. Comparing base (6dea961) to head (098ab7d).

Files with missing lines Patch % Lines
include/boost/math/quadrature/symplectic.hpp 67.92% 17 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1411      +/-   ##
===========================================
- Coverage    95.39%   95.37%   -0.02%     
===========================================
  Files          826      828       +2     
  Lines        68901    68976      +75     
===========================================
+ Hits         65726    65787      +61     
- Misses        3175     3189      +14     
Files with missing lines Coverage Δ
test/test_symplectic.cpp 100.00% <100.00%> (ø)
include/boost/math/quadrature/symplectic.hpp 67.92% <67.92%> (ø)

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6dea961...098ab7d. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@NAThompson

NAThompson commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

Are you saying return a third object that could be used to interpolate between different t_k?

Exactly. Say you have an $\mathcal{O}(\delta t^6)$ accurate ODE stepper. That means you only need to store a very sparse set of $(t_k, y_k)$ pairs. And each ODE stepper does come with a "natural interpolant", so naively this is no loss of information. But the user gets this data back and has no clue how to interpolate it, or what the "natural interpolant" even is. So they resort to just using linear interpolation. This makes the display and subsequent use of the data worse than if you used a less accurate ODE stepper.

However, you have to compute $\dot{y}_k = f(t_k, y_k)$ during the course of the computation anyway, so if you just store it you can at least give the user a way to display the data as a hermite spline. I've been trying to get this built up in H5Web-see here.

Note that this is still inferior to the "natural interpolant", but given there seems to be no hope to get every ODE stepper's interpolant into the standard graphics packages, I think this is a reasonable compromise.

@JacobHass8

Copy link
Copy Markdown
Contributor Author

The methods implemented here do appear better than those in Scipy. I test a simple harmonic oscillator where the Hamiltonian is given by $H = p^2 + x^2$. Starting with the initial condition $x=1$ and $p=0$, the total energy of the system is $1$. I ran the system from time 0 to 1 with time steps of 0.05. Here's a plot of the position as a function of time. Both graphs match up pretty nicely so we know they are both performing as expected.

ScipyComp

However, if we look $p^2 + x^2 -1$, which I call the energy loss, it's clear that the symplectic integrators implemented here outperform scipy's Runge-Kutta method.

ScipyEnergyFluctuations

namespace boost{ namespace math {namespace quadrature {

template <class RealType, class ReturnType, class Func>
std::pair<ReturnType, ReturnType> second_order_yoshida(const ReturnType p0,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@JacobHass8 : It appears to me that if we wanted to return both objects of the same type, we would do a std::array<ReturnType,2>. But it also appears that these two objects have different units. Could it work with dimensioned types like mpunitz or boost::units? That would indeed force you into a std::pair.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think the return object necessarily need to be the same type. It is just returning the input types of p0 and q0.

@JacobHass8 JacobHass8 Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

However, there is a constraint on these types. Either we need to be able to add the types of p0 and q0 or we need the function dHdp to take in a type of p0 and return a type of q0 (for dHdq we need q0 -> p0).

This is because of the lines

    ReturnType p = p0;
    ReturnType q = q0;

    q = q + dt / 2 * dHdp(p);
    p = p - dt * dHdq(q);

I'm not familiar with mpunitz or boost::units. I was only thinking about singletons versus array types.

Comment thread include/boost/math/quadrature/symplectic.hpp Outdated
Comment thread test/test_symplectic.cpp
Comment thread include/boost/math/quadrature/symplectic.hpp
Comment thread test/Jamfile.v2 Outdated
[ run test_trapezoidal.cpp /boost/test//boost_unit_test_framework : : :
release [ requires cxx11_lambdas cxx11_auto_declarations cxx11_decltype cxx11_unified_initialization_syntax cxx11_variadic_templates ]
$(float128_type) ]
[ run test_symplectic.cpp /boost/test//boost_unit_test_framework ]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think you used boost unit test framework here right? You just used the boost::math floating point comparisons.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not entirely sure what the unit test framework is. I just copied it from test_trapezoidal...

@JacobHass8

JacobHass8 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@NAThompson I created a .qbk file to add documentation for the functions I added. I couldn't figure out how to build the documentation though. I kept getting errors when trying to follow the boost math guide.

I wanted to include an equation so I created a .svg and .png using latex. However, I noticed that all other equations have a .mml file. Do you know how to convert these?

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