Skip to content

fix: type-stable multi-batch Jacobian and Hessian assembly for static arrays - #1080

Open
devmotion wants to merge 4 commits into
mainfrom
dmw/static-multibatch-assembly
Open

devmotion wants to merge 4 commits into
mainfrom
dmw/static-multibatch-assembly

Conversation

@devmotion

Copy link
Copy Markdown
Member

Stacked on #1078.

Replaces mapreduce(hcat/vcat, ...) in the multi-batch Jacobian and Hessian paths with map + a single reduce(hcat/vcat, ...) through new internal hooks, which the StaticArrays extension overloads. Multi-batch Jacobians and Hessians of static arrays are now inferred and return static matrices (turning #1078's @test_broken into passing tests).

Why map + reduce instead of mapreduce

reduce(hcat, ::AbstractVector{<:AbstractVecOrMat}) (and vcat) has a specialized Base method that allocates the result once. mapreduce(f, hcat, v) has no such method and falls back to pairwise hcat, re-copying the partial result at every level.

Concatenating A blocks of size m × B (Chairmarks):

m × (A × B) mapreduce(f, hcat, v) reduce(hcat, map(f, v))
10 × (3 × 4) 89 ns, 3.0 KB 93 ns, 2.4 KB
100 × (9 × 12) 12.4 µs, 573 KB 3.5 µs, 191 KB
1000 × (84 × 12) 78 ms, 358 MB 0.36 ms, 16 MB

End-to-end, prepared jacobian(identity, prep, backend, x) with dense x and chunksize = 12:

backend, length(x) before after
AutoSimpleFiniteDiff, 100 29.7 µs, 1.16 MB 27.3 µs, 0.87 MB
AutoSimpleFiniteDiff, 1000 32.0 ms, 401 MB 3.0 ms, 74 MB
AutoReverseFromPrimitive(AutoSimpleFiniteDiff), 1000 780 ms, 5.22 GB 430 ms, 4.90 GB

(stack was also considered: equivalent for columns, but rows need an extra permutedims copy.)

🤖 Generated with Claude Code

devmotion and others added 2 commits October 12, 2026 11:37
…ic arrays

Follow-up to #1076: lock in that `pick_batchsize` and `prepare_jacobian`
infer the batch size from the type for `SVector`, `SMatrix` and `MVector`,
with adaptive and fixed batch sizes. Mark multi-batch `jacobian` inference
as broken, since `mapreduce(hcat, ...)` changes the static size at every step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… arrays

Compute all batch blocks with `map` and concatenate them once with
`reduce(hcat/vcat, ...)` via new internal hooks `stack_batches_col` and
`stack_batches_row`, instead of `mapreduce(hcat/vcat, ...)` with an
in-loop slice of the last batch. The StaticArrays extension overloads
the hooks to concatenate a statically sized tuple of blocks, so that
multi-batch Jacobians and Hessians of static arrays are inferred and
return static matrices.

For dense arrays this avoids the repeated reallocation of pairwise
`hcat`/`vcat` (e.g. 10x faster, 5x less memory for a 1000x1000
Jacobian with chunksize 12).

Also remove the unreachable unaligned branch in the single-batch
Jacobian methods: a single batch is always aligned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@devmotion
devmotion requested a review from gdalle as a code owner October 12, 2026 14:51
@codecov

codecov Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.21429% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 98.25%. Comparing base (e64b3a4) to head (3209372).

Files with missing lines Patch % Lines
DifferentiationInterface/src/utils/linalg.jl 90.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1080      +/-   ##
==========================================
+ Coverage   98.21%   98.25%   +0.03%     
==========================================
  Files         143      143              
  Lines        8246     8243       -3     
==========================================
  Hits         8099     8099              
+ Misses        147      144       -3     
Flag Coverage Δ
DI 98.09% <98.21%> (+0.04%) ⬆️
DIT 98.67% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

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

Base automatically changed from dmw/static-batchsize-inference-tests to main October 13, 2026 13:23
…-assembly

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@gdalle gdalle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks, this looks like a worthwhile improvement! A few things to iron out though

Comment thread DifferentiationInterface/src/utils/linalg.jl Outdated
Comment thread DifferentiationInterface/src/first_order/jacobian.jl
Comment thread DifferentiationInterface/src/first_order/jacobian.jl

function hessian(
f::F,
prep::HVPGradientHessianPrep{SIG, <:BatchSizeSettings{1, false, true}},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This method wasn't modified in the Jacobian file.
Essentially, there are currently three methods for Jacobian and Hessian:

  • single batch
  • multiple batches & batch size one
  • general case

Which ones do we need to touch here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Single batch needs no change: it has one block, and stack_vec_col/row is already overloaded for static arrays. The general and B=1 methods, for both the Jacobian (pushforward and pullback) and the Hessian, now all go through stack_batches_col/row. So the B=1 Jacobians also return static matrices, which the static tests now check with chunksize = 1.

- split `aligned ? M : M[...]` into if/else blocks for coverage
- drop the unused `B_last` field from `BatchSizeSettings`
- route the B=1 Jacobian methods through `stack_batches_col/row` too,
  so they also return static matrices for static arrays

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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