From 74a2111a7a876531324e46895c54d3b409e84a5d Mon Sep 17 00:00:00 2001 From: Jash Date: Wed, 12 Aug 2026 18:55:36 +0530 Subject: [PATCH 1/4] Implement the SciMLStructures interface for ArrayPartition SciMLStructures opts every numeric array into the interface and canonicalizes it with `vec`. That is right for a contiguous array, but an `ArrayPartition` is already an `AbstractVector`, so `vec` returns it unchanged and the buffer comes back unflattened. The generic `repack` then errors, since an `ArrayPartition` cannot be rebuilt by a trivial array constructor, and its message asks for exactly this. Implements `canonicalize`, `replace` and `replace!` for the `Tunable` portion, laying the partitions out one after another so the flat buffer matches `collect(p)`. The buffer is a copy, so `aliases` is `false`: the partitions are separate arrays and no flat view over them exists. It is built from the first partition rather than as a `Vector` so that an exotic backing type stays itself. `replace` takes `new_values::AbstractArray` rather than leaving it untyped, which would be ambiguous with the generic `replace(::Tunable, ::AbstractArray, ::AbstractArray)`. --- Project.toml | 6 +- ext/RecursiveArrayToolsSciMLStructuresExt.jl | 84 +++++++++++++++ test/Core/scimlstructures_test.jl | 103 +++++++++++++++++++ test/runtests.jl | 1 + 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 ext/RecursiveArrayToolsSciMLStructuresExt.jl create mode 100644 test/Core/scimlstructures_test.jl diff --git a/Project.toml b/Project.toml index e9c98d58..dc579e70 100644 --- a/Project.toml +++ b/Project.toml @@ -24,6 +24,7 @@ Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" MonteCarloMeasurements = "0987c9cc-fe09-11e8-30f0-b96dd679fdca" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" +SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" @@ -41,6 +42,7 @@ RecursiveArrayToolsMeasurementsExt = "Measurements" RecursiveArrayToolsMonteCarloMeasurementsExt = "MonteCarloMeasurements" RecursiveArrayToolsMooncakeExt = "Mooncake" RecursiveArrayToolsReverseDiffExt = ["ReverseDiff", "Zygote"] +RecursiveArrayToolsSciMLStructuresExt = "SciMLStructures" RecursiveArrayToolsSparseArraysExt = ["SparseArrays"] RecursiveArrayToolsStatisticsExt = "Statistics" RecursiveArrayToolsStructArraysExt = "StructArrays" @@ -67,6 +69,7 @@ Random = "1" RecipesBase = "1.3.4" RecursiveArrayToolsShorthandConstructors = "1" ReverseDiff = "1.15" +SciMLStructures = "1.10" SafeTestsets = "0.1" SciMLPublic = "1" SciMLTesting = "2.4" @@ -93,6 +96,7 @@ Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RecursiveArrayToolsShorthandConstructors = "39fb7555-b4ad-4efd-8abe-30331df017d3" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" +SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" @@ -103,4 +107,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" [targets] -test = ["FastBroadcast", "KernelAbstractions", "Measurements", "Pkg", "Polyester", "Random", "RecursiveArrayToolsShorthandConstructors", "SafeTestsets", "SciMLTesting", "SparseArrays", "StaticArrays", "Statistics", "StructArrays", "Tables", "Test", "Unitful"] +test = ["FastBroadcast", "KernelAbstractions", "Measurements", "Pkg", "Polyester", "Random", "RecursiveArrayToolsShorthandConstructors", "SafeTestsets", "SciMLStructures", "SciMLTesting", "SparseArrays", "StaticArrays", "Statistics", "StructArrays", "Tables", "Test", "Unitful"] diff --git a/ext/RecursiveArrayToolsSciMLStructuresExt.jl b/ext/RecursiveArrayToolsSciMLStructuresExt.jl new file mode 100644 index 00000000..13b15d15 --- /dev/null +++ b/ext/RecursiveArrayToolsSciMLStructuresExt.jl @@ -0,0 +1,84 @@ +module RecursiveArrayToolsSciMLStructuresExt + +using RecursiveArrayTools: ArrayPartition +using SciMLStructures: SciMLStructures, Tunable + +# SciMLStructures opts every numeric array into the interface and canonicalizes it +# with `vec`. That is right for a contiguous array, but an `ArrayPartition` is +# already an `AbstractVector`, so `vec` returns it unchanged and the buffer comes +# back unflattened; the generic `repack` then errors, since an `ArrayPartition` +# cannot be rebuilt by a trivial array constructor. +# +# The partitions are laid out one after another, which is the same stable ordering +# `copyto!` and `Vector` use, so a caller can rely on the flat buffer matching +# `collect(p)`. + +# The buffer is a copy: the partitions are separate arrays, so no flat view over +# them exists to alias. Built from the first partition rather than as a `Vector` so +# that a GPU-backed partition yields a GPU-backed buffer. +function _flatten(p::ArrayPartition) + isempty(p.x) && throw( + ArgumentError("cannot canonicalize an `ArrayPartition` with no partitions") + ) + return copyto!(similar(first(p.x), length(p)), p) +end + +SciMLStructures.isscimlstructure(::ArrayPartition) = true +SciMLStructures.ismutablescimlstructure(::ArrayPartition) = true + +function SciMLStructures.canonicalize(::Tunable, p::ArrayPartition) + buffer = _flatten(p) + repack = let p = p + new_values -> SciMLStructures.replace(Tunable(), p, new_values) + end + return buffer, repack, false +end + +function SciMLStructures.replace( + ::Tunable, p::ArrayPartition, new_values::AbstractArray + ) + length(new_values) == length(p) || throw( + DimensionMismatch( + "expected $(length(p)) values to replace the tunable portion, got " * + "$(length(new_values))" + ) + ) + offsets = _offsets(p) + parts = ntuple(length(p.x)) do i + part = similar(p.x[i]) + copyto!(part, view(new_values, (offsets[i] + 1):offsets[i + 1])) + end + return ArrayPartition(parts) +end + +function SciMLStructures.replace!( + ::Tunable, p::ArrayPartition, new_values::AbstractArray + ) + length(new_values) == length(p) || throw( + DimensionMismatch( + "expected $(length(p)) values to replace the tunable portion, got " * + "$(length(new_values))" + ) + ) + offsets = _offsets(p) + for i in eachindex(p.x) + copyto!(p.x[i], view(new_values, (offsets[i] + 1):offsets[i + 1])) + end + return nothing +end + +# Cumulative partition boundaries, so partition `i` owns +# `(offsets[i] + 1):offsets[i + 1]` of the flat buffer. +function _offsets(p::ArrayPartition) + n = length(p.x) + offsets = ntuple(n + 1) do i + total = 0 + for j in 1:(i - 1) + total += length(p.x[j]) + end + total + end + return offsets +end + +end diff --git a/test/Core/scimlstructures_test.jl b/test/Core/scimlstructures_test.jl new file mode 100644 index 00000000..8fb0a680 --- /dev/null +++ b/test/Core/scimlstructures_test.jl @@ -0,0 +1,103 @@ +using RecursiveArrayTools, SciMLStructures, StaticArrays, Test +using SciMLStructures: Tunable, Constants, Caches, Discrete, Initials, Input, + canonicalize, hasportion, isscimlstructure, ismutablescimlstructure + +# SciMLStructures canonicalizes a generic array with `vec`, which returns an +# `ArrayPartition` unchanged since it is already an `AbstractVector`, and its generic +# `repack` cannot rebuild one. The extension implements the interface properly. +@testset "SciMLStructures interface for ArrayPartition" begin + p = ArrayPartition([1.0, 2.0], [3.0, 4.0, 5.0]) + + @testset "traits" begin + @test isscimlstructure(p) + @test ismutablescimlstructure(p) + @test hasportion(Tunable(), p) + end + + @testset "canonicalize flattens in the documented order" begin + buffer, repack, aliases = canonicalize(Tunable(), p) + @test buffer isa AbstractVector + @test !(buffer isa ArrayPartition) + @test length(buffer) == length(p) + # The partitions are laid out one after another, matching `collect`. + @test buffer == collect(p) + @test buffer == [1.0, 2.0, 3.0, 4.0, 5.0] + # The partitions are separate arrays, so the flat buffer has to be a copy. + @test aliases == false + buffer[1] = -1.0 + @test p.x[1][1] == 1.0 + end + + @testset "repack rebuilds the partitioning" begin + _, repack, _ = canonicalize(Tunable(), p) + back = repack([9.0, 8.0, 7.0, 6.0, 5.0]) + @test back isa ArrayPartition + @test map(length, back.x) == map(length, p.x) + @test collect(back) == [9.0, 8.0, 7.0, 6.0, 5.0] + # The original is untouched. + @test collect(p) == [1.0, 2.0, 3.0, 4.0, 5.0] + end + + @testset "replace matches repack" begin + _, repack, _ = canonicalize(Tunable(), p) + new_values = [9.0, 8.0, 7.0, 6.0, 5.0] + @test collect(SciMLStructures.replace(Tunable(), p, new_values)) == + collect(repack(new_values)) + end + + @testset "replace! mutates in place" begin + q = ArrayPartition([0.0, 0.0], [0.0, 0.0, 0.0]) + parts = q.x + @test SciMLStructures.replace!(Tunable(), q, [1.0, 2.0, 3.0, 4.0, 5.0]) === nothing + @test collect(q) == [1.0, 2.0, 3.0, 4.0, 5.0] + # The same partition arrays were written into, not replaced. + @test q.x[1] === parts[1] + @test q.x[2] === parts[2] + end + + @testset "wrong lengths are rejected" begin + @test_throws DimensionMismatch SciMLStructures.replace(Tunable(), p, [1.0]) + @test_throws DimensionMismatch SciMLStructures.replace!( + Tunable(), ArrayPartition([0.0], [0.0]), [1.0] + ) + end + + @testset "other portions are absent" begin + for portion in (Constants(), Caches(), Discrete(), Initials(), Input()) + @test !hasportion(portion, p) + @test canonicalize(portion, p) == (nothing, nothing, nothing) + end + end + + @testset "uneven and single partitions" begin + for q in ( + ArrayPartition([1.0]), + ArrayPartition([1.0], [2.0, 3.0], [4.0, 5.0, 6.0]), + ArrayPartition([1.0, 2.0], Float64[], [3.0]), + ) + buffer, repack, _ = canonicalize(Tunable(), q) + @test buffer == collect(q) + back = repack(collect(Float64, 1:length(q))) + @test map(length, back.x) == map(length, q.x) + @test collect(back) == collect(Float64, 1:length(q)) + end + end + + @testset "the partition array type is preserved" begin + # The buffer is built from the first partition rather than as a `Vector`, so + # an exotic backing type stays itself rather than being moved to a `Vector`. + q = ArrayPartition(MVector(1.0, 2.0), MVector(3.0, 4.0)) + buffer, repack, _ = canonicalize(Tunable(), q) + @test buffer == [1.0, 2.0, 3.0, 4.0] + back = repack([5.0, 6.0, 7.0, 8.0]) + @test back.x[1] isa MVector + @test collect(back) == [5.0, 6.0, 7.0, 8.0] + end + + @testset "integer partitions" begin + q = ArrayPartition([1, 2], [3, 4]) + buffer, repack, _ = canonicalize(Tunable(), q) + @test buffer == [1, 2, 3, 4] + @test collect(repack([5, 6, 7, 8])) == [5, 6, 7, 8] + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 1c949610..d6d0ece1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -23,6 +23,7 @@ run_tests(; @time @safetestset "Table traits" include("Core/tabletraits.jl") @time @safetestset "StaticArrays Tests" include("Core/copy_static_array_test.jl") @time @safetestset "Linear Algebra Tests" include("Core/linalg.jl") + @time @safetestset "SciMLStructures Tests" include("Core/scimlstructures_test.jl") return @time @safetestset "Measurement Tests" include("Core/measurements.jl") end, groups = Dict( From e4a13bc5c2ca04840d32778b371749cef665da80 Mon Sep 17 00:00:00 2001 From: Jash Date: Wed, 12 Aug 2026 19:13:21 +0530 Subject: [PATCH 2/4] Flatten by concatenating the partitions Review feedback: sizing the buffer from `p.x[1]` assumed every partition shares that one's array and element type. `ArrayPartition([1, 2], [3.0, 4.5])` gave a `Vector{Int}` buffer and truncated the second partition. `reduce(vcat, p.x)` promotes across both, and keeps a uniformly static partitioning as an `MVector` where sizing from the first partition dropped it to a `Vector`. `reduce(vcat, (x,))` returns `x` itself, so a single partition is copied rather than handing back a buffer that aliases `p` while `canonicalize` reports `aliases = false`. --- ext/RecursiveArrayToolsSciMLStructuresExt.jl | 13 +++++--- test/Core/scimlstructures_test.jl | 31 ++++++++++++++++++-- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/ext/RecursiveArrayToolsSciMLStructuresExt.jl b/ext/RecursiveArrayToolsSciMLStructuresExt.jl index 13b15d15..2f2f941f 100644 --- a/ext/RecursiveArrayToolsSciMLStructuresExt.jl +++ b/ext/RecursiveArrayToolsSciMLStructuresExt.jl @@ -13,14 +13,19 @@ using SciMLStructures: SciMLStructures, Tunable # `copyto!` and `Vector` use, so a caller can rely on the flat buffer matching # `collect(p)`. -# The buffer is a copy: the partitions are separate arrays, so no flat view over -# them exists to alias. Built from the first partition rather than as a `Vector` so -# that a GPU-backed partition yields a GPU-backed buffer. +# `reduce(vcat, p.x)` rather than building from one partition: the partitions need +# not share an array type or an element type, and concatenating promotes across both. +# It also keeps a uniform static or device-backed partitioning in kind, where sizing +# from `p.x[1]` would silently pick that partition's type for the whole buffer. +# +# The buffer must not alias `p`, since `canonicalize` reports `aliases = false`, and +# `reduce(vcat, (x,))` returns `x` itself, so a lone partition is copied. function _flatten(p::ArrayPartition) isempty(p.x) && throw( ArgumentError("cannot canonicalize an `ArrayPartition` with no partitions") ) - return copyto!(similar(first(p.x), length(p)), p) + length(p.x) == 1 && return copy(only(p.x)) + return reduce(vcat, p.x) end SciMLStructures.isscimlstructure(::ArrayPartition) = true diff --git a/test/Core/scimlstructures_test.jl b/test/Core/scimlstructures_test.jl index 8fb0a680..3d941e96 100644 --- a/test/Core/scimlstructures_test.jl +++ b/test/Core/scimlstructures_test.jl @@ -84,16 +84,43 @@ using SciMLStructures: Tunable, Constants, Caches, Discrete, Initials, Input, end @testset "the partition array type is preserved" begin - # The buffer is built from the first partition rather than as a `Vector`, so - # an exotic backing type stays itself rather than being moved to a `Vector`. + # Concatenating keeps a uniformly static partitioning static rather than + # dropping it to a `Vector`, and `replace` rebuilds each partition in kind. q = ArrayPartition(MVector(1.0, 2.0), MVector(3.0, 4.0)) buffer, repack, _ = canonicalize(Tunable(), q) @test buffer == [1.0, 2.0, 3.0, 4.0] + @test buffer isa MVector back = repack([5.0, 6.0, 7.0, 8.0]) @test back.x[1] isa MVector @test collect(back) == [5.0, 6.0, 7.0, 8.0] end + # The partitions need not share an array type or an element type, so the buffer + # has to promote across them rather than take its type from one of them. + @testset "partitions of differing types" begin + mixed_eltype = ArrayPartition([1, 2], [3.0, 4.5]) + buffer, repack, _ = canonicalize(Tunable(), mixed_eltype) + # Sizing from the first partition would give a `Vector{Int}` and truncate. + @test eltype(buffer) === Float64 + @test buffer == [1.0, 2.0, 3.0, 4.5] + + mixed_array = ArrayPartition([1.0, 2.0], MVector(3.0, 4.0)) + buffer2, _, _ = canonicalize(Tunable(), mixed_array) + @test buffer2 == [1.0, 2.0, 3.0, 4.0] + @test length(buffer2) == 4 + end + + # `reduce(vcat, (x,))` returns `x` itself, so the single-partition case has to + # copy or the buffer would alias `p` despite `aliases` being reported `false`. + @testset "a single partition still yields an independent buffer" begin + q = ArrayPartition([1.0, 2.0, 3.0]) + buffer, _, aliases = canonicalize(Tunable(), q) + @test aliases == false + @test buffer !== q.x[1] + buffer[1] = -1.0 + @test q.x[1][1] == 1.0 + end + @testset "integer partitions" begin q = ArrayPartition([1, 2], [3, 4]) buffer, repack, _ = canonicalize(Tunable(), q) From 2d0766cc3bd7978aae3b2bb370d91344ab856046 Mon Sep 17 00:00:00 2001 From: Jash Date: Wed, 12 Aug 2026 19:55:01 +0530 Subject: [PATCH 3/4] Make SciMLStructures a dependency rather than an extension Review feedback: the package is small, so the interface moves from `ext/RecursiveArrayToolsSciMLStructuresExt.jl` into `src/scimlstructures.jl` and SciMLStructures becomes a direct dependency. --- Project.toml | 6 ++---- src/RecursiveArrayTools.jl | 2 ++ .../scimlstructures.jl | 6 ------ 3 files changed, 4 insertions(+), 10 deletions(-) rename ext/RecursiveArrayToolsSciMLStructuresExt.jl => src/scimlstructures.jl (95%) diff --git a/Project.toml b/Project.toml index dc579e70..50480f58 100644 --- a/Project.toml +++ b/Project.toml @@ -11,6 +11,7 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" SciMLPublic = "431bcebd-1456-4ced-9d72-93c2757fff0b" +SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" SymbolicIndexingInterface = "2efcf032-c050-4f8e-a9bb-153293bab1f5" @@ -24,7 +25,6 @@ Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" MonteCarloMeasurements = "0987c9cc-fe09-11e8-30f0-b96dd679fdca" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" -SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" @@ -42,7 +42,6 @@ RecursiveArrayToolsMeasurementsExt = "Measurements" RecursiveArrayToolsMonteCarloMeasurementsExt = "MonteCarloMeasurements" RecursiveArrayToolsMooncakeExt = "Mooncake" RecursiveArrayToolsReverseDiffExt = ["ReverseDiff", "Zygote"] -RecursiveArrayToolsSciMLStructuresExt = "SciMLStructures" RecursiveArrayToolsSparseArraysExt = ["SparseArrays"] RecursiveArrayToolsStatisticsExt = "Statistics" RecursiveArrayToolsStructArraysExt = "StructArrays" @@ -96,7 +95,6 @@ Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" RecursiveArrayToolsShorthandConstructors = "39fb7555-b4ad-4efd-8abe-30331df017d3" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" @@ -107,4 +105,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" [targets] -test = ["FastBroadcast", "KernelAbstractions", "Measurements", "Pkg", "Polyester", "Random", "RecursiveArrayToolsShorthandConstructors", "SafeTestsets", "SciMLStructures", "SciMLTesting", "SparseArrays", "StaticArrays", "Statistics", "StructArrays", "Tables", "Test", "Unitful"] +test = ["FastBroadcast", "KernelAbstractions", "Measurements", "Pkg", "Polyester", "Random", "RecursiveArrayToolsShorthandConstructors", "SafeTestsets", "SciMLTesting", "SparseArrays", "StaticArrays", "Statistics", "StructArrays", "Tables", "Test", "Unitful"] diff --git a/src/RecursiveArrayTools.jl b/src/RecursiveArrayTools.jl index e78f6451..2cf4f91f 100644 --- a/src/RecursiveArrayTools.jl +++ b/src/RecursiveArrayTools.jl @@ -14,6 +14,7 @@ module RecursiveArrayTools UnitUpperTriangular, UpperTriangular, ldiv!, mul! using RecipesBase: RecipesBase, @recipe using SciMLPublic: @public + using SciMLStructures: SciMLStructures, Tunable using StaticArraysCore: StaticArraysCore using SymbolicIndexingInterface: SymbolicIndexingInterface, ArraySymbolic, NotSymbolic, ParameterIndexingProxy, ParameterTimeseriesCollection, @@ -200,6 +201,7 @@ module RecursiveArrayTools include("vector_of_array.jl") include("array_partition.jl") include("named_array_partition.jl") + include("scimlstructures.jl") function Base.show(io::IO, x::ArrayPartition) return invoke(show, Tuple{typeof(io), Any}, io, x) diff --git a/ext/RecursiveArrayToolsSciMLStructuresExt.jl b/src/scimlstructures.jl similarity index 95% rename from ext/RecursiveArrayToolsSciMLStructuresExt.jl rename to src/scimlstructures.jl index 2f2f941f..62b08244 100644 --- a/ext/RecursiveArrayToolsSciMLStructuresExt.jl +++ b/src/scimlstructures.jl @@ -1,7 +1,3 @@ -module RecursiveArrayToolsSciMLStructuresExt - -using RecursiveArrayTools: ArrayPartition -using SciMLStructures: SciMLStructures, Tunable # SciMLStructures opts every numeric array into the interface and canonicalizes it # with `vec`. That is right for a contiguous array, but an `ArrayPartition` is @@ -85,5 +81,3 @@ function _offsets(p::ArrayPartition) end return offsets end - -end From ea619f5bd5abbc57dde080921419707d4ce6d8cf Mon Sep 17 00:00:00 2001 From: Jash Date: Wed, 12 Aug 2026 20:29:58 +0530 Subject: [PATCH 4/4] Drop a stray leading blank line Runic's format check flagged it; the file picked it up when the code moved out of the extension module. --- src/scimlstructures.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scimlstructures.jl b/src/scimlstructures.jl index 62b08244..23238871 100644 --- a/src/scimlstructures.jl +++ b/src/scimlstructures.jl @@ -1,4 +1,3 @@ - # SciMLStructures opts every numeric array into the interface and canonicalizes it # with `vec`. That is right for a contiguous array, but an `ArrayPartition` is # already an `AbstractVector`, so `vec` returns it unchanged and the buffer comes