Skip to content

Same-shape fast path for restructure(x::Array, y::Array)#497

Merged
ChrisRackauckas merged 1 commit into
JuliaArrays:masterfrom
ChrisRackauckas-Claude:restructure-same-shape-fastpath
Jul 23, 2026
Merged

Same-shape fast path for restructure(x::Array, y::Array)#497
ChrisRackauckas merged 1 commit into
JuliaArrays:masterfrom
ChrisRackauckas-Claude:restructure-same-shape-fastpath

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown

What

Add a same-shape fast path to restructure(x::Array, y::Array): when y already has x's shape, return y directly instead of reshaping.

Why

restructure(x::Array, y) is reshape(convert(Array, y), size(x)...). reshape has no same-shape short-circuit (unlike vec, which returns a Vector unchanged), so even reshaping an array to its own exact shape mints a fresh Array headerreshape(y, size(y)) !== y, 32 bytes on Julia 1.12's Memory-backed arrays. The data buffer is shared (no copy), but the wrapper object is a per-call heap allocation.

That per-call allocation shows up in hot loops. In NonlinearSolve's Newton descent, the linear solve already writes its result into the cached δu buffer and then restructures it back to the state shape — for a plain Vector state that's a no-op that allocates ~once per iteration. On an OrdinaryDiffEq NonlinearSolveAlg (Van der Pol μ=1e5, TRBDF2) that single call was 68% of the solver's per-step allocations; this fast path cuts the solve's total allocation by ~56% with identical results, and it helps every caller that restructures already-correctly-shaped arrays (RecursiveArrayTools, DiffEq, NonlinearSolve, …).

Semantics

Unchanged. The x::Array path already returned a data-sharing reshape, so returning y (which shares its own data) preserves the existing aliasing contract; eltype/shape of the result are identical. A genuine shape change (size(x) != size(y), e.g. vector → matrix) still reshapes exactly as before. Type-stable: for differing ndims the size comparison is a compile-time false, so the reshape branch is always taken.

Patch bump (7.28.0 → 7.28.1); test added to the restructure testset.


Draft — please ignore until reviewed by @ChrisRackauckas.

🤖 Generated with Claude Code

`restructure(x::Array, y)` is `reshape(convert(Array, y), size(x)...)`. `reshape`
has no same-shape short-circuit (unlike `vec`), so reshaping an array to its own
shape still mints a fresh `Array` header (sharing the data) — a per-call heap
allocation. Return `y` directly when it already has `x`'s shape.

Semantics unchanged: the `::Array` path already returned a data-sharing reshape,
so `=== y` preserves the aliasing contract, and a genuine shape change still
reshapes. On Julia 1.12 this removes a 32-byte allocation per call; in
NonlinearSolve's Newton descent (which restructures an already-shaped `δu`
buffer once per iteration) it cuts ~56% of a NonlinearSolveAlg solve's total
allocation.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NB3oFTNzGW79UtDt8AyjsM
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.75%. Comparing base (80e3539) to head (bba033c).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #497      +/-   ##
==========================================
+ Coverage   60.56%   60.75%   +0.19%     
==========================================
  Files          15       15              
  Lines         606      609       +3     
==========================================
+ Hits          367      370       +3     
  Misses        239      239              

☔ 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.

@ChrisRackauckas
ChrisRackauckas marked this pull request as ready for review July 23, 2026 23:51
@ChrisRackauckas
ChrisRackauckas merged commit d767284 into JuliaArrays:master Jul 23, 2026
20 of 21 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