Skip to content

Update for SciMLBase v3 compatibility - #472

Merged
ChrisRackauckas merged 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:scimlbase-v3-compat
Apr 23, 2026
Merged

Update for SciMLBase v3 compatibility#472
ChrisRackauckas merged 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:scimlbase-v3-compat

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member

Summary

Supersedes #466 — replaces the pure compat bump with the source and test changes needed for SciMLBase v3 / RecursiveArrayTools v4, where AbstractVectorOfArray (and thus ODESolution/VectorOfArray) now subtypes AbstractArray with column-major linear-indexing semantics.

v3 breaking changes this addresses

v2 v3
sol[i] (timestep) first scalar element (linear index)
length(sol) (timesteps) prod(size(sol))
first(sol)/last(sol) first/last scalar
iterate(sol) / map(f, sol) over scalars
prob_func(prob, i, repeat) prob_func(prob, ctx)

Changes

Tests

  • lib/BoundaryValueDiffEqMIRK/test/ensemble_tests.jl, lib/BoundaryValueDiffEqFIRK/test/{nested,expanded}/ensemble_tests.jl: switch prob_func to the v3 (prob, ctx) signature.
  • test/misc/default_solvers.jl: user BC uses sol.u[1][1] / sol.u[end][1].

Source

  • lib/BoundaryValueDiffEqMIRK/src/adaptivity.jl halve_sol: use sol.u / new_sol.u for timestep-indexed read/write and length(sol.u) for the timestep count.
  • lib/BoundaryValueDiffEqCore/src/utils.jl:
    • length(sol[1])length(sol.u[1]) in the second-order BC eval.
    • __restructure_sol(::AbstractVectorOfArray, ...) iterates sol.u for first and map.
    • __initial_guess_length(::VectorOfArray) uses length(u₀.u).
  • lib/BoundaryValueDiffEqCore/src/solution_utils.jl: added an Integer getindex overload on EvalSol so that sol[i] still returns the i-th timestep, mirroring the v2 VectorOfArray indexing semantics that the rest of the package depends on.
  • lib/BoundaryValueDiffEqMIRK/src/mirk.jl and lib/BoundaryValueDiffEqFIRK/src/firk.jl: parameter-tuning paths use cache.y₀.u[1] instead of first(cache.y₀), and foreach(..., cache.y₀.u) instead of map(..., cache.y₀). Solution construction loops iterate cache.y₀.u.
  • lib/BoundaryValueDiffEqFIRK/src/{interpolation,adaptivity}.jl: length(cache.y₀)length(cache.y₀.u) for timestep counts.

Compat

SciMLBase widened to "2.152.1, 3" in the top-level package and in every lib (Core, MIRK, MIRKN, FIRK, Shooting, Ascher).

Notes

I haven't been able to run the test suite against SciMLBase v3 locally before opening — this is a best-effort sweep targeted at the documented breaking patterns. CI is the source of truth. If additional locations surface, they follow the same .u pattern.

Test plan

  • Core test suite passes.
  • MIRK/FIRK/MIRKN/Shooting/Ascher lib test suites pass.
  • Ensemble tests pass with the new prob_func(prob, ctx) signature.
  • test/misc/default_solvers.jl passes with the updated BC.

Co-Authored-By: Chris Rackauckas accounts@chrisrackauckas.com

🤖 Generated with Claude Code

In SciMLBase v3 / RecursiveArrayTools v4, `AbstractVectorOfArray`
(and thus `ODESolution` and `VectorOfArray`) now subtypes `AbstractArray`
with column-major linear-indexing semantics. That changes:

- `sol[i]`        : was `sol.u[i]` (timestep), now the i-th scalar element.
- `length(sol)`   : was timestep count, now `prod(size(sol))`.
- `first`/`last`  : was first/last timestep, now first/last scalar.
- `iterate`/`map` : was over timesteps, now over scalars.

Source/test changes in this patch:

- Ensemble tests (MIRK, FIRK nested & expanded): switch `prob_func`
  from the v2 `(prob, i, repeat)` signature to the v3 `(prob, ctx)`
  signature.
- `test/misc/default_solvers.jl`: user BC now indexes `sol.u[1]` /
  `sol.u[end]` instead of `sol[1]` / `sol[end]`.
- `BoundaryValueDiffEqMIRK/src/adaptivity.jl` `halve_sol`: use
  `sol.u` / `new_sol.u` for all timestep-indexed read/write.
- `BoundaryValueDiffEqCore/src/utils.jl`:
  - `length(sol[1])` → `length(sol.u[1])` in second-order BC eval.
  - `__restructure_sol(::AbstractVectorOfArray, ...)` iterates
    `sol.u` for `first` and `map`.
  - `__initial_guess_length(::VectorOfArray)` uses `length(u₀.u)`.
- `BoundaryValueDiffEqCore/src/solution_utils.jl`: add an `Integer`
  `getindex` overload on `EvalSol` so `sol[i]` still returns the
  i-th timestep (mirrors the v2 `VectorOfArray` indexing semantics
  that the rest of the package assumes).
- `BoundaryValueDiffEqMIRK/src/mirk.jl` and
  `BoundaryValueDiffEqFIRK/src/firk.jl`:
  - Parameter-tuning paths: use `cache.y₀.u[1]` instead of
    `first(cache.y₀)`, and `foreach(..., cache.y₀.u)` instead of
    `map(..., cache.y₀)`.
  - Solution construction loop iterates `cache.y₀.u`.
