AbstractVectorOfArray{T, N, A} now subtypes AbstractArray{T, N}. This means
all VectorOfArray and DiffEqArray objects are proper Julia AbstractArrays,
and all standard AbstractArray operations work out of the box, including linear
algebra, broadcasting with plain arrays, and generic algorithms.
Previously, A[i] returned the ith inner array (A.u[i]). Now, A[i] returns
the ith element in column-major linear order, matching standard Julia AbstractArray
behavior.
A = VectorOfArray([[1, 2], [3, 4]])
# Old: A[1] == [1, 2] (first inner array)
# New: A[1] == 1 (first element, column-major)
# To access inner arrays: A.u[1] or A[:, 1]For ragged arrays (inner arrays of different sizes), size(A) now reports the
maximum size in each dimension. Out-of-bounds elements are treated as zero
(sparse representation):
A = VectorOfArray([[1, 2], [3, 4, 5]])
size(A) # (3, 2) — max inner length is 3
A[3, 1] # 0 — implicit zero (inner array 1 has only 2 elements)
A[3, 2] # 5 — actual stored value
Array(A) # [1 3; 2 4; 0 5] — zero-padded dense arrayThis means ragged VectorOfArrays can be used directly with linear algebra
operations, treating the data as a rectangular matrix with zero padding.
Iteration now goes over scalar elements in column-major order, matching
AbstractArray behavior:
A = VectorOfArray([[1, 2], [3, 4]])
collect(A) # [1 3; 2 4] — 2x2 matrix
# To iterate over inner arrays: for u in A.u ... endlength(A) now returns prod(size(A)) (total number of elements including
ragged zeros), not the number of inner arrays. Use length(A.u) for the number
of inner arrays.
map(f, A) now maps over individual elements, not inner arrays. Use
map(f, A.u) to map over inner arrays.
first(A) and last(A) return the first/last scalar element, not the first/last
inner array. Use first(A.u) / last(A.u) for inner arrays.
eachindex(A) returns CartesianIndices(size(A)) for the full rectangular shape,
not indices into A.u.
| Old Code | New Code |
|---|---|
A[i] (get inner array) |
A.u[i] or A[:, i] |
length(A) (number of arrays) |
length(A.u) |
for elem in A (iterate columns) |
for elem in A.u |
first(A) (first inner array) |
first(A.u) |
map(f, A) (map over columns) |
map(f, A.u) |
A == vec_of_vecs |
A.u == vec_of_vecs |
DiffEqArray now has interp and dense fields for interpolation support:
# Create with interpolation
da = DiffEqArray(u, t, p, sys; interp = my_interp, dense = true)
# Callable syntax
da(0.5) # interpolate at t=0.5
da(0.5, Val{1}) # first derivative at t=0.5
da([0.1, 0.5, 0.9]) # interpolate at multiple times
da(0.5; idxs = 1) # interpolate single component
da(0.5; idxs = [1, 2]) # interpolate subset of componentsThe interpolation object must be callable as interp(t, idxs, deriv, p, continuity),
matching the protocol used by SciMLBase's LinearInterpolation, HermiteInterpolation,
and ConstantInterpolation.
When dense = true and interp is provided, plot(da) automatically generates
dense interpolated output instead of plotting only the saved time points.
RaggedVectorOfArray and RaggedDiffEqArray are available via:
using RecursiveArrayToolsRaggedArraysThese types preserve the true ragged structure without zero-padding, and do not
subtype AbstractArray. See the RecursiveArrayToolsRaggedArrays subpackage for details.
Some Zygote adjoint rules need updating for the new AbstractArray subtyping.
ForwardDiff continues to work correctly. Zygote support will be updated in a
follow-up release.