From 34d8b6c63dc73643b4ea16016f539d4a480c3a8e Mon Sep 17 00:00:00 2001 From: ArnoStrouwen Date: Mon, 13 Feb 2023 23:53:44 +0100 Subject: [PATCH] various doc and style improvements --- .JuliaFormatter.toml | 1 + .github/workflows/FormatCheck.yml | 42 ++++ LICENSE.md | 5 +- README.md | 6 +- docs/make.jl | 32 +-- docs/pages.jl | 6 +- docs/src/array_types.md | 2 +- docs/src/index.md | 55 +++-- docs/src/recursive_array_functions.md | 2 +- ext/RecursiveArrayToolsTrackerExt.jl | 2 +- src/RecursiveArrayTools.jl | 2 +- src/array_partition.jl | 2 +- src/tabletraits.jl | 14 +- src/utils.jl | 257 +++++++++++++---------- src/vector_of_array.jl | 12 +- src/zygote.jl | 289 ++++++++++++++------------ test/adjoints.jl | 30 +-- test/basic_indexing.jl | 41 ++-- test/copy_static_array_test.jl | 24 +-- test/downstream/TrackerExt.jl | 4 +- test/downstream/downstream_events.jl | 43 ++-- test/downstream/symbol_indexing.jl | 27 ++- test/gpu.jl | 8 +- test/gpu/ode_gpu.jl | 18 +- test/gpu/vectorofarray_gpu.jl | 66 +++--- test/interface_tests.jl | 36 ++-- test/linalg.jl | 16 +- test/partitions_and_static_arrays.jl | 15 +- test/partitions_test.jl | 139 +++++++------ test/testutils.jl | 9 +- test/upstream.jl | 126 +++++------ test/utils_test.jl | 70 +++---- 32 files changed, 764 insertions(+), 637 deletions(-) create mode 100644 .github/workflows/FormatCheck.yml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index 580b7511..9c793591 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1 +1,2 @@ style = "sciml" +format_markdown = true \ No newline at end of file diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml new file mode 100644 index 00000000..2a3517a0 --- /dev/null +++ b/.github/workflows/FormatCheck.yml @@ -0,0 +1,42 @@ +name: format-check + +on: + push: + branches: + - 'master' + - 'release-' + tags: '*' + pull_request: + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + julia-version: [1] + julia-arch: [x86] + os: [ubuntu-latest] + steps: + - uses: julia-actions/setup-julia@latest + with: + version: ${{ matrix.julia-version }} + + - uses: actions/checkout@v1 + - name: Install JuliaFormatter and format + # This will use the latest version by default but you can set the version like so: + # + # julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter", version="0.13.0"))' + run: | + julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter"))' + julia -e 'using JuliaFormatter; format(".", verbose=true)' + - name: Format check + run: | + julia -e ' + out = Cmd(`git diff --name-only`) |> read |> String + if out == "" + exit(0) + else + @error "Some files have not been formatted !!!" + write(stdout, out) + exit(1) + end' diff --git a/LICENSE.md b/LICENSE.md index e484789b..adb75982 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -19,13 +19,10 @@ The RecursiveArrayTools.jl package is licensed under the MIT "Expat" License: > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE > SOFTWARE. -> The chain function is from Iterators.jl and is licensed under the MIT License: ->Copyright (c) 2012-2016: Daniel Jones, Stefan Karpinski, Simon Kornblith, Kevin Squire, Jeff Bezanson, Tim Holy, Jonathan Malmaud, Eric Davies, and other contributors. +> Copyright (c) 2012-2016: Daniel Jones, Stefan Karpinski, Simon Kornblith, Kevin Squire, Jeff Bezanson, Tim Holy, Jonathan Malmaud, Eric Davies, and other contributors. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - - diff --git a/README.md b/README.md index a9549fc3..af34685c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Build Status](https://github.com/SciML/RecursiveArrayTools.jl/workflows/CI/badge.svg)](https://github.com/SciML/RecursiveArrayTools.jl/actions?query=workflow%3ACI) [![build status](https://badge.buildkite.com/9eab94781cf0af9a3566e9b9f16abe5aea167b640b88065285.svg?branch=master)](https://buildkite.com/julialang/recursivearraytools-dot-jl) -[![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor's%20Guide-blueviolet)](https://github.com/SciML/ColPrac) +[![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor%27s%20Guide-blueviolet)](https://github.com/SciML/ColPrac) [![SciML Code Style](https://img.shields.io/static/v1?label=code%20style&message=SciML&color=9558b2&labelColor=389826)](https://github.com/SciML/SciMLStyle) RecursiveArrayTools.jl is a set of tools for dealing with recursive arrays like @@ -31,8 +31,8 @@ vB = VectorOfArray(b) vA .* vB # Now all standard array stuff works! -a = (rand(5),rand(5)) -b = (rand(5),rand(5)) +a = (rand(5), rand(5)) +b = (rand(5), rand(5)) pA = ArrayPartition(a) pB = ArrayPartition(b) diff --git a/docs/make.jl b/docs/make.jl index fedb38c0..0e3883f7 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,18 +5,22 @@ cp("./docs/Project.toml", "./docs/src/assets/Project.toml", force = true) include("pages.jl") -makedocs( - sitename="RecursiveArrayTools.jl", - authors="Chris Rackauckas", - modules=[RecursiveArrayTools], - clean=true,doctest=false, - format = Documenter.HTML(analytics = "UA-90474609-3", - assets = ["assets/favicon.ico"], - canonical="https://docs.sciml.ai/RecursiveArrayTools/stable/"), - pages=pages -) +makedocs(sitename = "RecursiveArrayTools.jl", + authors = "Chris Rackauckas", + modules = [RecursiveArrayTools], + clean = true, doctest = false, linkcheck = true, + strict = [ + :doctest, + :linkcheck, + :parse_error, + :example_block, + # Other available options are + # :autodocs_block, :cross_references, :docs_block, :eval_block, :example_block, :footnote, :meta_block, :missing_docs, :setup_block + ], + format = Documenter.HTML(analytics = "UA-90474609-3", + assets = ["assets/favicon.ico"], + canonical = "https://docs.sciml.ai/RecursiveArrayTools/stable/"), + pages = pages) -deploydocs( - repo = "github.com/SciML/RecursiveArrayTools.jl.git"; - push_preview = true -) +deploydocs(repo = "github.com/SciML/RecursiveArrayTools.jl.git"; + push_preview = true) diff --git a/docs/pages.jl b/docs/pages.jl index 90989bda..9ad69ca9 100644 --- a/docs/pages.jl +++ b/docs/pages.jl @@ -1,7 +1,7 @@ # Put in a separate page so it can be used by SciMLDocs.jl -pages=[ +pages = [ "Home" => "index.md", "array_types.md", - "recursive_array_functions.md" -] \ No newline at end of file + "recursive_array_functions.md", +] diff --git a/docs/src/array_types.md b/docs/src/array_types.md index cee5f4b4..79a59adf 100644 --- a/docs/src/array_types.md +++ b/docs/src/array_types.md @@ -13,4 +13,4 @@ mapping and iteration functions, and more. VectorOfArray DiffEqArray ArrayPartition -``` \ No newline at end of file +``` diff --git a/docs/src/index.md b/docs/src/index.md index 234270d9..79403ef7 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,6 +1,6 @@ # RecursiveArrayTools.jl: Arrays of Arrays and Even Deeper -RecursiveArrayTools.jl is a set of tools for dealing with recursive arrays like +RecursiveArrayTools.jl is a set of tools for dealing with recursive arrays, like arrays of arrays. It contains type wrappers for making recursive arrays act more like normal arrays (for example, automating the recursion of broadcast, maps, iteration, and more), and utility functions which make it easier to work with @@ -17,66 +17,87 @@ Pkg.add("RecursiveArrayTools") ## Contributing -- Please refer to the - [SciML ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://github.com/SciML/ColPrac/blob/master/README.md) - for guidance on PRs, issues, and other matters relating to contributing to SciML. -- There are a few community forums: - - the #diffeq-bridged channel in the [Julia Slack](https://julialang.org/slack/) - - [JuliaDiffEq](https://gitter.im/JuliaDiffEq/Lobby) on Gitter - - on the [Julia Discourse forums](https://discourse.julialang.org) - - see also [SciML Community page](https://sciml.ai/community/) + - Please refer to the + [SciML ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://github.com/SciML/ColPrac/blob/master/README.md) + for guidance on PRs, issues, and other matters relating to contributing to SciML. + + - See the [SciML Style Guide](https://github.com/SciML/SciMLStyle) for common coding practices and other style decisions. + - There are a few community forums: + + + The #diffeq-bridged and #sciml-bridged channels in the + [Julia Slack](https://julialang.org/slack/) + + The #diffeq-bridged and #sciml-bridged channels in the + [Julia Zulip](https://julialang.zulipchat.com/#narrow/stream/279055-sciml-bridged) + + On the [Julia Discourse forums](https://discourse.julialang.org) + + See also [SciML Community page](https://sciml.ai/community/) ## Reproducibility + ```@raw html
The documentation of this SciML package was built using these direct dependencies, ``` + ```@example using Pkg # hide Pkg.status() # hide ``` + ```@raw html
``` + ```@raw html
and using this machine and Julia version. ``` + ```@example using InteractiveUtils # hide versioninfo() # hide ``` + ```@raw html
``` + ```@raw html
A more complete overview of all dependencies and their versions is also provided. ``` + ```@example using Pkg # hide -Pkg.status(;mode = PKGMODE_MANIFEST) # hide +Pkg.status(; mode = PKGMODE_MANIFEST) # hide ``` + ```@raw html
``` + ```@raw html You can also download the manifest file and the project file. -``` \ No newline at end of file +``` diff --git a/docs/src/recursive_array_functions.md b/docs/src/recursive_array_functions.md index b2df1ca4..1bb31691 100644 --- a/docs/src/recursive_array_functions.md +++ b/docs/src/recursive_array_functions.md @@ -10,4 +10,4 @@ recursivecopy recursivecopy! vecvecapply copyat_or_push! -``` \ No newline at end of file +``` diff --git a/ext/RecursiveArrayToolsTrackerExt.jl b/ext/RecursiveArrayToolsTrackerExt.jl index 43c7f4a7..a06163c2 100644 --- a/ext/RecursiveArrayToolsTrackerExt.jl +++ b/ext/RecursiveArrayToolsTrackerExt.jl @@ -15,4 +15,4 @@ function RecursiveArrayTools.recursivecopy!(b::AbstractArray{T, N}, end end -end \ No newline at end of file +end diff --git a/src/RecursiveArrayTools.jl b/src/RecursiveArrayTools.jl index c93ca011..39805654 100644 --- a/src/RecursiveArrayTools.jl +++ b/src/RecursiveArrayTools.jl @@ -45,7 +45,7 @@ end import Requires @static if !isdefined(Base, :get_extension) function __init__() - Requires.@require Tracker="9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" begin include("../ext/RecursiveArrayToolsTrackerExt.jl") end + Requires.@require Tracker="9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" begin include("../ext/RecursiveArrayToolsTrackerExt.jl") end end end diff --git a/src/array_partition.jl b/src/array_partition.jl index 148971de..aeff0416 100644 --- a/src/array_partition.jl +++ b/src/array_partition.jl @@ -18,7 +18,7 @@ Thus, for: ```julia using RecursiveArrayTools -A = ArrayPartition(y,z) +A = ArrayPartition(y, z) ``` we would have `A.x[1]==y` and `A.x[2]==z`. Broadcasting like `f.(A)` is efficient. diff --git a/src/tabletraits.jl b/src/tabletraits.jl index f8799aa5..71ba06aa 100644 --- a/src/tabletraits.jl +++ b/src/tabletraits.jl @@ -7,12 +7,17 @@ function Tables.rows(A::AbstractDiffEqArray) N = length(A.u[1]) names = [ :timestamp, - (!(A.sc isa SymbolicIndexingInterface.SymbolCache{Nothing, Nothing, Nothing}) ? (states(A.sc)[i] for i in 1:N) : + (!(A.sc isa SymbolicIndexingInterface.SymbolCache{Nothing, Nothing, Nothing}) ? + (states(A.sc)[i] for i in 1:N) : (Symbol("value", i) for i in 1:N))..., ] types = Type[eltype(A.t), (eltype(A.u[1]) for _ in 1:N)...] else - names = [:timestamp, !(A.sc isa SymbolicIndexingInterface.SymbolCache{Nothing, Nothing, Nothing}) ? states(A.sc)[1] : :value] + names = [ + :timestamp, + !(A.sc isa SymbolicIndexingInterface.SymbolCache{Nothing, Nothing, Nothing}) ? + states(A.sc)[1] : :value, + ] types = Type[eltype(A.t), VT] end return AbstractDiffEqArrayRows(names, types, A.t, A.u) @@ -32,14 +37,15 @@ struct AbstractDiffEqArrayRows{T, U} end function AbstractDiffEqArrayRows(names, types, t, u) AbstractDiffEqArrayRows(Symbol.(names), types, - Dict(Symbol(nm) => i for (i, nm) in enumerate(names)), t, u) + Dict(Symbol(nm) => i for (i, nm) in enumerate(names)), t, u) end Base.length(x::AbstractDiffEqArrayRows) = length(x.u) function Base.eltype(::Type{AbstractDiffEqArrayRows{T, U}}) where {T, U} AbstractDiffEqArrayRow{eltype(T), eltype(U)} end -function Base.iterate(x::AbstractDiffEqArrayRows, (t_state, u_state)=(iterate(x.t), iterate(x.u))) +function Base.iterate(x::AbstractDiffEqArrayRows, + (t_state, u_state) = (iterate(x.t), iterate(x.u))) t_state === nothing && return nothing u_state === nothing && return nothing t, _t_state = t_state diff --git a/src/utils.jl b/src/utils.jl index 907d04e2..5112838e 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,32 +1,34 @@ """ ```julia -recursivecopy(b::AbstractArray{T,N},a::AbstractArray{T,N}) +recursivecopy(b::AbstractArray{T, N}, a::AbstractArray{T, N}) ``` A recursive `copy` function. Acts like a `deepcopy` on arrays of arrays, but like `copy` on arrays of scalars. """ function recursivecopy(a) - deepcopy(a) + deepcopy(a) end -recursivecopy(a::Union{StaticArraysCore.SVector,StaticArraysCore.SMatrix, - StaticArraysCore.SArray,Number}) = copy(a) -function recursivecopy(a::AbstractArray{T,N}) where {T<:Number,N} - copy(a) +function recursivecopy(a::Union{StaticArraysCore.SVector, StaticArraysCore.SMatrix, + StaticArraysCore.SArray, Number}) + copy(a) +end +function recursivecopy(a::AbstractArray{T, N}) where {T <: Number, N} + copy(a) end -function recursivecopy(a::AbstractArray{T,N}) where {T<:AbstractArray,N} - if ArrayInterfaceCore.ismutable(a) - b = similar(a) - map!(recursivecopy, b, a) - else - ArrayInterfaceCore.restructure(a, map(recursivecopy, a)) - end +function recursivecopy(a::AbstractArray{T, N}) where {T <: AbstractArray, N} + if ArrayInterfaceCore.ismutable(a) + b = similar(a) + map!(recursivecopy, b, a) + else + ArrayInterfaceCore.restructure(a, map(recursivecopy, a)) + end end """ ```julia -recursivecopy!(b::AbstractArray{T,N},a::AbstractArray{T,N}) +recursivecopy!(b::AbstractArray{T, N}, a::AbstractArray{T, N}) ``` A recursive `copy!` function. Acts like a `deepcopy!` on arrays of arrays, but @@ -34,148 +36,162 @@ like `copy!` on arrays of scalars. """ function recursivecopy! end -function recursivecopy!(b::AbstractArray{T,N},a::AbstractArray{T2,N}) where {T<:StaticArraysCore.StaticArray,T2<:StaticArraysCore.StaticArray,N} - @inbounds for i in eachindex(a) - # TODO: Check for `setindex!`` and use `copy!(b[i],a[i])` or `b[i] = a[i]`, see #19 - b[i] = copy(a[i]) - end +function recursivecopy!(b::AbstractArray{T, N}, + a::AbstractArray{T2, N}) where {T <: StaticArraysCore.StaticArray, + T2 <: StaticArraysCore.StaticArray, + N} + @inbounds for i in eachindex(a) + # TODO: Check for `setindex!`` and use `copy!(b[i],a[i])` or `b[i] = a[i]`, see #19 + b[i] = copy(a[i]) + end end -function recursivecopy!(b::AbstractArray{T,N},a::AbstractArray{T2,N}) where {T<:Enum,T2<:Enum,N} - copyto!(b,a) +function recursivecopy!(b::AbstractArray{T, N}, + a::AbstractArray{T2, N}) where {T <: Enum, T2 <: Enum, N} + copyto!(b, a) end -function recursivecopy!(b::AbstractArray{T,N},a::AbstractArray{T2,N}) where {T<:Number,T2<:Number,N} - copyto!(b,a) +function recursivecopy!(b::AbstractArray{T, N}, + a::AbstractArray{T2, N}) where {T <: Number, T2 <: Number, N} + copyto!(b, a) end -function recursivecopy!(b::AbstractArray{T,N},a::AbstractArray{T2,N}) where {T<:AbstractArray,T2<:AbstractArray,N} - if ArrayInterfaceCore.ismutable(T) - @inbounds for i in eachindex(b, a) - recursivecopy!(b[i], a[i]) +function recursivecopy!(b::AbstractArray{T, N}, + a::AbstractArray{T2, N}) where {T <: AbstractArray, + T2 <: AbstractArray, N} + if ArrayInterfaceCore.ismutable(T) + @inbounds for i in eachindex(b, a) + recursivecopy!(b[i], a[i]) + end + else + copyto!(b, a) end - else - copyto!(b, a) - end - return b + return b end """ ```julia -recursivefill!(b::AbstractArray{T,N},a) +recursivefill!(b::AbstractArray{T, N}, a) ``` A recursive `fill!` function. """ function recursivefill! end -function recursivefill!(b::AbstractArray{T,N},a::T2) where {T<:StaticArraysCore.StaticArray,T2<:StaticArraysCore.StaticArray,N} - @inbounds for i in eachindex(b) - b[i] = copy(a) - end +function recursivefill!(b::AbstractArray{T, N}, + a::T2) where {T <: StaticArraysCore.StaticArray, + T2 <: StaticArraysCore.StaticArray, N} + @inbounds for i in eachindex(b) + b[i] = copy(a) + end end -function recursivefill!(b::AbstractArray{T,N},a::T2) where {T<:StaticArraysCore.SArray,T2<:Union{Number,Bool},N} - @inbounds for i in eachindex(b) - b[i] = fill(a, typeof(b[i])) - end +function recursivefill!(b::AbstractArray{T, N}, + a::T2) where {T <: StaticArraysCore.SArray, + T2 <: Union{Number, Bool}, N} + @inbounds for i in eachindex(b) + b[i] = fill(a, typeof(b[i])) + end end -function recursivefill!(b::AbstractArray{T,N},a::T2) where {T<:Enum,T2<:Enum,N} - fill!(b,a) +function recursivefill!(b::AbstractArray{T, N}, a::T2) where {T <: Enum, T2 <: Enum, N} + fill!(b, a) end -function recursivefill!(b::AbstractArray{T,N},a::T2) where {T<:Union{Number,Bool},T2<:Union{Number,Bool},N} - fill!(b, a) +function recursivefill!(b::AbstractArray{T, N}, + a::T2) where {T <: Union{Number, Bool}, T2 <: Union{Number, Bool}, N + } + fill!(b, a) end -function recursivefill!(b::AbstractArray{T,N},a) where {T<:StaticArraysCore.MArray,N} - @inbounds for i in eachindex(b) - if isassigned(b,i) - recursivefill!(b[i],a) - else - b[i] = zero(eltype(b)) - recursivefill!(b[i], a) +function recursivefill!(b::AbstractArray{T, N}, a) where {T <: StaticArraysCore.MArray, N} + @inbounds for i in eachindex(b) + if isassigned(b, i) + recursivefill!(b[i], a) + else + b[i] = zero(eltype(b)) + recursivefill!(b[i], a) + end end - end end -function recursivefill!(b::AbstractArray{T,N},a) where {T<:AbstractArray,N} - @inbounds for i in eachindex(b) - recursivefill!(b[i], a) - end - return b +function recursivefill!(b::AbstractArray{T, N}, a) where {T <: AbstractArray, N} + @inbounds for i in eachindex(b) + recursivefill!(b[i], a) + end + return b end # Deprecated function vecvec_to_mat(vecvec) - mat = Matrix{eltype(eltype(vecvec))}(undef, length(vecvec),length(vecvec[1])) - for i in 1:length(vecvec) - mat[i,:] = vecvec[i] - end - mat + mat = Matrix{eltype(eltype(vecvec))}(undef, length(vecvec), length(vecvec[1])) + for i in 1:length(vecvec) + mat[i, :] = vecvec[i] + end + mat end """ ```julia -vecvecapply(f::Base.Callable,v) +vecvecapply(f::Base.Callable, v) ``` Calls `f` on each element of a vecvec `v`. """ -function vecvecapply(f,v) - sol = Vector{eltype(eltype(v))}() - for i in eachindex(v) - for j in eachindex(v[i]) - push!(sol,v[i][j]) +function vecvecapply(f, v) + sol = Vector{eltype(eltype(v))}() + for i in eachindex(v) + for j in eachindex(v[i]) + push!(sol, v[i][j]) + end end - end - f(sol) + f(sol) end -function vecvecapply(f,v::Array{T}) where T<:Number - f(v) +function vecvecapply(f, v::Array{T}) where {T <: Number} + f(v) end -function vecvecapply(f,v::T) where T<:Number - f(v) +function vecvecapply(f, v::T) where {T <: Number} + f(v) end """ ```julia -copyat_or_push!{T}(a::AbstractVector{T},i::Int,x) +copyat_or_push!{T}(a::AbstractVector{T}, i::Int, x) ``` If `i= i - if !ArrayInterfaceCore.ismutable(T) || !perform_copy - # TODO: Check for `setindex!`` if T <: StaticArraysCore.StaticArray and use `copy!(b[i],a[i])` - # or `b[i] = a[i]`, see https://github.com/JuliaDiffEq/RecursiveArrayTools.jl/issues/19 - a[i] = x +""" +function copyat_or_push!(a::AbstractVector{T}, i::Int, x, perform_copy = true) where {T} + @inbounds if length(a) >= i + if !ArrayInterfaceCore.ismutable(T) || !perform_copy + # TODO: Check for `setindex!`` if T <: StaticArraysCore.StaticArray and use `copy!(b[i],a[i])` + # or `b[i] = a[i]`, see https://github.com/JuliaDiffEq/RecursiveArrayTools.jl/issues/19 + a[i] = x + else + if length(a[i]) == length(x) + recursivecopy!(a[i], x) + else + a[i] = recursivecopy(x) + end + end else - if length(a[i]) == length(x) - recursivecopy!(a[i],x) - else - a[i] = recursivecopy(x) - end + if perform_copy + push!(a, recursivecopy(x)) + else + push!(a, x) + end end - else - if perform_copy - push!(a,recursivecopy(x)) - else - push!(a,x) - end - end - nothing + nothing end - -function copyat_or_push!(a::AbstractVector{T},i::Int,x,nc::Type{Val{perform_copy}}) where {T, perform_copy} - copyat_or_push!(a,i,x,perform_copy) + +function copyat_or_push!(a::AbstractVector{T}, i::Int, x, + nc::Type{Val{perform_copy}}) where {T, perform_copy} + copyat_or_push!(a, i, x, perform_copy) end - + """ ```julia recursive_one(a) @@ -184,7 +200,7 @@ recursive_one(a) Calls `one` on the bottom container to get the "true element one type". """ recursive_one(a) = recursive_one(a[1]) -recursive_one(a::T) where {T<:Number} = one(a) +recursive_one(a::T) where {T <: Number} = one(a) recursive_bottom_eltype(a) = a == eltype(a) ? a : recursive_bottom_eltype(eltype(a)) @@ -198,10 +214,16 @@ ones has a `Array{Array{Float64,N},N}`, this will return `Float64`. """ recursive_unitless_bottom_eltype(a) = recursive_unitless_bottom_eltype(typeof(a)) recursive_unitless_bottom_eltype(a::Type{Any}) = Any -recursive_unitless_bottom_eltype(a::Type{T}) where T = recursive_unitless_bottom_eltype(eltype(a)) -recursive_unitless_bottom_eltype(a::Type{T}) where {T<:AbstractArray} = recursive_unitless_bottom_eltype(eltype(a)) -recursive_unitless_bottom_eltype(a::Type{T}) where {T<:Number} = eltype(a) == Number ? Float64 : typeof(one(eltype(a))) -recursive_unitless_bottom_eltype(::Type{<:Enum{T}}) where T = T +function recursive_unitless_bottom_eltype(a::Type{T}) where {T} + recursive_unitless_bottom_eltype(eltype(a)) +end +function recursive_unitless_bottom_eltype(a::Type{T}) where {T <: AbstractArray} + recursive_unitless_bottom_eltype(eltype(a)) +end +function recursive_unitless_bottom_eltype(a::Type{T}) where {T <: Number} + eltype(a) == Number ? Float64 : typeof(one(eltype(a))) +end +recursive_unitless_bottom_eltype(::Type{<:Enum{T}}) where {T} = T """ ```julia @@ -214,25 +236,29 @@ ones has a `Array{Array{Float64,N},N}`, this will return `Array{Float64,N}`. recursive_unitless_eltype(a) = recursive_unitless_eltype(eltype(a)) recursive_unitless_eltype(a::Type{Any}) = Any -recursive_unitless_eltype(a::Type{T}) where {T<:StaticArraysCore.StaticArray} = StaticArraysCore.similar_type(a, recursive_unitless_eltype(eltype(a))) +function recursive_unitless_eltype(a::Type{T}) where {T <: StaticArraysCore.StaticArray} + StaticArraysCore.similar_type(a, recursive_unitless_eltype(eltype(a))) +end -recursive_unitless_eltype(a::Type{T}) where {T<:Array} = Array{recursive_unitless_eltype(eltype(a)),ndims(a)} -recursive_unitless_eltype(a::Type{T}) where {T<:Number} = typeof(one(eltype(a))) -recursive_unitless_eltype(::Type{<:Enum{T}}) where T = T +function recursive_unitless_eltype(a::Type{T}) where {T <: Array} + Array{recursive_unitless_eltype(eltype(a)), ndims(a)} +end +recursive_unitless_eltype(a::Type{T}) where {T <: Number} = typeof(one(eltype(a))) +recursive_unitless_eltype(::Type{<:Enum{T}}) where {T} = T recursive_mean(x...) = mean(x...) -function recursive_mean(vecvec::Vector{T}) where T<:AbstractArray - out = zero(vecvec[1]) - for i in eachindex(vecvec) - out+= vecvec[i] - end - out/length(vecvec) +function recursive_mean(vecvec::Vector{T}) where {T <: AbstractArray} + out = zero(vecvec[1]) + for i in eachindex(vecvec) + out += vecvec[i] + end + out / length(vecvec) end # From Iterators.jl. Moved here since Iterators.jl is not precompile safe anymore. # Concatenate the output of n iterators -struct Chain{T<:Tuple} +struct Chain{T <: Tuple} xss::T end @@ -242,6 +268,7 @@ end chain(xs...) Iterate through any number of iterators in sequence. + ```jldoctest julia> for i in chain(1:3, ['a', 'b', 'c']) @show i diff --git a/src/vector_of_array.jl b/src/vector_of_array.jl index 01efb8d8..e734125c 100644 --- a/src/vector_of_array.jl +++ b/src/vector_of_array.jl @@ -12,16 +12,16 @@ structure is: ```julia A[i] # Returns the ith array in the vector of arrays -A[j,i] # Returns the jth component in the ith array -A[j1,...,jN,i] # Returns the (j1,...,jN) component of the ith array +A[j, i] # Returns the jth component in the ith array +A[j1, ..., jN, i] # Returns the (j1,...,jN) component of the ith array ``` which presents itself as a column-major matrix with the columns being the arrays from the vector. The `AbstractArray` interface is implemented, giving access to `copy`, `push`, `append!`, etc. functions, which act appropriately. Points to note are: -- The length is the number of vectors, or `length(A.u)` where `u` is the vector of arrays. -- Iteration follows the linear index and goes over the vectors + - The length is the number of vectors, or `length(A.u)` where `u` is the vector of arrays. + - Iteration follows the linear index and goes over the vectors Additionally, the `convert(Array,VA::AbstractVectorOfArray)` function is provided, which transforms the `VectorOfArray` into a matrix/tensor. Also, `vecarr_to_vectors(VA::AbstractVectorOfArray)` @@ -35,7 +35,7 @@ end """ ```julia -DiffEqArray(u::AbstractVector,t::AbstractVector) +DiffEqArray(u::AbstractVector, t::AbstractVector) ``` This is a `VectorOfArray`, which stores `A.t` that matches `A.u`. This will plot @@ -49,7 +49,7 @@ f(t) = t - 1 f2(t) = t^2 vals = [[f(tval) f2(tval)] for tval in t] A = DiffEqArray(vals, t) -A[1,:] # all time periods for f(t) +A[1, :] # all time periods for f(t) A.t ``` """ diff --git a/src/zygote.jl b/src/zygote.jl index 8b795c40..15672da8 100644 --- a/src/zygote.jl +++ b/src/zygote.jl @@ -1,129 +1,160 @@ -function ChainRulesCore.rrule(::typeof(getindex),VA::AbstractVectorOfArray, i::Union{Int,AbstractArray{Int},CartesianIndex,Colon,BitArray,AbstractArray{Bool}}) - function AbstractVectorOfArray_getindex_adjoint(Δ) - Δ′ = [ (i == j ? Δ : zero(x)) for (x,j) in zip(VA.u, 1:length(VA))] - (NoTangent(),VectorOfArray(Δ′),NoTangent()) - end - VA[i],AbstractVectorOfArray_getindex_adjoint -end - -function ChainRulesCore.rrule(::typeof(getindex),VA::AbstractVectorOfArray, indices::Union{Int,AbstractArray{Int},CartesianIndex,Colon,BitArray,AbstractArray{Bool}}...) - function AbstractVectorOfArray_getindex_adjoint(Δ) - Δ′ = zero(VA) - Δ′[indices...] = Δ - (NoTangent(), VectorOfArray(Δ′), map(_ -> NoTangent(), indices)...) - end - VA[indices...],AbstractVectorOfArray_getindex_adjoint -end - -function ChainRulesCore.rrule(::Type{<:ArrayPartition}, x::S, ::Type{Val{copy_x}} = Val{false}) where {S<:Tuple,copy_x} - function ArrayPartition_adjoint(_y) - y = Array(_y) - starts = vcat(0,cumsum(reduce(vcat,length.(x)))) - NoTangent(), ntuple(i -> reshape(y[starts[i]+1:starts[i+1]], size(x[i])), length(x)), NoTangent() - end - - ArrayPartition(x, Val{copy_x}), ArrayPartition_adjoint -end - -function ChainRulesCore.rrule(::Type{<:VectorOfArray},u) - VectorOfArray(u),y -> (NoTangent(),[y[ntuple(x->Colon(),ndims(y)-1)...,i] for i in 1:size(y)[end]]) -end - -function ChainRulesCore.rrule(::Type{<:DiffEqArray},u,t) - DiffEqArray(u,t),y -> (NoTangent(),[y[ntuple(x->Colon(),ndims(y)-1)...,i] for i in 1:size(y)[end]],NoTangent()) -end - -function ChainRulesCore.rrule(::typeof(getproperty),A::ArrayPartition, s::Symbol) - if s !== :x - error("$s is not a field of ArrayPartition") - end - function literal_ArrayPartition_x_adjoint(d) - (NoTangent(),ArrayPartition((isnothing(d[i]) ? zero(A.x[i]) : d[i] for i in 1:length(d))...)) - end - A.x,literal_ArrayPartition_x_adjoint -end - -# Define a new species of projection operator for this type: -ChainRulesCore.ProjectTo(x::VectorOfArray) = ChainRulesCore.ProjectTo{VectorOfArray}() - -# Gradient from iteration will be e.g. Vector{Vector}, this makes it another AbstractMatrix -#(::ChainRulesCore.ProjectTo{VectorOfArray})(dx::AbstractVector{<:AbstractArray}) = VectorOfArray(dx) -# Gradient from broadcasting will be another AbstractArray -#(::ChainRulesCore.ProjectTo{VectorOfArray})(dx::AbstractArray) = dx - -# These rules duplicate the `rrule` methods above, because Zygote looks for an `@adjoint` -# definition first, and finds its own before finding those. - -ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::Int) - function AbstractVectorOfArray_getindex_adjoint(Δ) - Δ′ = [(i == j ? Δ : Fill(zero(eltype(x)),size(x))) for (x,j) in zip(VA.u, 1:length(VA))] - (VectorOfArray(Δ′),nothing) - end - VA[i],AbstractVectorOfArray_getindex_adjoint -end - -ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::Union{BitArray,AbstractArray{Bool}}) - function AbstractVectorOfArray_getindex_adjoint(Δ) - Δ′ = [(i[j] ? Δ[j] : Fill(zero(eltype(x)),size(x))) for (x,j) in zip(VA.u, 1:length(VA))] - (VectorOfArray(Δ′),nothing) - end - VA[i],AbstractVectorOfArray_getindex_adjoint -end - -ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::AbstractArray{Int}) - function AbstractVectorOfArray_getindex_adjoint(Δ) - iter = 0 - Δ′ = [(j ∈ i ? Δ[iter+=1] : Fill(zero(eltype(x)),size(x))) for (x,j) in zip(VA.u, 1:length(VA))] - (VectorOfArray(Δ′),nothing) - end - VA[i],AbstractVectorOfArray_getindex_adjoint -end - -ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::Union{Int,AbstractArray{Int}}) - function AbstractVectorOfArray_getindex_adjoint(Δ) - Δ′ = [(i[j] ? Δ[j] : Fill(zero(eltype(x)),size(x))) for (x,j) in zip(VA.u, 1:length(VA))] - (VectorOfArray(Δ′),nothing) - end - VA[i],AbstractVectorOfArray_getindex_adjoint -end - -ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::Colon) - function AbstractVectorOfArray_getindex_adjoint(Δ) - (VectorOfArray(Δ),nothing) - end - VA[i],AbstractVectorOfArray_getindex_adjoint -end - -ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::Int, j::Union{Int,AbstractArray{Int},CartesianIndex,Colon,BitArray,AbstractArray{Bool}}...) - function AbstractVectorOfArray_getindex_adjoint(Δ) - Δ′ = VectorOfArray([zero(x) for (x,j) in zip(VA.u, 1:length(VA))]) - Δ′[i,j...] = Δ - (Δ′, nothing, map(_ -> nothing, j)...) - end - VA[i,j...],AbstractVectorOfArray_getindex_adjoint -end - -ZygoteRules.@adjoint function ArrayPartition(x::S, ::Type{Val{copy_x}} = Val{false}) where {S<:Tuple,copy_x} - function ArrayPartition_adjoint(_y) - y = Array(_y) - starts = vcat(0,cumsum(reduce(vcat,length.(x)))) - ntuple(i -> reshape(y[starts[i]+1:starts[i+1]], size(x[i])), length(x)), nothing - end - - ArrayPartition(x, Val{copy_x}), ArrayPartition_adjoint -end - -ZygoteRules.@adjoint function VectorOfArray(u) - VectorOfArray(u),y -> (VectorOfArray([y[ntuple(x->Colon(),ndims(y)-1)...,i] for i in 1:size(y)[end]]),) -end - -ZygoteRules.@adjoint function DiffEqArray(u,t) - DiffEqArray(u,t),y -> (DiffEqArray([y[ntuple(x->Colon(),ndims(y)-1)...,i] for i in 1:size(y)[end]],t),nothing) -end - -ZygoteRules.@adjoint function ZygoteRules.literal_getproperty(A::ArrayPartition, ::Val{:x}) - function literal_ArrayPartition_x_adjoint(d) - (ArrayPartition((isnothing(d[i]) ? zero(A.x[i]) : d[i] for i in 1:length(d))...),) - end - A.x,literal_ArrayPartition_x_adjoint -end +function ChainRulesCore.rrule(::typeof(getindex), VA::AbstractVectorOfArray, + i::Union{Int, AbstractArray{Int}, CartesianIndex, Colon, + BitArray, AbstractArray{Bool}}) + function AbstractVectorOfArray_getindex_adjoint(Δ) + Δ′ = [(i == j ? Δ : zero(x)) for (x, j) in zip(VA.u, 1:length(VA))] + (NoTangent(), VectorOfArray(Δ′), NoTangent()) + end + VA[i], AbstractVectorOfArray_getindex_adjoint +end + +function ChainRulesCore.rrule(::typeof(getindex), VA::AbstractVectorOfArray, + indices::Union{Int, AbstractArray{Int}, CartesianIndex, Colon, + BitArray, AbstractArray{Bool}}...) + function AbstractVectorOfArray_getindex_adjoint(Δ) + Δ′ = zero(VA) + Δ′[indices...] = Δ + (NoTangent(), VectorOfArray(Δ′), map(_ -> NoTangent(), indices)...) + end + VA[indices...], AbstractVectorOfArray_getindex_adjoint +end + +function ChainRulesCore.rrule(::Type{<:ArrayPartition}, x::S, + ::Type{Val{copy_x}} = Val{false}) where {S <: Tuple, copy_x} + function ArrayPartition_adjoint(_y) + y = Array(_y) + starts = vcat(0, cumsum(reduce(vcat, length.(x)))) + NoTangent(), + ntuple(i -> reshape(y[(starts[i] + 1):starts[i + 1]], size(x[i])), length(x)), + NoTangent() + end + + ArrayPartition(x, Val{copy_x}), ArrayPartition_adjoint +end + +function ChainRulesCore.rrule(::Type{<:VectorOfArray}, u) + VectorOfArray(u), + y -> (NoTangent(), + [y[ntuple(x -> Colon(), ndims(y) - 1)..., i] for i in 1:size(y)[end]]) +end + +function ChainRulesCore.rrule(::Type{<:DiffEqArray}, u, t) + DiffEqArray(u, t), + y -> (NoTangent(), + [y[ntuple(x -> Colon(), ndims(y) - 1)..., i] for i in 1:size(y)[end]], + NoTangent()) +end + +function ChainRulesCore.rrule(::typeof(getproperty), A::ArrayPartition, s::Symbol) + if s !== :x + error("$s is not a field of ArrayPartition") + end + function literal_ArrayPartition_x_adjoint(d) + (NoTangent(), + ArrayPartition((isnothing(d[i]) ? zero(A.x[i]) : d[i] for i in 1:length(d))...)) + end + A.x, literal_ArrayPartition_x_adjoint +end + +# Define a new species of projection operator for this type: +ChainRulesCore.ProjectTo(x::VectorOfArray) = ChainRulesCore.ProjectTo{VectorOfArray}() + +# Gradient from iteration will be e.g. Vector{Vector}, this makes it another AbstractMatrix +#(::ChainRulesCore.ProjectTo{VectorOfArray})(dx::AbstractVector{<:AbstractArray}) = VectorOfArray(dx) +# Gradient from broadcasting will be another AbstractArray +#(::ChainRulesCore.ProjectTo{VectorOfArray})(dx::AbstractArray) = dx + +# These rules duplicate the `rrule` methods above, because Zygote looks for an `@adjoint` +# definition first, and finds its own before finding those. + +ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::Int) + function AbstractVectorOfArray_getindex_adjoint(Δ) + Δ′ = [(i == j ? Δ : Fill(zero(eltype(x)), size(x))) + for (x, j) in zip(VA.u, 1:length(VA))] + (VectorOfArray(Δ′), nothing) + end + VA[i], AbstractVectorOfArray_getindex_adjoint +end + +ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, + i::Union{BitArray, AbstractArray{Bool}}) + function AbstractVectorOfArray_getindex_adjoint(Δ) + Δ′ = [(i[j] ? Δ[j] : Fill(zero(eltype(x)), size(x))) + for (x, j) in zip(VA.u, 1:length(VA))] + (VectorOfArray(Δ′), nothing) + end + VA[i], AbstractVectorOfArray_getindex_adjoint +end + +ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::AbstractArray{Int}) + function AbstractVectorOfArray_getindex_adjoint(Δ) + iter = 0 + Δ′ = [(j ∈ i ? Δ[iter += 1] : Fill(zero(eltype(x)), size(x))) + for (x, j) in zip(VA.u, 1:length(VA))] + (VectorOfArray(Δ′), nothing) + end + VA[i], AbstractVectorOfArray_getindex_adjoint +end + +ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, + i::Union{Int, AbstractArray{Int}}) + function AbstractVectorOfArray_getindex_adjoint(Δ) + Δ′ = [(i[j] ? Δ[j] : Fill(zero(eltype(x)), size(x))) + for (x, j) in zip(VA.u, 1:length(VA))] + (VectorOfArray(Δ′), nothing) + end + VA[i], AbstractVectorOfArray_getindex_adjoint +end + +ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::Colon) + function AbstractVectorOfArray_getindex_adjoint(Δ) + (VectorOfArray(Δ), nothing) + end + VA[i], AbstractVectorOfArray_getindex_adjoint +end + +ZygoteRules.@adjoint function getindex(VA::AbstractVectorOfArray, i::Int, + j::Union{Int, AbstractArray{Int}, CartesianIndex, + Colon, BitArray, AbstractArray{Bool}}...) + function AbstractVectorOfArray_getindex_adjoint(Δ) + Δ′ = VectorOfArray([zero(x) for (x, j) in zip(VA.u, 1:length(VA))]) + Δ′[i, j...] = Δ + (Δ′, nothing, map(_ -> nothing, j)...) + end + VA[i, j...], AbstractVectorOfArray_getindex_adjoint +end + +ZygoteRules.@adjoint function ArrayPartition(x::S, + ::Type{Val{copy_x}} = Val{false}) where { + S <: + Tuple, + copy_x + } + function ArrayPartition_adjoint(_y) + y = Array(_y) + starts = vcat(0, cumsum(reduce(vcat, length.(x)))) + ntuple(i -> reshape(y[(starts[i] + 1):starts[i + 1]], size(x[i])), length(x)), + nothing + end + + ArrayPartition(x, Val{copy_x}), ArrayPartition_adjoint +end + +ZygoteRules.@adjoint function VectorOfArray(u) + VectorOfArray(u), + y -> (VectorOfArray([y[ntuple(x -> Colon(), ndims(y) - 1)..., i] + for i in 1:size(y)[end]]),) +end + +ZygoteRules.@adjoint function DiffEqArray(u, t) + DiffEqArray(u, t), + y -> (DiffEqArray([y[ntuple(x -> Colon(), ndims(y) - 1)..., i] for i in 1:size(y)[end]], + t), nothing) +end + +ZygoteRules.@adjoint function ZygoteRules.literal_getproperty(A::ArrayPartition, ::Val{:x}) + function literal_ArrayPartition_x_adjoint(d) + (ArrayPartition((isnothing(d[i]) ? zero(A.x[i]) : d[i] for i in 1:length(d))...),) + end + A.x, literal_ArrayPartition_x_adjoint +end diff --git a/test/adjoints.jl b/test/adjoints.jl index d26547f6..a6abb445 100644 --- a/test/adjoints.jl +++ b/test/adjoints.jl @@ -2,46 +2,46 @@ using RecursiveArrayTools, Zygote, ForwardDiff, Test using OrdinaryDiffEq function loss(x) - sum(abs2,Array(VectorOfArray([x .* i for i in 1:5]))) + sum(abs2, Array(VectorOfArray([x .* i for i in 1:5]))) end function loss2(x) - sum(abs2,Array(DiffEqArray([x .* i for i in 1:5],1:5))) + sum(abs2, Array(DiffEqArray([x .* i for i in 1:5], 1:5))) end function loss3(x) y = VectorOfArray([x .* i for i in 1:5]) tmp = 0.0 for i in 1:5, j in 1:5 - tmp += y[i,j] + tmp += y[i, j] end tmp end function loss4(x) - y = DiffEqArray([x .* i for i in 1:5],1:5) + y = DiffEqArray([x .* i for i in 1:5], 1:5) tmp = 0.0 for i in 1:5, j in 1:5 - tmp += y[i,j] + tmp += y[i, j] end tmp end function loss5(x) - sum(abs2,Array(ArrayPartition([x .* i for i in 1:5]...))) + sum(abs2, Array(ArrayPartition([x .* i for i in 1:5]...))) end function loss6(x) - _x = ArrayPartition([x .* i for i in 1:5]...) - _prob = ODEProblem((u,p,t)->u, _x, (0,1)) - sum(abs2, Array(_prob.u0)) + _x = ArrayPartition([x .* i for i in 1:5]...) + _prob = ODEProblem((u, p, t) -> u, _x, (0, 1)) + sum(abs2, Array(_prob.u0)) end x = float.(6:10) loss(x) -@test Zygote.gradient(loss,x)[1] == ForwardDiff.gradient(loss,x) -@test Zygote.gradient(loss2,x)[1] == ForwardDiff.gradient(loss2,x) -@test Zygote.gradient(loss3,x)[1] == ForwardDiff.gradient(loss3,x) -@test Zygote.gradient(loss4,x)[1] == ForwardDiff.gradient(loss4,x) -@test Zygote.gradient(loss5,x)[1] == ForwardDiff.gradient(loss5,x) -@test Zygote.gradient(loss6,x)[1] == ForwardDiff.gradient(loss6,x) +@test Zygote.gradient(loss, x)[1] == ForwardDiff.gradient(loss, x) +@test Zygote.gradient(loss2, x)[1] == ForwardDiff.gradient(loss2, x) +@test Zygote.gradient(loss3, x)[1] == ForwardDiff.gradient(loss3, x) +@test Zygote.gradient(loss4, x)[1] == ForwardDiff.gradient(loss4, x) +@test Zygote.gradient(loss5, x)[1] == ForwardDiff.gradient(loss5, x) +@test Zygote.gradient(loss6, x)[1] == ForwardDiff.gradient(loss6, x) diff --git a/test/basic_indexing.jl b/test/basic_indexing.jl index a2bdb470..5ebd7e1e 100644 --- a/test/basic_indexing.jl +++ b/test/basic_indexing.jl @@ -2,14 +2,14 @@ using RecursiveArrayTools, Test # Example Problem recs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] -testa = cat(recs..., dims=2) +testa = cat(recs..., dims = 2) testva = VectorOfArray(recs) @test maximum(testva) == maximum(maximum.(recs)) # broadcast with array X = rand(3, 3) mulX = sqrt.(abs.(testva .* X)) -ref = mapreduce((x,y)->sqrt.(abs.(x.*y)), hcat, testva, eachcol(X)) +ref = mapreduce((x, y) -> sqrt.(abs.(x .* y)), hcat, testva, eachcol(X)) @test mulX == ref fill!(mulX, 0) mulX .= sqrt.(abs.(testva .* X)) @@ -23,8 +23,8 @@ mulX .= sqrt.(abs.(testva .* X)) @test testva[1:2, 1:2] == [1 4; 2 5] @test testa[1:2, 1:2] == [1 4; 2 5] -t = [1,2,3] -diffeq = DiffEqArray(recs,t) +t = [1, 2, 3] +diffeq = DiffEqArray(recs, t) @test Array(diffeq) == [1 4 7 2 5 8 3 6 9] @@ -33,20 +33,20 @@ diffeq = DiffEqArray(recs,t) # # ndims == 2 t = 1:10 recs = [rand(8) for i in 1:10] -testa = cat(recs...,dims=2) +testa = cat(recs..., dims = 2) testva = VectorOfArray(recs) # ## Linear indexing @test testva[1] == testa[:, 1] @test testva[:] == recs @test testva[end] == testa[:, end] -@test testva[2:end] == VectorOfArray([recs[i] for i = 2:length(recs)]) +@test testva[2:end] == VectorOfArray([recs[i] for i in 2:length(recs)]) -diffeq = DiffEqArray(recs,t) +diffeq = DiffEqArray(recs, t) @test diffeq[1] == testa[:, 1] @test diffeq[:] == recs @test diffeq[end] == testa[:, end] -@test diffeq[2:end] == DiffEqArray([recs[i] for i = 2:length(recs)], t) +@test diffeq[2:end] == DiffEqArray([recs[i] for i in 2:length(recs)], t) # ## (Int, Int) @test testa[5, 4] == testva[5, 4] @@ -70,9 +70,9 @@ diffeq = DiffEqArray(recs,t) # # ndims == 3 t = 1:15 recs = recs = [rand(10, 8) for i in 1:15] -testa = cat(recs...,dims=3) +testa = cat(recs..., dims = 3) testva = VectorOfArray(recs) -diffeq = DiffEqArray(recs,t) +diffeq = DiffEqArray(recs, t) # ## (Int, Int, Int) @test testa[1, 7, 14] == testva[1, 7, 14] @@ -111,7 +111,7 @@ diffeq = DiffEqArray(recs,t) t = 1:3 recs = [[1, 2, 3], [3, 5, 6, 7], [8, 9, 10, 11]] testva = VectorOfArray(recs) #TODO: clearly this printed form is nonsense -diffeq = DiffEqArray(recs,t) +diffeq = DiffEqArray(recs, t) @test testva[:, 1] == recs[1] @test testva[1:2, 1:2] == [1 3; 2 5] @@ -119,24 +119,24 @@ diffeq = DiffEqArray(recs,t) @test diffeq[1:2, 1:2] == [1 3; 2 5] t = 1:5 -recs = [rand(2,2) for i in 1:5] +recs = [rand(2, 2) for i in 1:5] testva = VectorOfArray(recs) -diffeq = DiffEqArray(recs,t) +diffeq = DiffEqArray(recs, t) -@test Array(testva) isa Array{Float64,3} -@test Array(diffeq) isa Array{Float64,3} +@test Array(testva) isa Array{Float64, 3} +@test Array(diffeq) isa Array{Float64, 3} -v = VectorOfArray([zeros(20), zeros(10,10), zeros(3,3,3)]) +v = VectorOfArray([zeros(20), zeros(10, 10), zeros(3, 3, 3)]) v[CartesianIndex((2, 3, 2, 3))] = 1 @test v[CartesianIndex((2, 3, 2, 3))] == 1 @test v.u[3][2, 3, 2] == 1 -v = DiffEqArray([zeros(20), zeros(10,10), zeros(3,3,3)], 1:3) +v = DiffEqArray([zeros(20), zeros(10, 10), zeros(3, 3, 3)], 1:3) v[CartesianIndex((2, 3, 2, 3))] = 1 @test v[CartesianIndex((2, 3, 2, 3))] == 1 @test v.u[3][2, 3, 2] == 1 -v = VectorOfArray([rand(20), rand(10,10), rand(3,3,3)]) +v = VectorOfArray([rand(20), rand(10, 10), rand(3, 3, 3)]) w = v .* v @test w isa VectorOfArray @test w[1] isa Vector @@ -150,8 +150,7 @@ w = v .+ 1 @test w isa VectorOfArray @test w.u == map(x -> x .+ 1, v.u) - -v = DiffEqArray([rand(20), rand(10,10), rand(3,3,3)], 1:3) +v = DiffEqArray([rand(20), rand(10, 10), rand(3, 3, 3)], 1:3) w = v .* v @test_broken w isa DiffEqArray # FIXME @test w[1] isa Vector @@ -179,4 +178,4 @@ mulX .= sqrt.(abs.(testva .* testvb)) # https://github.com/SciML/RecursiveArrayTools.jl/issues/49 a = ArrayPartition(1:5, 1:6) a[1:8] -a[[1,3,8]] +a[[1, 3, 8]] diff --git a/test/copy_static_array_test.jl b/test/copy_static_array_test.jl index 4fe49c34..76b9668b 100644 --- a/test/copy_static_array_test.jl +++ b/test/copy_static_array_test.jl @@ -1,17 +1,17 @@ using Test, RecursiveArrayTools, StaticArrays, StructArrays -struct ImmutableFV <: FieldVector{2,Float64} +struct ImmutableFV <: FieldVector{2, Float64} a::Float64 b::Float64 end -mutable struct MutableFV <: FieldVector{2,Float64} +mutable struct MutableFV <: FieldVector{2, Float64} a::Float64 b::Float64 end # Immutable FieldVector -vec = ImmutableFV(1.,2.) +vec = ImmutableFV(1.0, 2.0) a = [vec] @test recursive_unitless_eltype(a) == ImmutableFV b = zero(a) @@ -19,12 +19,12 @@ recursivecopy!(b, a) @test a[1] == b[1] copyat_or_push!(a, 2, b[1]) @test a[2] == b[1] -b[1] = 2*b[1] +b[1] = 2 * b[1] copyat_or_push!(a, 2, b[1]) @test a[2] == b[1] # Mutable FieldVector -vec = MutableFV(1.,2.) +vec = MutableFV(1.0, 2.0) a = [vec] @test recursive_unitless_eltype(a) == MutableFV b = zero(a) @@ -36,24 +36,24 @@ copyat_or_push!(a, 2, b[1]) @test a[2] == b[1] a[2][1] *= 5 @test a[2] != b[1] -b[1] = 2*b[1] +b[1] = 2 * b[1] copyat_or_push!(a, 2, b[1]) @test a[2] == b[1] # SArray -vec = @SArray [1., 2.] +vec = @SArray [1.0, 2.0] a = [vec] b = zero(a) recursivecopy!(b, a) @test a[1] == b[1] copyat_or_push!(a, 2, b[1]) @test a[2] == b[1] -b[1] = 2*b[1] +b[1] = 2 * b[1] copyat_or_push!(a, 2, b[1]) @test a[2] == b[1] # MArray -vec = @MArray [1., 2.] +vec = @MArray [1.0, 2.0] a = [vec] b = zero(a) recursivecopy!(b, a) @@ -63,12 +63,12 @@ copyat_or_push!(a, 2, b[1]) @test a[2] == b[1] a[2][1] *= 5 @test a[2] != b[1] -b[1] = 2*b[1] +b[1] = 2 * b[1] copyat_or_push!(a, 2, b[1]) @test a[2] == b[1] # StructArray of Immutable FieldVector -a = StructArray([ImmutableFV(1., 2.)]) +a = StructArray([ImmutableFV(1.0, 2.0)]) b = recursivecopy(a) @test typeof(a) == typeof(b) @test a[1] == b[1] @@ -76,7 +76,7 @@ a[1] *= 2 @test a[1] != b[1] # StructArray of Mutable FieldVector -a = StructArray([MutableFV(1., 2.)]) +a = StructArray([MutableFV(1.0, 2.0)]) b = recursivecopy(a) @test typeof(a) == typeof(b) @test a[1] == b[1] diff --git a/test/downstream/TrackerExt.jl b/test/downstream/TrackerExt.jl index 275f2336..da740b23 100644 --- a/test/downstream/TrackerExt.jl +++ b/test/downstream/TrackerExt.jl @@ -3,5 +3,5 @@ using RecursiveArrayTools, Tracker, Test x = [5.0] a = [Tracker.TrackedArray(x)] b = [Tracker.TrackedArray(copy([5.2]))] -RecursiveArrayTools.recursivecopy!(a,b) -@test a[1][1] == 5.2 \ No newline at end of file +RecursiveArrayTools.recursivecopy!(a, b) +@test a[1][1] == 5.2 diff --git a/test/downstream/downstream_events.jl b/test/downstream/downstream_events.jl index 39353b5e..f67cdfec 100644 --- a/test/downstream/downstream_events.jl +++ b/test/downstream/downstream_events.jl @@ -1,22 +1,21 @@ -using OrdinaryDiffEq, StaticArrays, RecursiveArrayTools -u0 = ArrayPartition(SVector{1}(50.0), SVector{1}(0.0)) -tspan = (0.0,15.0) - -function f(u,p,t) - ArrayPartition(SVector{1}(u[2]), SVector{1}(-9.81)) -end - -prob = ODEProblem(f,u0,tspan) - -function condition(u,t,integrator) # Event when event_f(u,t,k) == 0 - u[1] -end - -affect! = nothingf = -affect_neg! = function (integrator) - integrator.u = ArrayPartition(SVector{1}(integrator.u[1]), SVector{1}(-integrator.u[2])) -end - -callback = ContinuousCallback(condition,affect!,affect_neg!,interp_points=100) - -sol = solve(prob,Tsit5(),callback=callback,adaptive=false,dt=1/4) +using OrdinaryDiffEq, StaticArrays, RecursiveArrayTools +u0 = ArrayPartition(SVector{1}(50.0), SVector{1}(0.0)) +tspan = (0.0, 15.0) + +function f(u, p, t) + ArrayPartition(SVector{1}(u[2]), SVector{1}(-9.81)) +end + +prob = ODEProblem(f, u0, tspan) + +function condition(u, t, integrator) # Event when event_f(u,t,k) == 0 + u[1] +end + +affect! = nothingf = affect_neg! = function (integrator) + integrator.u = ArrayPartition(SVector{1}(integrator.u[1]), SVector{1}(-integrator.u[2])) +end + +callback = ContinuousCallback(condition, affect!, affect_neg!, interp_points = 100) + +sol = solve(prob, Tsit5(), callback = callback, adaptive = false, dt = 1 / 4) diff --git a/test/downstream/symbol_indexing.jl b/test/downstream/symbol_indexing.jl index b8fce572..8110cf7c 100644 --- a/test/downstream/symbol_indexing.jl +++ b/test/downstream/symbol_indexing.jl @@ -6,23 +6,21 @@ include("../testutils.jl") @parameters τ D = Differential(t) @variables RHS(t) -@named fol_separate = ODESystem([ RHS ~ (1 - x)/τ, - D(x) ~ RHS ]) +@named fol_separate = ODESystem([RHS ~ (1 - x) / τ, + D(x) ~ RHS]) fol_simplified = structural_simplify(fol_separate) -prob = ODEProblem(fol_simplified, [x => 0.0], (0.0,10.0), [τ => 3.0]) +prob = ODEProblem(fol_simplified, [x => 0.0], (0.0, 10.0), [τ => 3.0]) sol = solve(prob, Tsit5()) -sol_new = DiffEqArray( - sol.u[1:10], - sol.t[1:10], - sol.prob.f.syms, - sol.prob.f.indepsym, - sol.prob.f.observed, - sol.prob.p -) +sol_new = DiffEqArray(sol.u[1:10], + sol.t[1:10], + sol.prob.f.syms, + sol.prob.f.indepsym, + sol.prob.f.observed, + sol.prob.p) -@test sol_new[RHS] ≈ (1 .- sol_new[x])./3.0 +@test sol_new[RHS] ≈ (1 .- sol_new[x]) ./ 3.0 @test sol_new[t] ≈ sol_new.t @test sol_new[t, 1:5] ≈ sol_new.t[1:5] @@ -32,7 +30,7 @@ test_tables_interface(sol_new, [:timestamp, Symbol("x(t)")], hcat(sol_new[t], so # Two components @variables y(t) @parameters α β γ δ -@named lv = ODESystem([ D(x) ~ α * x - β * x * y, +@named lv = ODESystem([D(x) ~ α * x - β * x * y, D(y) ~ δ * x * y - γ * x * y]) prob = ODEProblem(lv, [x => 1.0, y => 1.0], (0.0, 10.0), @@ -42,4 +40,5 @@ sol = solve(prob, Tsit5()) ts = 0:0.5:10 sol_ts = sol(ts) @assert sol_ts isa DiffEqArray -test_tables_interface(sol_ts, [:timestamp, Symbol("x(t)"), Symbol("y(t)")], hcat(ts, Array(sol_ts)')) +test_tables_interface(sol_ts, [:timestamp, Symbol("x(t)"), Symbol("y(t)")], + hcat(ts, Array(sol_ts)')) diff --git a/test/gpu.jl b/test/gpu.jl index 72fcb579..2ed5211c 100644 --- a/test/gpu.jl +++ b/test/gpu.jl @@ -1,4 +1,4 @@ -using RecursiveArrayTools, CuArrays -a = ArrayPartition(([1.0f0] |> cu,[2.0f0] |> cu,[3.0f0] |> cu)) -b = ArrayPartition(([0.0f0] |> cu,[0.0f0] |> cu,[0.0f0] |> cu)) -@. a + b +using RecursiveArrayTools, CuArrays +a = ArrayPartition(([1.0f0] |> cu, [2.0f0] |> cu, [3.0f0] |> cu)) +b = ArrayPartition(([0.0f0] |> cu, [0.0f0] |> cu, [0.0f0] |> cu)) +@. a + b diff --git a/test/gpu/ode_gpu.jl b/test/gpu/ode_gpu.jl index 9cb10384..e8f3f00c 100644 --- a/test/gpu/ode_gpu.jl +++ b/test/gpu/ode_gpu.jl @@ -2,13 +2,13 @@ using CUDA, LinearAlgebra, OrdinaryDiffEq u0 = cu(rand(100)) -A = cu(randn(100,100)) +A = cu(randn(100, 100)) -f(du,u,p,t) = mul!(du,A,u) +f(du, u, p, t) = mul!(du, A, u) -prob = ODEProblem(f,u0,(0.0f0,1.0f0)) +prob = ODEProblem(f, u0, (0.0f0, 1.0f0)) -sol = solve(prob,Tsit5()) +sol = solve(prob, Tsit5()) Array(sol) @@ -18,12 +18,12 @@ u0 = cu(rand(100)) du0 = cu(rand(100)) -A = cu(randn(100,100)) +A = cu(randn(100, 100)) -f(ddu,du,u,p,t) = mul!(ddu,A,u) +f(ddu, du, u, p, t) = mul!(ddu, A, u) -prob = SecondOrderODEProblem(f,du0,u0,(0.0f0,1.0f0)) +prob = SecondOrderODEProblem(f, du0, u0, (0.0f0, 1.0f0)) -sol = solve(prob,Tsit5()) +sol = solve(prob, Tsit5()) -CuArray(sol) \ No newline at end of file +CuArray(sol) diff --git a/test/gpu/vectorofarray_gpu.jl b/test/gpu/vectorofarray_gpu.jl index 54066a36..9fb22539 100644 --- a/test/gpu/vectorofarray_gpu.jl +++ b/test/gpu/vectorofarray_gpu.jl @@ -1,33 +1,33 @@ -using RecursiveArrayTools, CUDA, Test, Zygote -CUDA.allowscalar(false) - -# Test indexing with colon -x = zeros(5) -y = VectorOfArray([x, x, x]) -y[:, :] - -x = CUDA.zeros(5) -y = VectorOfArray([x, x, x]) -y[:, :] - -# Test indexing with boolean masks and colon -nx, ny, nt = 3, 4, 5 -x = CUDA.rand(nx, ny, nt) -m = CUDA.rand(nx, ny) .> 0.5 -x[m, :] - -va = VectorOfArray([slice for slice in eachslice(x, dims=3)]) -@test va[m, :] ≈ x[m, :] - -xc = Array(x) -mc = Array(m) -@test xc[mc, :] ≈ Array(va[m, :]) - -# Check differentiation with GPUs - -p = cu([1.0, 2.0]) -function f(p) - x = VectorOfArray([p, p]) - sum(CuArray(x)) -end -Zygote.gradient(f, p) \ No newline at end of file +using RecursiveArrayTools, CUDA, Test, Zygote +CUDA.allowscalar(false) + +# Test indexing with colon +x = zeros(5) +y = VectorOfArray([x, x, x]) +y[:, :] + +x = CUDA.zeros(5) +y = VectorOfArray([x, x, x]) +y[:, :] + +# Test indexing with boolean masks and colon +nx, ny, nt = 3, 4, 5 +x = CUDA.rand(nx, ny, nt) +m = CUDA.rand(nx, ny) .> 0.5 +x[m, :] + +va = VectorOfArray([slice for slice in eachslice(x, dims = 3)]) +@test va[m, :] ≈ x[m, :] + +xc = Array(x) +mc = Array(m) +@test xc[mc, :] ≈ Array(va[m, :]) + +# Check differentiation with GPUs + +p = cu([1.0, 2.0]) +function f(p) + x = VectorOfArray([p, p]) + sum(CuArray(x)) +end +Zygote.gradient(f, p) diff --git a/test/interface_tests.jl b/test/interface_tests.jl index ab6137b6..3ac5283d 100644 --- a/test/interface_tests.jl +++ b/test/interface_tests.jl @@ -2,7 +2,7 @@ using RecursiveArrayTools, Test t = 1:3 testva = VectorOfArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) -testda = DiffEqArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]],t) +testda = DiffEqArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]], t) for (i, elem) in enumerate(testva) @test elem == testva[i] @@ -58,24 +58,24 @@ push!(testda, [-1, -2, -3, -4]) # convert array from VectorOfArray/DiffEqArray t = 1:8 -recs = [rand(10, 7) for i = 1:8] +recs = [rand(10, 7) for i in 1:8] testva = VectorOfArray(recs) -testda = DiffEqArray(recs,t) -testa = cat(recs...,dims=3) +testda = DiffEqArray(recs, t) +testa = cat(recs..., dims = 3) -@test convert(Array,testva) == testa -@test convert(Array,testda) == testa +@test convert(Array, testva) == testa +@test convert(Array, testda) == testa t = 1:3 recs = [[1 2; 3 4], [3 5; 6 7], [8 9; 10 11]] testva = VectorOfArray(recs) -testda = DiffEqArray(recs,t) +testda = DiffEqArray(recs, t) -@test size(convert(Array,testva)) == (2,2,3) -@test size(convert(Array,testda)) == (2,2,3) +@test size(convert(Array, testva)) == (2, 2, 3) +@test size(convert(Array, testda)) == (2, 2, 3) # create similar VectorOfArray -recs = [rand(6) for i = 1:4] +recs = [rand(6) for i in 1:4] testva = VectorOfArray(recs) testva2 = similar(testva) @@ -85,11 +85,11 @@ testva2 = similar(testva) # Fill AbstractVectorOfArray and check all testval = 3.0 fill!(testva2, testval) -@test all(x->(x==testval), testva2) +@test all(x -> (x == testval), testva2) testts = rand(Float64, size(testva.u)) testda = DiffEqArray(recursivecopy(testva.u), testts) fill!(testda, testval) -@test all(x->(x==testval), testda) +@test all(x -> (x == testval), testda) # check any recs = [collect(1:5), collect(6:10), collect(11:15)] @@ -98,8 +98,8 @@ testva = VectorOfArray(recs) testda = DiffEqArray(recs, testts) testval1 = 4 testval2 = 17 -@test any(x->(x==testval1), testva) -@test !any(x->(x==testval2), testda) +@test any(x -> (x == testval1), testva) +@test !any(x -> (x == testval2), testda) # check creation from empty arrays emptyva = VectorOfArray(Array{Vector{Float64}}([])) @@ -107,8 +107,8 @@ emptyva = VectorOfArray(Array{Vector{Float64}}([])) emptyda = DiffEqArray(Array{Vector{Float64}}([]), Vector{Float64}()) @test isempty(emptyda) -A = VectorOfArray(map(i->rand(2,4),1:7)) -@test map(x->maximum(x),A) isa Vector +A = VectorOfArray(map(i -> rand(2, 4), 1:7)) +@test map(x -> maximum(x), A) isa Vector -DA = DiffEqArray(map(i->rand(2,4),1:7), 1:7) -@test map(x->maximum(x),DA) isa Vector +DA = DiffEqArray(map(i -> rand(2, 4), 1:7), 1:7) +@test map(x -> maximum(x), DA) isa Vector diff --git a/test/linalg.jl b/test/linalg.jl index 492dc336..0dcaa270 100644 --- a/test/linalg.jl +++ b/test/linalg.jl @@ -6,26 +6,26 @@ bb = rand(n), rand(m) b = ArrayPartition(bb) @test Array(b) isa Array @test Array(b) == collect(b) == vcat(bb...) -A = randn(MersenneTwister(123), n+m, n+m) +A = randn(MersenneTwister(123), n + m, n + m) for T in (UpperTriangular, UnitUpperTriangular, LowerTriangular, UnitLowerTriangular) local B = T(A) - @test B*Array(B \ b) ≈ b + @test B * Array(B \ b) ≈ b bbb = copy(b) @test ldiv!(bbb, B, b) === bbb copyto!(bbb, b) @test ldiv!(B, bbb) === bbb - @test B*Array(bbb) ≈ b + @test B * Array(bbb) ≈ b end for ff in (lu, svd, qr) FF = ff(A) - @test A*(FF \ b) ≈ b + @test A * (FF \ b) ≈ b bbb = copy(b) @test ldiv!(bbb, FF, b) === bbb copyto!(bbb, b) @test ldiv!(FF, bbb) === bbb - @test A*bbb ≈ b + @test A * bbb ≈ b end # linalg mul! overloads @@ -37,14 +37,14 @@ b = ArrayPartition(bb) c = ArrayPartition(cc) d = ArrayPartition(dd) A = rand(n) -for T in (Array{Float64}, Array{ComplexF64},) +for T in (Array{Float64}, Array{ComplexF64}) local B = T(A) mul!(d, b, A) - for i = 1:length(c.x) + for i in 1:length(c.x) @test d.x[i] == b.x[i] * A end mul!(d, b, c) - for i = 1:length(d.x) + for i in 1:length(d.x) @test d.x[i] == b.x[i] * c.x[i] end end diff --git a/test/partitions_and_static_arrays.jl b/test/partitions_and_static_arrays.jl index 49852e5d..e26788b4 100644 --- a/test/partitions_and_static_arrays.jl +++ b/test/partitions_and_static_arrays.jl @@ -1,13 +1,14 @@ using Test, RecursiveArrayTools, StaticArrays -p = ArrayPartition((zeros(Float32, 2), zeros(SMatrix{2,2, Int64},2), zeros(SVector{3, Float64}, 2))) -@test eltype(p)==Float64 -@test recursive_bottom_eltype(p)==Float64 -@test recursive_unitless_eltype(p)==Float64 -@test recursive_unitless_bottom_eltype(p)==Float64 +p = ArrayPartition((zeros(Float32, 2), zeros(SMatrix{2, 2, Int64}, 2), + zeros(SVector{3, Float64}, 2))) +@test eltype(p) == Float64 +@test recursive_bottom_eltype(p) == Float64 +@test recursive_unitless_eltype(p) == Float64 +@test recursive_unitless_bottom_eltype(p) == Float64 p2 = similar(p) -@test typeof(p2)==typeof(p) +@test typeof(p2) == typeof(p) -p3 = ArrayPartition(SA[1.0, 2.0], MMatrix{2,2}([3.0 4.0; 3.0 5.0])) +p3 = ArrayPartition(SA[1.0, 2.0], MMatrix{2, 2}([3.0 4.0; 3.0 5.0])) @test (@inferred length(typeof(p3))) == 6 diff --git a/test/partitions_test.jl b/test/partitions_test.jl index 7c16f6a2..98dec3a6 100644 --- a/test/partitions_test.jl +++ b/test/partitions_test.jl @@ -1,9 +1,9 @@ using RecursiveArrayTools, Test, Statistics, ArrayInterfaceCore -A = (rand(5),rand(5)) +A = (rand(5), rand(5)) p = ArrayPartition(A) -@test (p.x[1][1],p.x[2][1]) == (p[1],p[6]) +@test (p.x[1][1], p.x[2][1]) == (p[1], p[6]) -p = ArrayPartition(A,Val{true}) +p = ArrayPartition(A, Val{true}) @test !(p.x[1] === A[1]) p2 = similar(p) @@ -11,54 +11,54 @@ p2[1] = 1 @test p2.x[1] != p.x[1] C = rand(10) -p3 = similar(p,axes(p)) +p3 = similar(p, axes(p)) @test length(p3.x[1]) == length(p3.x[2]) == 5 @test length(p.x) == length(p2.x) == length(p3.x) == 2 -A = (rand(5),rand(5)) +A = (rand(5), rand(5)) p = ArrayPartition(A) -B = (rand(5),rand(5)) +B = (rand(5), rand(5)) p2 = ArrayPartition(B) a = 5 -@. p = p*5 -@. p = p*a -@. p = p*p2 -K = p.*p2 +@. p = p * 5 +@. p = p * a +@. p = p * p2 +K = p .* p2 x = rand(10) -y = p.*x +y = p .* x @test y[1:5] == p.x[1] .* x[1:5] @test y[6:10] == p.x[2] .* x[6:10] -y = p.*x' +y = p .* x' for i in 1:10 - @test y[1:5,i] == p.x[1] .* x[i] - @test y[6:10,i] == p.x[2] .* x[i] + @test y[1:5, i] == p.x[1] .* x[i] + @test y[6:10, i] == p.x[2] .* x[i] end y = p .* p' -@test y[1:5,1:5] == p.x[1] .* p.x[1]' -@test y[6:10,6:10] == p.x[2] .* p.x[2]' -@test y[1:5,6:10] == p.x[1] .* p.x[2]' -@test y[6:10,1:5] == p.x[2] .* p.x[1]' +@test y[1:5, 1:5] == p.x[1] .* p.x[1]' +@test y[6:10, 6:10] == p.x[2] .* p.x[2]' +@test y[1:5, 6:10] == p.x[1] .* p.x[2]' +@test y[6:10, 1:5] == p.x[2] .* p.x[1]' a = ArrayPartition([1], [2]) a .= [10, 20] b = rand(10) c = rand(10) -copyto!(b,p) +copyto!(b, p) @test b[1:5] == p.x[1] @test b[6:10] == p.x[2] -copyto!(p,c) +copyto!(p, c) @test c[1:5] == p.x[1] @test c[6:10] == p.x[2] ## inference tests x = ArrayPartition([1, 2], [3.0, 4.0]) -@test x[:,1] == (1,3.0) +@test x[:, 1] == (1, 3.0) # similar partitions @inferred similar(x) @@ -71,24 +71,24 @@ x = ArrayPartition([1, 2], [3.0, 4.0]) # zero @inferred zero(x) -@inferred zero(x, (2,2)) +@inferred zero(x, (2, 2)) @inferred zero(x) # ones @inferred ones(x) -@inferred ones(x, (2,2)) +@inferred ones(x, (2, 2)) # vector space calculations -@inferred x+5 -@inferred 5+x -@inferred x-5 -@inferred 5-x -@inferred x*5 -@inferred 5*x -@inferred x/5 -@inferred 5\x -@inferred x+x -@inferred x-x +@inferred x + 5 +@inferred 5 + x +@inferred x - 5 +@inferred 5 - x +@inferred x * 5 +@inferred 5 * x +@inferred x / 5 +@inferred 5 \ x +@inferred x + x +@inferred x - x # indexing @inferred first(x) @@ -107,60 +107,61 @@ _broadcast_wrapper(y) = _scalar_op.(y) @inferred _broadcast_wrapper(x) # Testing map -@test map(x->x^2, x) == ArrayPartition(x.x[1].^2, x.x[2].^2) +@test map(x -> x^2, x) == ArrayPartition(x.x[1] .^ 2, x.x[2] .^ 2) # Testing filter -@test filter(x->iseven(round(Int, x)), x) == ArrayPartition([2], [4.0]) +@test filter(x -> iseven(round(Int, x)), x) == ArrayPartition([2], [4.0]) #### testing copyto! S = [ - ((1,),(2,)) => ((1,),(2,)), - ((3,2),(2,)) => ((3,2),(2,)), - ((3,2),(2,)) => ((3,),(3,),(2,)) - ] + ((1,), (2,)) => ((1,), (2,)), + ((3, 2), (2,)) => ((3, 2), (2,)), + ((3, 2), (2,)) => ((3,), (3,), (2,)), +] for sizes in S - local x = ArrayPartition( randn.(sizes[1]) ) - local y = ArrayPartition( zeros.(sizes[2]) ) - y_array = zeros(length(x)) - copyto!(y,x) #testing Base.copyto!(dest::ArrayPartition,A::ArrayPartition) - copyto!(y_array,x) #testing Base.copyto!(dest::Array,A::ArrayPartition) - @test all([x[i] == y[i] for i in eachindex(x)]) - @test all([x[i] == y_array[i] for i in eachindex(x)]) + local x = ArrayPartition(randn.(sizes[1])) + local y = ArrayPartition(zeros.(sizes[2])) + y_array = zeros(length(x)) + copyto!(y, x) #testing Base.copyto!(dest::ArrayPartition,A::ArrayPartition) + copyto!(y_array, x) #testing Base.copyto!(dest::Array,A::ArrayPartition) + @test all([x[i] == y[i] for i in eachindex(x)]) + @test all([x[i] == y_array[i] for i in eachindex(x)]) end # Non-allocating broadcast -xce0 = ArrayPartition(zeros(2),[0.]) +xce0 = ArrayPartition(zeros(2), [0.0]) xcde0 = copy(xce0) function foo(y, x) - y .= y .+ x - nothing + y .= y .+ x + nothing end foo(xcde0, xce0) #@test 0 == @allocated foo(xcde0, xce0) function foo(y, x) - y .= y .+ 2 .* x - nothing + y .= y .+ 2 .* x + nothing end foo(xcde0, xce0) #@test 0 == @allocated foo(xcde0, xce0) # Custom AbstractArray types broadcasting struct MyType{T} <: AbstractVector{T} - data :: Vector{T} + data::Vector{T} end Base.similar(A::MyType{T}) where {T} = MyType{T}(similar(A.data)) -Base.similar(A::MyType{T},::Type{S}) where {T,S} = MyType(similar(A.data,S)) +Base.similar(A::MyType{T}, ::Type{S}) where {T, S} = MyType(similar(A.data, S)) Base.size(A::MyType) = size(A.data) -Base.getindex(A::MyType, i::Int) = getindex(A.data,i) -Base.setindex!(A::MyType, v, i::Int) = setindex!(A.data,v,i) +Base.getindex(A::MyType, i::Int) = getindex(A.data, i) +Base.setindex!(A::MyType, v, i::Int) = setindex!(A.data, v, i) Base.IndexStyle(::MyType) = IndexLinear() Base.BroadcastStyle(::Type{<:MyType}) = Broadcast.ArrayStyle{MyType}() -function Base.similar(bc::Broadcast.Broadcasted{Broadcast.ArrayStyle{MyType}},::Type{T}) where {T} - similar(find_mt(bc),T) +function Base.similar(bc::Broadcast.Broadcasted{Broadcast.ArrayStyle{MyType}}, + ::Type{T}) where {T} + similar(find_mt(bc), T) end function Base.similar(bc::Broadcast.Broadcasted{Broadcast.ArrayStyle{MyType}}) @@ -174,7 +175,7 @@ find_mt(::Tuple{}) = nothing find_mt(a::MyType, rest) = a find_mt(::Any, rest) = find_mt(rest) -ap = ArrayPartition(MyType(ones(10)),collect(1:2)) +ap = ArrayPartition(MyType(ones(10)), collect(1:2)) up = ap .+ 1 @test typeof(ap) == typeof(up) @@ -182,21 +183,35 @@ up = 2 .* ap .+ 1 @test typeof(ap) == typeof(up) # Test that `zeros()` does not get screwed up -ap = ArrayPartition(zeros(),[1.0]) +ap = ArrayPartition(zeros(), [1.0]) up = ap .+ 1 @test typeof(ap) == typeof(up) up = 2 .* ap .+ 1 @test typeof(ap) == typeof(up) -@testset "ArrayInterfaceCore.ismutable(ArrayPartition($a, $b)) == $r" for (a, b, r) in ((1,2, false), ([1], 2, false), ([1], [2], true)) +@testset "ArrayInterfaceCore.ismutable(ArrayPartition($a, $b)) == $r" for (a, b, r) in ((1, + 2, + false), + ([ + 1, + ], + 2, + false), + ([ + 1, + ], + [ + 2, + ], + true)) @test ArrayInterfaceCore.ismutable(ArrayPartition(a, b)) == r end # Test unary minus x = ArrayPartition(ArrayPartition([1, 2]), [3, 4]) -@test -x == 0-x +@test -x == 0 - x @test typeof(x) === typeof(-x) # Test conversions @@ -205,7 +220,7 @@ begin c = [1 2; 3 4] d = ArrayPartition(view(b, :), c) - new_type = ArrayPartition{Float64,Tuple{Vector{Float64},Matrix{Float64}}} + new_type = ArrayPartition{Float64, Tuple{Vector{Float64}, Matrix{Float64}}} @test (@inferred convert(new_type, d)) isa new_type @test convert(new_type, d) == d @test_throws MethodError convert(new_type, ArrayPartition(view(b, :), c, c)) diff --git a/test/testutils.jl b/test/testutils.jl index 0830849b..471b65e1 100644 --- a/test/testutils.jl +++ b/test/testutils.jl @@ -3,7 +3,8 @@ using RecursiveArrayTools: Tables, IteratorInterfaceExtensions # Test Tables interface with row access + IteratorInterfaceExtensions for QueryVerse # (see https://tables.juliadata.org/stable/#Testing-Tables.jl-Implementations) -function test_tables_interface(x::AbstractDiffEqArray, names::Vector{Symbol}, values::Matrix) +function test_tables_interface(x::AbstractDiffEqArray, names::Vector{Symbol}, + values::Matrix) @assert length(names) == size(values, 2) # AbstractDiffEqArray is a table with row access @@ -28,7 +29,8 @@ function test_tables_interface(x::AbstractDiffEqArray, names::Vector{Symbol}, va @test eltype(tbl) === typeof(row) @test propertynames(row) == Tables.columnnames(row) == names for (j, name) in enumerate(names) - @test getproperty(row, name) == Tables.getcolumn(row, name) == Tables.getcolumn(row, j) == values[i, j] + @test getproperty(row, name) == Tables.getcolumn(row, name) == + Tables.getcolumn(row, j) == values[i, j] end end @@ -42,7 +44,8 @@ function test_tables_interface(x::AbstractDiffEqArray, names::Vector{Symbol}, va @test Tables.columns(coltbl) === coltbl @test propertynames(coltbl) == Tables.columnnames(coltbl) == Tuple(names) for (i, name) in enumerate(names) - @test getproperty(coltbl, name) == Tables.getcolumn(coltbl, name) == Tables.getcolumn(coltbl, i) == values[:, i] + @test getproperty(coltbl, name) == Tables.getcolumn(coltbl, name) == + Tables.getcolumn(coltbl, i) == values[:, i] end # IteratorInterfaceExtensions diff --git a/test/upstream.jl b/test/upstream.jl index 21f73a40..158c05bc 100644 --- a/test/upstream.jl +++ b/test/upstream.jl @@ -1,72 +1,54 @@ -using OrdinaryDiffEq, NLsolve, RecursiveArrayTools, Test, ArrayInterfaceCore -function lorenz(du,u,p,t) - du[1] = 10.0*(u[2]-u[1]) - du[2] = u[1]*(28.0-u[3]) - u[2] - du[3] = u[1]*u[2] - (8/3)*u[3] -end -u0 = ArrayPartition([1.0,0.0],[0.0]) -@test ArrayInterfaceCore.zeromatrix(u0) isa Matrix -tspan = (0.0,100.0) -prob = ODEProblem(lorenz,u0,tspan) -sol = solve(prob,Tsit5()) -sol = solve(prob,AutoTsit5(Rosenbrock23(autodiff=false))) -sol = solve(prob,AutoTsit5(Rosenbrock23())) - -@test all(Array(sol) .== sol) - -function mymodel(F, vars) - for i in 1:2 - x = vars.x[i] - F.x[i][1,1] = (x[1,1]+3)*(x[1,2]^3-7)+18.0 - F.x[i][1,2] = sin(x[1,2]*exp(x[1,1])-1) - F.x[i][2,1] = (x[2,1]+3)*(x[2,2]^3-7)+19.0 - F.x[i][2,2] = sin(x[2,2]*exp(x[2,1])-3) - end -end -# To show that the function works -F = ArrayPartition([0.0 0.0; 0.0 0.0],[0.0 0.0; 0.0 0.0]) -u0= ArrayPartition([0.1 1.2; 0.1 1.2], [0.1 1.2; 0.1 1.2]) -result = mymodel(F, u0) -nlsolve(mymodel, u0) - -# Nested ArrayPartition solves - -dyn(u, p, t) = ArrayPartition( - ArrayPartition(zeros(1), [0.0]), - ArrayPartition(zeros(1), [0.0]) -) - -@test solve( - ODEProblem( - dyn, - ArrayPartition( - ArrayPartition(zeros(1), [-1.0]), - ArrayPartition(zeros(1), [0.75]) - ), - (0.0, 1.0) - ),AutoTsit5(Rodas5()) -).retcode == :Success - -if VERSION < v"1.7" - @test solve( - ODEProblem( - dyn, - ArrayPartition( - ArrayPartition(zeros(1), [-1.0]), - ArrayPartition(zeros(1), [0.75]) - ), - (0.0, 1.0) - ),Rodas5() - ).retcode == :Success -else - @test_broken solve( - ODEProblem( - dyn, - ArrayPartition( - ArrayPartition(zeros(1), [-1.0]), - ArrayPartition(zeros(1), [0.75]) - ), - (0.0, 1.0) - ),Rodas5() - ).retcode == :Success -end \ No newline at end of file +using OrdinaryDiffEq, NLsolve, RecursiveArrayTools, Test, ArrayInterfaceCore +function lorenz(du, u, p, t) + du[1] = 10.0 * (u[2] - u[1]) + du[2] = u[1] * (28.0 - u[3]) - u[2] + du[3] = u[1] * u[2] - (8 / 3) * u[3] +end +u0 = ArrayPartition([1.0, 0.0], [0.0]) +@test ArrayInterfaceCore.zeromatrix(u0) isa Matrix +tspan = (0.0, 100.0) +prob = ODEProblem(lorenz, u0, tspan) +sol = solve(prob, Tsit5()) +sol = solve(prob, AutoTsit5(Rosenbrock23(autodiff = false))) +sol = solve(prob, AutoTsit5(Rosenbrock23())) + +@test all(Array(sol) .== sol) + +function mymodel(F, vars) + for i in 1:2 + x = vars.x[i] + F.x[i][1, 1] = (x[1, 1] + 3) * (x[1, 2]^3 - 7) + 18.0 + F.x[i][1, 2] = sin(x[1, 2] * exp(x[1, 1]) - 1) + F.x[i][2, 1] = (x[2, 1] + 3) * (x[2, 2]^3 - 7) + 19.0 + F.x[i][2, 2] = sin(x[2, 2] * exp(x[2, 1]) - 3) + end +end +# To show that the function works +F = ArrayPartition([0.0 0.0; 0.0 0.0], [0.0 0.0; 0.0 0.0]) +u0 = ArrayPartition([0.1 1.2; 0.1 1.2], [0.1 1.2; 0.1 1.2]) +result = mymodel(F, u0) +nlsolve(mymodel, u0) + +# Nested ArrayPartition solves + +function dyn(u, p, t) + ArrayPartition(ArrayPartition(zeros(1), [0.0]), + ArrayPartition(zeros(1), [0.0])) +end + +@test solve(ODEProblem(dyn, + ArrayPartition(ArrayPartition(zeros(1), [-1.0]), + ArrayPartition(zeros(1), [0.75])), + (0.0, 1.0)), AutoTsit5(Rodas5())).retcode == :Success + +if VERSION < v"1.7" + @test solve(ODEProblem(dyn, + ArrayPartition(ArrayPartition(zeros(1), [-1.0]), + ArrayPartition(zeros(1), [0.75])), + (0.0, 1.0)), Rodas5()).retcode == :Success +else + @test_broken solve(ODEProblem(dyn, + ArrayPartition(ArrayPartition(zeros(1), [-1.0]), + ArrayPartition(zeros(1), [0.75])), + (0.0, 1.0)), Rodas5()).retcode == :Success +end diff --git a/test/utils_test.jl b/test/utils_test.jl index 288035d3..0b5b1f7b 100644 --- a/test/utils_test.jl +++ b/test/utils_test.jl @@ -1,7 +1,7 @@ using RecursiveArrayTools, StaticArrays using Test -t = collect(range(0, stop=10, length=200)) +t = collect(range(0, stop = 10, length = 200)) randomized = VectorOfArray([0.01randn(2) for i in 1:10]) data = convert(Array, randomized) @test typeof(data) <: Matrix{Float64} @@ -9,7 +9,7 @@ data = convert(Array, randomized) ## Test means A = [[1 2; 3 4], [1 3; 4 6], [5 6; 7 8]] @test recursive_mean(A) ≈ [2.33333333 3.666666666 - 4.6666666666 6.0] + 4.6666666666 6.0] A = zeros(5, 5) @test recursive_unitless_eltype(A) == Float64 @@ -18,52 +18,52 @@ using Unitful A = zeros(5, 5) * 1u"kg" @test recursive_unitless_eltype(A) == Float64 AA = [zeros(5, 5) for i in 1:5] -@test recursive_unitless_eltype(AA) == Array{Float64,2} +@test recursive_unitless_eltype(AA) == Array{Float64, 2} AofA = [copy(A) for i in 1:5] -@test recursive_unitless_eltype(AofA) == Array{Float64,2} +@test recursive_unitless_eltype(AofA) == Array{Float64, 2} AofSA = [@SVector [2.0, 3.0] for i in 1:5] -@test recursive_unitless_eltype(AofSA) == SVector{2,Float64} +@test recursive_unitless_eltype(AofSA) == SVector{2, Float64} AofuSA = [@SVector [2.0u"kg", 3.0u"kg"] for i in 1:5] -@test recursive_unitless_eltype(AofuSA) == SVector{2,Float64} +@test recursive_unitless_eltype(AofuSA) == SVector{2, Float64} -A = [ArrayPartition(ones(1), ones(1)),] +A = [ArrayPartition(ones(1), ones(1))] function test_recursive_bottom_eltype() - function test_value(val::Any, expected_type::Type) - # It should return the expected type for the given expected type - @test recursive_bottom_eltype(expected_type) == expected_type + function test_value(val::Any, expected_type::Type) + # It should return the expected type for the given expected type + @test recursive_bottom_eltype(expected_type) == expected_type - # It should return the expected type for the given value - @test recursive_bottom_eltype(val) == expected_type + # It should return the expected type for the given value + @test recursive_bottom_eltype(val) == expected_type - # It should return the expected type for an array of the given value - Aval = [val for i in 1:5] - @test recursive_bottom_eltype(Aval) == expected_type + # It should return the expected type for an array of the given value + Aval = [val for i in 1:5] + @test recursive_bottom_eltype(Aval) == expected_type - # It should return expected type for a nested array of the gicen value - AAval = [Aval for i in 1:5] - @test recursive_bottom_eltype(AAval) == expected_type + # It should return expected type for a nested array of the gicen value + AAval = [Aval for i in 1:5] + @test recursive_bottom_eltype(AAval) == expected_type - # It should return expected type for an array of vectors of chars - AVval = [@SVector [val, val] for i in 1:5] - @test recursive_bottom_eltype(AVval) == expected_type - end + # It should return expected type for an array of vectors of chars + AVval = [@SVector [val, val] for i in 1:5] + @test recursive_bottom_eltype(AVval) == expected_type + end - # testing chars - test_value('c', Char) + # testing chars + test_value('c', Char) - # testing strings - # We expect recursive_bottom_eltype to return `Char` for a string, because - # `eltype("Some String") == Char` - test_value("Some String", Char) + # testing strings + # We expect recursive_bottom_eltype to return `Char` for a string, because + # `eltype("Some String") == Char` + test_value("Some String", Char) - # testing integer values - test_value(1, Int) - test_value(1u"kg", eltype(1u"kg")) + # testing integer values + test_value(1, Int) + test_value(1u"kg", eltype(1u"kg")) - # testing float values - test_value(1.0, Float64) - test_value(1.0u"kg", eltype(1.0u"kg")) + # testing float values + test_value(1.0, Float64) + test_value(1.0u"kg", eltype(1.0u"kg")) end test_recursive_bottom_eltype() @@ -98,4 +98,4 @@ recursivefill!(x, true) x = similar(x) recursivefill!(x, true) @test x[1] == MVector{10}(ones(10)) -@test x[2] == MVector{10}(ones(10)) \ No newline at end of file +@test x[2] == MVector{10}(ones(10))