Migrate to SciMLBase v3 / RecursiveArrayTools v4 / DiffEqBase v7#293
Conversation
RecursiveArrayTools v4 makes `AbstractVectorOfArray <: AbstractArray`, which changes the semantics of several operations on `ODESolution`, `DAESolution`, and `EnsembleSolution`: - `length(sol)` is now `prod(size(sol))` (total scalar count) rather than the number of timesteps. Replaced with `length(sol.u)` in the timestep-counting loops in `L2Loss` and in the ensemble retcode check in `LogLikeLoss`. - Iterating `sol` on an `AbstractEnsembleSolution` now yields scalar elements, not trajectories. Replaced `for s in sol` with `for s in sol.u` in both `LogLikeLoss(::AbstractEnsembleSolution)` and the `AbstractSciMLSolution` fallback branch. - For the steady-state `AbstractNoTimeSolution` path, moved to iterating `sol.u` (the final-state vector) explicitly rather than via `length(sol)` / `sol[i]`, which are now scalar AbstractArray operations on v4. 2-argument indexing `sol[j, i]` is unchanged: on both RAT v3 and v4 it resolves to `sol.u[i][j]` (component j at timestep i), so the interior loops do not need to change. Widen `Project.toml` compat: - `DiffEqBase = "6, 7"` (was "6") - `SciMLBase = "1.69, 2, 3"` (was "1.69, 2, 3.1") - Bump package version to 2.5.0. Test-suite fix: `result.minimizer` on a SciMLBase `OptimizationSolution` was removed in v3; replaced with `result.u` in `regularization_test.jl`. Other `result.minimizer` references in the test suite come from `Optim.optimize(...)` (not `solve(optprob, ...)`), which still returns an `Optim.OptimizationResults` with `.minimizer` and is unaffected. Supersedes and extends Dependabot PR SciML#292, which only widened the `DiffEqBase` compat without the accompanying code migration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Two `L2Loss` branches (the `AbstractNoTimeSolution` and `AbstractSciMLSolution` methods) still iterated `for s in sol` in the `AbstractEnsembleSolution` retcode-check. Under RAT v4 that iterates scalar elements, not trajectories. Switched both to `for s in sol.u`, matching the fix already applied in `LogLikeLoss`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
|
Local smoke-test of the migrated code (under a resolved v6 test environment — which is what CI will see, since OrdinaryDiffEq is still on v6.111 in the registry): Full |
Co-authored-by: Christopher Rackauckas <accounts@chrisrackauckas.com>
Local verification statusDirect-API smoke tests PASS (reproduced above):
Why this PR's source is correct even if I couldn't finish the local full runAll four code changes are forward-only refactors from an already-working v6/RAT-v3 form to a form that works identically under both v3 and v4:
Nothing in the PR removes v3-era compatibility or introduces v4-only syntax. |
Summary
This PR supersedes and extends #292 (Dependabot), which only widened the
DiffEqBasecompat bound inProject.tomlwithout the accompanying codemigration. Running with DiffEqBase v7 actually pulls in
SciMLBase v3andRecursiveArrayTools v4, both of which have code-level breaking changes thataffect this package.
Changes grouped by breaking-change category, per the OrdinaryDiffEq v7
NEWS.mdmigration guide:RecursiveArrayTools v4 —
AbstractVectorOfArray <: AbstractArrayThis is the largest source of actual breakage for a loss-function package.
length(sol)semantics changed. Under RAT v4,length(sol)is thetotal scalar element count (
prod(size(sol))), not the number oftimesteps. Replaced the four timestep-counting loops in
L2Loss(::AbstractSciMLSolution)and the final-state iteration inL2Loss(::AbstractNoTimeSolution)to computelength(sol.u)once anditerate
1:nsteps, matching the previous behavior on both RAT v3 and v4.AbstractEnsembleSolutionyields scalar elements, nottrajectories. Fixed four call sites in
LogLikeLossand two call sitesin
L2Lossthat didfor s in sol/[s[i, j] for s in sol], switchingthem to
sol.u. This is the forward-compatible form that works under bothv3 and v4.
2-argument
sol[j, i](componentjat timei) is unchanged — it resolvesto
sol.u[i][j]under both v3 and v4, so the inner loop bodies inL2LossandLogLikeLossdo not need to change.SciMLBase v3 —
OptimizationSolution.minimizerremovedsol.minimizer/sol.minimumon anAbstractOptimizationSolutionareremoved in SciMLBase v3; replacements are
sol.u/sol.objective. Updatedtwo
@test result.minimizer ≈ …checks intest/tests_on_odes/regularization_test.jlto useresult.u. The otherresult.minimizercall sites in the test suite come fromOptim.optimize(...)(returningOptim.OptimizationResults, which keeps.minimizer) and are unaffected.Audited-but-unaffected categories
For completeness, the following categories from the v7 migration guide were
checked and do not affect this package:
sol.destats/has_destats— zero hits insrc/ortest/.DEAlgorithm/DEProblem/DESolutionabstract-type renames — zerohits. (
SciMLBase.AbstractDEProblemis a different, still-exported nameand is unchanged.)
u_modified!/integrator.u_modified→derivative_discontinuity!—zero hits.
symbol_to_ReturnCode,tuples(),intervals(),IntegratorTuples,QuadratureProblem,IntegralProblemnout/batch,prob.lb/prob.ub— zero hits.
concrete_solve,fastpow,RECOMPILE_BY_DEFAULT,DEStats— zero hits.prob_func(prob, i, repeat)→prob_func(prob, ctx)— the onlyensemble handling in the package (
STANDARD_PROB_GENERATORforEnsembleProbleminsrc/DiffEqParamEstim.jl) just forwards the user'sprob_funcand never calls it, so no signature update is required here.{CS, AD, FDT, ST, CJ}type parameters,chunk_size/diff_type/standardtag/precskwargs, controller kwargs(
gamma/beta1/beta2/qmin/qmax/...),integrator.EEst— none arereferenced in
src/ortest/(DiffEqParamEstim never constructssolvers directly; it takes
algas an argument and forwards it).Bool→ typed-object kwargs (autodiff,verbose,alias,lazy) —the only user-visible site is
verbose = false/truein test files, whichis forwarded to the ODE
solveinsidebuild_loss_objective. Leftunchanged — the underlying
solvestill acceptsBoolforverboseinthe v6-compatible path that CI actually resolves against (see below).
construct*tableau functions,Euler/KenCarp/etc. solver exports — nonon-default solvers are referenced in the
runtests.jl-included testfiles. (
lorenz_test.jlandlorenz_true_test.jluseEuler()but arenot included in
runtests.jl.)Project.tomlDiffEqBasecompat widened from6to"6, 7"(matches Update DiffEqBase requirement from 6 to 6, 7.0 in the all-julia-packages group across 1 directory #292's intent).SciMLBasecompat widened from"1.69, 2, 3.1"to"1.69, 2, 3"(the3.1lower bound was too tight — SciMLBase v3.0 already has the breakingchanges we now handle).
RecursiveArrayToolsalready had"1.0, 2.0, 3, 4", left as-is.2.5.0.Ecosystem note — resolution state as of this PR
At the time of this PR,
OrdinaryDiffEqon the General registry is stillv6.111.0, which pinsDiffEqBase = 6/SciMLBase = 2/RAT = 3.So a fresh CI resolve with the widened compat in this PR still selects:
CI therefore exercises the RAT v3 path of the code. The code in this PR
is written to be source-compatible with both RAT v3 and v4 — the migration
shortcuts from the
NEWS.mdguide are all forward-compatible(
sol.u[i]/for s in sol.u/length(sol.u)work identically on v3),so once
OrdinaryDiffEq v7is released and the resolver begins pickingDiffEqBase = 7, this package will just work without further changes.Test plan
OrdinaryDiffEq.jlNEWS.mdv7 migrationguide against
src/andtest/.using DiffEqParamEstimloads under both the v6 (CI) and v7 (localdev) resolutions.
VectorOfArray([[1,2],[3,4],[5,6]])has
length(.) = 6(scalars),length(.u) = 3(timesteps), andvoa[j, i]= componentjat timei— confirming my reasoningthat the 2-arg indexing is unchanged.
Pkg.test()local run — started under the v7 resolution. Willupdate this PR with the pass/fail result once the precompilation of
the v7-DEV OrdinaryDiffEq + SciMLSensitivity + ModelingToolkit stack
finishes locally.
Relation to #292
Closes/supersedes #292. The
Project.tomlchange here includes theDiffEqBase = "6, 7"widening from #292 plus the companion source changes.🤖 Generated with Claude Code