Skip to content

Feature/custom structs backsolve adjoint#1292

Closed
simenhu wants to merge 6 commits intoSciML:masterfrom
simenhu:feature/custom_structs_backsolve_adjoint
Closed

Feature/custom structs backsolve adjoint#1292
simenhu wants to merge 6 commits intoSciML:masterfrom
simenhu:feature/custom_structs_backsolve_adjoint

Conversation

@simenhu
Copy link

@simenhu simenhu commented Dec 9, 2025

Checklist

  • Appropriate tests were added
  • Any code changes were done in a way that does not break public API
  • All documentation related to code changes were updated
  • The new code follows the
    contributor guidelines, in particular the SciML Style Guide and
    COLPRAC.
  • Any new documentation only uses public API

Additional context

BacksolveAdjoint now works with SciMLStructures

@ChrisRackauckas-Claude
Copy link
Contributor

I've rebased this PR onto the latest master to resolve the merge conflicts.

The rebased branch is available at: https://github.com/ChrisRackauckas-Claude/SciMLSensitivity.jl/tree/feature/custom_structs_backsolve_adjoint

@simenhu To update your PR with the rebased changes, you can run:

git remote add claude https://github.com/ChrisRackauckas-Claude/SciMLSensitivity.jl.git
git fetch claude feature/custom_structs_backsolve_adjoint
git checkout feature/custom_structs_backsolve_adjoint
git reset --hard claude/feature/custom_structs_backsolve_adjoint
git push --force origin feature/custom_structs_backsolve_adjoint

The rebase resolved the following conflicts in src/derivative_wrappers.jl:

  1. Added both the gclosure1/gclosure2 helper functions from master AND the repack_ode_function from this PR
  2. Combined the Enzyme.Duplicated logic to use the PR's tunables approach for SciMLStructures and master's shadow_p optimization for regular parameters

Co-Authored-By: Chris Rackauckas [email protected]

@ChrisRackauckas-Claude
Copy link
Contributor

Opened a rebased version of this PR at #1335.

claude and others added 4 commits January 21, 2026 12:51
Minor optimization: cache the result of isscimlstructure(p) in a local
variable to avoid calling it twice in the hot _vecjacobian! path.

Co-Authored-By: Chris Rackauckas <[email protected]>
Performance optimization: use the pre-cached wrapped function (pf) from
S.diffcache.pf instead of calling repack_ode_function in every
_vecjacobian! call. The function wrapping is already done during setup
in adjoint_common.jl, so we can reuse it directly.

This avoids:
- Closure creation in the hot path
- Calling repack inside the closure on every ODE evaluation

Co-Authored-By: Chris Rackauckas <[email protected]>
…ions

The closure was only defined for inplace signature (du, u, p, t), but
out-of-place functions need (u, p, t) signature. Added isinplace parameter
to generate the correct closure based on the function type.

Co-Authored-By: Chris Rackauckas <[email protected]>
For some sensitivity algorithms (QuadratureAdjoint, etc.), pf is set to
nothing in adjointdiffcache. Fall back to the original behavior of using
SciMLBase.Void(f) for inplace or f for out-of-place when pf is nothing.

Co-Authored-By: Chris Rackauckas <[email protected]>
@simenhu simenhu force-pushed the feature/custom_structs_backsolve_adjoint branch from 0e9e939 to d7661ab Compare January 28, 2026 14:51
ChrisRackauckas-Claude pushed a commit to ChrisRackauckas-Claude/SciMLSensitivity.jl that referenced this pull request Feb 12, 2026
Change CallbackAffectPWrapper signature from (dp, p, u, t) to (dp, u, p, t)
and use the dgrad output path for p-derivatives instead of hijacking the dλ
(u-derivative) path via swapped vecjacobian! arguments.

This unblocks PRs SciML#1335, SciML#1292, SciML#1260, SciML#1223 that need SciMLStructures
support, where canonicalize(Tunable(), _p) was running on state y instead
of actual parameters, and Enzyme code assumed position 2 is a state-like
object.

Changes:
- CallbackAffectPWrapper: (dp, p, u, t) → (dp, u, p, t)
- vecjacobian! calls: use standard arg order with dgrad kwarg
- Add _get_wp_paramjac_config helper for param-sized output buffers
- ReverseDiff on-the-fly tape: PSwap dispatch for param-sized output
- QuadratureAdjoint callback path: normalize wp call and vecjacobian!

Co-Authored-By: Chris Rackauckas <[email protected]>
ChrisRackauckas-Claude pushed a commit to ChrisRackauckas-Claude/SciMLSensitivity.jl that referenced this pull request Feb 13, 2026
Previously only GaussAdjoint supported SciMLStructures-compatible
parameter types. This extends support to BacksolveAdjoint,
InterpolatingAdjoint, and QuadratureAdjoint by:

- Fixing parameter gates in concrete_solve.jl and sensitivity_interface.jl
  to allow SciMLStructures types through
- Wrapping unwrappedf with repack in ForwardDiff ParamJacobianWrapper and
  ParamGradientWrapper (adjoint_common.jl) so ForwardDiff sees plain vectors
- Adding canonicalization in the Bool _vecjacobian! path
  (derivative_wrappers.jl) to pass tunables to jacobian! calls
- Fixing ZygoteVJP to differentiate w.r.t. tunables with repack wrapper
- Fixing EnzymeVJP to extract gradients from shadow struct via
  canonicalize after autodiff
- Overhauling QuadratureAdjoint's AdjointSensitivityIntegrand to use
  tunables/repack throughout constructor, vec_pjac!, and result init

Refs: SciML#1335, SciML#1292, SciML#1260, SciML#1223

Co-Authored-By: Chris Rackauckas <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
@ChrisRackauckas
Copy link
Member

Handled in #1349

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.

4 participants