forked from SciML/RecursiveArrayTools.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRecursiveArrayTools.jl
More file actions
147 lines (105 loc) · 5.03 KB
/
RecursiveArrayTools.jl
File metadata and controls
147 lines (105 loc) · 5.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
__precompile__()
"""
$(DocStringExtensions.README)
"""
module RecursiveArrayTools
using DocStringExtensions
using RecipesBase, StaticArraysCore,
ArrayInterface, LinearAlgebra
using SymbolicIndexingInterface
import Adapt
"""
AbstractVectorOfArray{T, N, A}
An AbstractVectorOfArray is an object which represents arrays of arrays,
and arbitrary recursive nesting of arrays, as a single array-like object.
Thus a canonical example of an AbstractVectorOfArray is something of the
form `VectorOfArray([[1,2],[3,4]])`, which "acts" like the matrix `[1 3; 2 4]`
where the data is stored and accessed in a column-ordered fashion (as is typical
in Julia), but the actual matrix is never constructed and instead lazily represented
through the type.
An AbstractVectorOfArray subtype should match the following behaviors.
!!! note
In 2023 the linear indexing `A[i]` was deprecated. It previously had the behavior that `A[i] = A.u[i]`. However, this is incompatible with standard `AbstractArray` interfaces, Since if `A = VectorOfArray([[1,2],[3,4]])` and `A` is supposed to act like `[1 3; 2 4]`, then there is a difference `A[1] = [1,2]` for the VectorOfArray while `A[1] = 1` for the matrix. This causes many issues if `AbstractVectorOfArray <: AbstractArray`. Thus we plan in 2026 to complete the deprecation and thus have a breaking update where `A[i]` matches the linear indexing of an`AbstractArray`, and then making `AbstractVectorOfArray <: AbstractArray`. Until then, `AbstractVectorOfArray` due to
this interface break but manually implements an `AbstractArray`-like interface for
future compatibility.
## Fields
An AbstractVectorOfArray has the following fields:
- `u` which holds the Vector of values at each timestep
## Array Interface
The general operations are as follows. Use
```julia
A.u[j]
```
to access the `j`th array. For multidimensional systems, this
will address first by component and lastly by time, and thus
```julia
A[i, j]
```
will be the `i`th component at array `j`. Hence, `A[j][i] == A[i, j]`. This is done
because Julia is column-major, so the leading dimension should be contiguous in memory.
If the independent variables had shape (for example, was a matrix), then `i` is the
linear index. We can also access solutions with shape:
```julia
A[i, k, j]
```
gives the `[i,k]` component of the system at array `j`. The colon operator is
supported, meaning that
```julia
A[i, :]
```
gives the timeseries for the `i`th component.
## Using the AbstractArray Interface
The `AbstractArray` interface can be directly used. For example, for a vector
system of variables `A[i,j]` is a matrix with rows being the variables and
columns being the timepoints. Operations like `A'` will
transpose the solution type. Functionality written for `AbstractArray`s can
directly use this. For example, the Base `cov` function computes correlations
amongst columns, and thus:
```julia
cov(A)
```
computes the correlation of the system state in time, whereas
```julia
cov(A, 2)
```
computes the correlation between the variables. Similarly, `mean(A,2)` is the
mean of the variable in time, and `var(A,2)` is the variance. Other statistical
functions and packages which work on `AbstractArray` types will work on the
solution type.
## Conversions
At anytime, a true `Array` can be created using `Array(A)`, or more generally `stack(A)`
to make the array type match the internal array type (for example, if `A` is an array
of GPU arrays, `stack(A)` will be a GPU array).
"""
abstract type AbstractVectorOfArray{T, N, A} end
"""
AbstractDiffEqArray{T, N, A} <: AbstractVectorOfArray{T, N, A}
An AbstractVectorOfArray object which has extra information of a time array `A.t`
in order to specify a time series. A canonical AbstractDiffEqArray is for example
the pairing `DiffEqArray([[1,2],[3,4]],[1.0,2.0])` which means that at time 1.0
the values were `[1,2]` and at time 2.0 the values were `[3,4]`.
An AbstractDiffEqArray has all of the same behaviors as an AbstractVectorOfArray with the
additional properties:
## Fields
An AbstractDiffEqArray adds the following fields:
- `t` which holds the times of each timestep.
"""
abstract type AbstractDiffEqArray{T, N, A} <: AbstractVectorOfArray{T, N, A} end
include("utils.jl")
include("vector_of_array.jl")
include("array_partition.jl")
include("named_array_partition.jl")
function Base.show(io::IO, x::Union{ArrayPartition, AbstractVectorOfArray})
invoke(show, Tuple{typeof(io), Any}, io, x)
end
import GPUArraysCore
Base.convert(T::Type{<:GPUArraysCore.AnyGPUArray}, VA::AbstractVectorOfArray) = stack(VA.u)
(T::Type{<:GPUArraysCore.AnyGPUArray})(VA::AbstractVectorOfArray) = T(Array(VA))
export VectorOfArray, DiffEqArray, AbstractVectorOfArray, AbstractDiffEqArray,
AllObserved, vecarr_to_vectors, tuples
export recursivecopy, recursivecopy!, recursivefill!, vecvecapply, copyat_or_push!,
vecvec_to_mat, recursive_one, recursive_mean, recursive_bottom_eltype,
recursive_unitless_bottom_eltype, recursive_unitless_eltype
export ArrayPartition, NamedArrayPartition
include("precompilation.jl")
end # module