- `BoundaryValueDiffEqFIRK/src/{interpolation,adaptivity}.jl`:
  `length(cache.y₀)` → `length(cache.y₀.u)` for timestep counts.

`Project.toml` compat for `SciMLBase` widened to `"2.152.1, 3"` in the
top-level package and in every lib (Core, MIRK, MIRKN, FIRK, Shooting,
Ascher).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Let EvalSol follow the same linear-indexing semantics as v3
AbstractVectorOfArray by delegating `sol[i]` through to `VectorOfArray`.
The only internal caller that relied on `sol[1]` returning a timestep
was `length(sol[1])` in `BoundaryValueDiffEqCore/src/utils.jl`, which
is already rewritten to `length(sol.u[1])`.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@github-actions

github-actions Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results

Click to check benchmark results
master 39437b3... master / 39437b3...
Simple Pendulum/IIP/BoundaryValueDiffEqMIRK.MIRK2() 0.511 ± 0.0043 s 0.503 ± 0.0066 s 1.02 ± 0.016
Simple Pendulum/IIP/BoundaryValueDiffEqMIRK.MIRK3() 10.4 ± 0.79 ms 10.4 ± 0.77 ms 1 ± 0.11
Simple Pendulum/IIP/BoundaryValueDiffEqMIRK.MIRK4() 2.28 ± 0.4 ms 2.22 ± 0.31 ms 1.03 ± 0.23
Simple Pendulum/IIP/BoundaryValueDiffEqMIRK.MIRK5() 2.73 ± 0.48 ms 2.72 ± 0.47 ms 1.01 ± 0.25
Simple Pendulum/IIP/BoundaryValueDiffEqMIRK.MIRK6() 1.3 ± 0.28 ms 1.3 ± 0.27 ms 1.01 ± 0.3
Simple Pendulum/IIP/MultipleShooting(10, Tsit5; grid_coarsening = false) 1.55 ± 0.45 ms 1.49 ± 0.46 ms 1.04 ± 0.44
Simple Pendulum/IIP/MultipleShooting(10, Tsit5; grid_coarsening = true) 3.05 ± 0.84 ms 3.03 ± 0.84 ms 1.01 ± 0.39
Simple Pendulum/IIP/MultipleShooting(100, Tsit5; grid_coarsening = false) 0.0374 ± 0.0051 s 0.0355 ± 0.002 s 1.06 ± 0.16
Simple Pendulum/IIP/MultipleShooting(100, Tsit5; grid_coarsening = true) 0.0572 ± 0.012 s 0.0577 ± 0.014 s 0.992 ± 0.32
Simple Pendulum/IIP/Shooting(Tsit5()) 0.216 ± 0.068 ms 0.219 ± 0.07 ms 0.986 ± 0.44
Simple Pendulum/OOP/BoundaryValueDiffEqMIRK.MIRK2() 0.665 ± 0.019 s 0.643 ± 0.0051 s 1.03 ± 0.031
Simple Pendulum/OOP/BoundaryValueDiffEqMIRK.MIRK3() 13.3 ± 5.6 ms 13.4 ± 5.8 ms 0.997 ± 0.6
Simple Pendulum/OOP/BoundaryValueDiffEqMIRK.MIRK4() 2.74 ± 0.21 ms 2.75 ± 0.19 ms 0.995 ± 0.1
Simple Pendulum/OOP/BoundaryValueDiffEqMIRK.MIRK5() 3.43 ± 0.51 ms 3.34 ± 0.26 ms 1.03 ± 0.17
Simple Pendulum/OOP/BoundaryValueDiffEqMIRK.MIRK6() 1.61 ± 0.4 ms 1.58 ± 0.26 ms 1.02 ± 0.31
Simple Pendulum/OOP/MultipleShooting(10, Tsit5; grid_coarsening = false) 3.39 ± 2.5 ms 3.25 ± 2.5 ms 1.04 ± 1.1
Simple Pendulum/OOP/MultipleShooting(10, Tsit5; grid_coarsening = true) 6.45 ± 5 ms 6.15 ± 4.9 ms 1.05 ± 1.2
Simple Pendulum/OOP/MultipleShooting(100, Tsit5; grid_coarsening = false) 0.0858 ± 0.0051 s 0.0835 ± 0.004 s 1.03 ± 0.078
Simple Pendulum/OOP/MultipleShooting(100, Tsit5; grid_coarsening = true) 0.13 ± 0.0072 s 0.128 ± 0.0075 s 1.01 ± 0.082
Simple Pendulum/OOP/Shooting(Tsit5()) 0.526 ± 0.11 ms 0.52 ± 0.088 ms 1.01 ± 0.27
time_to_load 6.81 ± 0.056 s 6.79 ± 0.038 s 1 ± 0.01
### Benchmark Plots A plot of the benchmark results has been uploaded as an artifact to the workflow run for this PR. Go to "Actions"->"Benchmark a pull request"->[the most recent run]->"Artifacts" (at the bottom).

@ChrisRackauckas
ChrisRackauckas merged commit 04c666b into SciML:master Apr 23, 2026
14 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.

2 participants