Skip to content

Add reshape support for DiffCache resizing#180

Draft
ChrisRackauckas-Claude wants to merge 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/diffcache-resize-nd
Draft

Add reshape support for DiffCache resizing#180
ChrisRackauckas-Claude wants to merge 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/diffcache-resize-nd

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Draft PR. Please ignore until reviewed by @ChrisRackauckas.

Summary

  • Add reshape(::DiffCache, dims...) so vector-backed DiffCache storage can be presented as a multidimensional cache without callers reaching into .du/.dual_du.
  • Keep the reshaped normal cache view-backed so the original vector cache can still be resize!d and reshaped again.
  • Preserve the existing raw dual-storage ratio when resizing vector-backed DiffCaches.
  • Keep vector-backed reshaped dual temporaries zero-copy by detecting vector/subvector-backed reshapes through public array APIs before falling back to ArrayInterface.restructure.
  • Document the resize/reshape workflow and bump the version to 1.3.0 for the new public API.

Root Cause

The issue workflow needed multidimensional DiffCache access while keeping resizeable vector storage. A plain reshape(vector, dims...) marks the vector as shared and prevents later resize!, while the existing public API did not expose the field/unsafe_wrap pattern safely.

The initial implementation used a view-backed reshape for safety, but the ForwardDiff path for that wrapper fell back to ArrayInterface.restructure, which copied into a fresh matrix. The current implementation adds a vector-backed reshaped-cache fast path so get_tmp remains zero-copy and writes alias the raw dual storage, without relying on non-public Base.ReshapedArray in source.

Fixes #140.

Performance Notes

Benchmarked locally with BenchmarkTools after rebasing onto current master, on a 1000-element vector-backed cache reshaped to (20, 50):

  • get_tmp for reshaped dual cache: 23.63 ns, 0 bytes
  • ordinary matrix dual cache get_tmp: 23.63 ns, 0 bytes
  • reshape(DiffCache vector): 5.63 ns, 0 bytes
  • unsafe_wrap(Array, pointer, dims): 45.35 ns, 48 bytes
  • elementwise fill/sum on the reshaped cache matched unsafe_wrap and ordinary matrix timings and allocated 0 bytes
  • reshaped normal and dual temporaries are StridedArrays and the dual temporary aliases dual_du

Non-standard probes:

  • SubArray and LVector vector-backed reshapes return strided, zero-copy reshaped dual temporaries.
  • LArray matrix reshapes stay on the existing ArrayInterface.restructure fallback, preserving wrapper behavior instead of applying the vector-backed fast path.
  • VectorOfArray reshaped normal access remains zero-allocation.

Validation

  • timeout 3600 /home/crackauc/.juliaup/bin/julia +1.10 --project=. test/core_resizing.jl
  • timeout 3600 /home/crackauc/.juliaup/bin/julia +1.10 --project=. -e 'using Runic; Runic.main(ARGS)' -- --check --diff .
  • timeout 3600 /home/crackauc/.juliaup/bin/julia +1.10 --project=. -e 'using Pkg; Pkg.test()'
  • GROUP=QA timeout 3600 /home/crackauc/.juliaup/bin/julia +1 --project=. -e 'using Pkg; Pkg.test()'
  • Docs build initially hit a transient GitHub 429 during Documenter linkcheck; retrying the same command unchanged passed: timeout 3600 /home/crackauc/.juliaup/bin/julia +1.10 --project=docs -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate(); include("docs/make.jl")'
  • BenchmarkTools probes in a temporary local perf_env, removed after use.

@ChrisRackauckas-Claude ChrisRackauckas-Claude force-pushed the agent/diffcache-resize-nd branch 2 times, most recently from e5bcc1f to f412824 Compare July 8, 2026 17:28
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude ChrisRackauckas-Claude force-pushed the agent/diffcache-resize-nd branch from f412824 to ead730d Compare July 8, 2026 18:49
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor Author

Follow-up for the PreallocationTools test coverage request.

Added core resizing tests for:

  • standard reshaped Array caches, including scalar dual, dual type, and dual array get_tmp dispatches
  • vector-backed non-standard caches: SubArray, LVector, and ArrayPartition
  • non-vector non-standard fallback behavior with LArray

The ArrayPartition case exposed that direct 1-D vector views were still taking the fallback restructure path, so I broadened the vector-backed view detector to cover direct SubArray{<:Any,1,<:AbstractVector} values as well as reshaped parents.

Local validation run on commit 81f6362:

  • julia +1.10 --project=.agent_probe_env test/core_resizing.jl: passed; DiffCache Resizing subtests include the new cases
  • julia +1.10 --project=. -e "using Pkg; Pkg.test()": passed; Testing PreallocationTools tests passed
  • julia +1.10 --project=. -e "using Runic; Runic.main(ARGS)" -- --check --diff .: 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.

Resizing multi-dimensional DiffCaches

2 participants