stan-dev / stan-dev/math

Re-evaluate ODE default max_num_steps values

Open
#1,969 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

performance
Dominant language
C++
Stars
839
Forks
220
Avg merge
2d 4h
Merged PRs (30d)
14

Description

Description

Practically I think the default max_num_steps arguments to both solvers are too high.

Currently we use 1e6 for the RK45 solver and 1e8 for the BDF solver.

This is the number of steps between output points in an ODE solve, and the max_num_steps is expected to throw an error if the solver is spending too much time.

The reason I think max_num_steps is too large that if we set up a simple ODE example like this:

struct CosArg1 {
  template <typename T0, typename T1, typename T2>
  inline Eigen::Matrix<stan::return_type_t<T1, T2>, Eigen::Dynamic, 1>
  operator()(const T0& t, const Eigen::Matrix<T1, Eigen::Dynamic, 1>& y,
             std::ostream* msgs, const T2& a) const {
    Eigen::Matrix<stan::return_type_t<T1, T2>, Eigen::Dynamic, 1> out(1);
    out << stan::math::cos(a * t);
    return out;
  }
};

TEST(StanMathOde_ode_bdf_tol, too_much_work) {
  Eigen::Matrix<var, Eigen::Dynamic, 1> y0
      = Eigen::VectorXd::Zero(1).template cast<var>();
  var t0 = 0;
  std::vector<var> ts = {0.45, 1e10};

  var a = 1.0;

  EXPECT_THROW_MSG(stan::math::ode_rk45(CosArg1(), y0, t0, ts, nullptr, a),
                   std::domain_error,
                   "Failed to integrate to next output time");
}

the rk45 solver takes about a second to give up. The bdf would be slower per-step, and also has a much higher default so it will be slower.

If we assume a model takes 50000 leapfrog steps to sample, and should hopefully be done within an hour, that leaves 70ms per leapfrog step. It takes roughly a second for the current RK45 defaults to fail on a simple problem like this. If we cut the default max_num_steps to 1e5, we're looking at roughly 100ms to fail, or with 1e4 that's 10ms to fail, which is probably more in line with what we'd expect a useful default to do.

People with particularly slow models can increase the max_num_steps after they've exhausted their other options (switching solvers, adjusting priors, reparameterizing the model, and changing tolerances).

Current Version:

v3.2.0

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the ode_rk45 and ode_bdf solver entry points and reproduce the slow-failure example in the StanMathOde_ode_bdf_tol test described in the issue. Measure candidate max_num_steps defaults for both solvers, then update the relevant tests so completion verifies the intended failure behavior and timing.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.