@@ -39,9 +39,7 @@ from_parent_dims(::Type{<:SubArray{T,N,A,I}}) where {T,N,A,I} = _from_sub_dims(A
39
39
end
40
40
out
41
41
end
42
- function from_parent_dims (:: Type{<:PermutedDimsArray{T,N,<:Any,I}} ) where {T,N,I}
43
- return _val_to_static (Val (I))
44
- end
42
+ from_parent_dims (:: Type{<:PermutedDimsArray{T,N,<:Any,I}} ) where {T,N,I} = static (Val (I))
45
43
46
44
"""
47
45
to_parent_dims(::Type{T}) -> Bool
@@ -51,7 +49,7 @@ Returns the mapping from child dimensions to parent dimensions.
51
49
to_parent_dims (x) = to_parent_dims (typeof (x))
52
50
to_parent_dims (:: Type{T} ) where {T} = nstatic (Val (ndims (T)))
53
51
to_parent_dims (:: Type{T} ) where {T<: Union{Transpose,Adjoint} } = (StaticInt (2 ), One ())
54
- to_parent_dims (:: Type{<:PermutedDimsArray{T,N,I}} ) where {T,N,I} = _val_to_static (Val (I))
52
+ to_parent_dims (:: Type{<:PermutedDimsArray{T,N,I}} ) where {T,N,I} = static (Val (I))
55
53
to_parent_dims (:: Type{<:SubArray{T,N,A,I}} ) where {T,N,A,I} = _to_sub_dims (A, I)
56
54
@generated function _to_sub_dims (:: Type{A} , :: Type{I} ) where {A,N,I<: Tuple{Vararg{Any,N}} }
57
55
out = Expr (:tuple )
@@ -79,37 +77,44 @@ function has_dimnames(::Type{T}) where {T}
79
77
end
80
78
end
81
79
80
+ # this takes the place of dimension names that aren't defined
81
+ const SUnderscore = StaticSymbol (:_ )
82
+
82
83
"""
83
- dimnames(::Type{T}) -> Tuple{Vararg{Symbol }}
84
- dimnames(::Type{T}, d ) -> Symbol
84
+ dimnames(::Type{T}) -> Tuple{Vararg{StaticSymbol }}
85
+ dimnames(::Type{T}, dim ) -> StaticSymbol
85
86
86
87
Return the names of the dimensions for `x`.
87
88
"""
88
89
@inline dimnames (x) = dimnames (typeof (x))
89
- @inline dimnames (x, i :: Integer ) = dimnames (typeof (x), i )
90
- @inline dimnames (:: Type{T} , d :: Integer ) where {T} = getfield ( dimnames (T ), to_dims (T, d) )
91
- @inline function dimnames (:: Type{T} ) where {T}
92
- if parent_type (T) <: T
93
- return ntuple (i -> :_ , Val ( ndims (T)))
90
+ @inline dimnames (x, dim :: Int ) = dimnames (typeof (x), dim )
91
+ @inline dimnames (x, dim :: StaticInt ) = dimnames (typeof (x ), dim )
92
+ @inline function dimnames (:: Type{T} , :: StaticInt{dim} ) where {T,dim }
93
+ if ndims (T) < dim
94
+ return SUnderscore
94
95
else
95
- return dimnames (parent_type (T) )
96
+ return getfield ( dimnames (T), dim )
96
97
end
97
98
end
98
- @inline function dimnames (:: Type{T} ) where {T<: Union{Transpose,Adjoint} }
99
- return _transpose_dimnames (Val (dimnames (parent_type (T))))
99
+ @inline function dimnames (:: Type{T} , dim:: Int ) where {T}
100
+ if ndims (T) < dim
101
+ return SUnderscore
102
+ else
103
+ return getfield (dimnames (T), dim)
104
+ end
100
105
end
101
- # inserting the Val here seems to help inferability; I got a test failure without it.
102
- function _transpose_dimnames (:: Val{S} ) where {S}
103
- if length (S) == 1
104
- (:_ , first (S))
105
- elseif length (S) == 2
106
- (last (S), first (S))
106
+ @inline function dimnames (:: Type{T} ) where {T}
107
+ if parent_type (T) <: T
108
+ return ntuple (_ -> SUnderscore, Val (ndims (T)))
107
109
else
108
- throw ( " Can't transpose $S of dim $( length (S)) . " )
110
+ return dimnames ( parent_type (T) )
109
111
end
110
112
end
111
- @inline _transpose_dimnames (x:: Tuple{Symbol,Symbol} ) = (last (x), first (x))
112
- @inline _transpose_dimnames (x:: Tuple{Symbol} ) = (:_ , first (x))
113
+ @inline function dimnames (:: Type{T} ) where {T<: Union{Adjoint,Transpose} }
114
+ _transpose_dimnames (dimnames (parent_type (T)))
115
+ end
116
+ @inline _transpose_dimnames (x:: Tuple{Any,Any} ) = (last (x), first (x))
117
+ @inline _transpose_dimnames (x:: Tuple{Any} ) = (SUnderscore, first (x))
113
118
114
119
@inline function dimnames (:: Type{T} ) where {I,T<: PermutedDimsArray{<:Any,<:Any,I} }
115
120
return map (i -> dimnames (parent_type (T), i), I)
123
128
for i in 1 : length (I)
124
129
if I[i] > 0
125
130
if nl < i
126
- push! (e. args, QuoteNode ( :_ ))
131
+ push! (e. args, :(ArrayInterface . SUnderscore ))
127
132
else
128
133
push! (e. args, QuoteNode (L[i]))
129
134
end
@@ -132,83 +137,79 @@ end
132
137
return e
133
138
end
134
139
135
- """
136
- to_dims(x[, d])
140
+ _to_int (x :: Integer ) = Int (x)
141
+ _to_int (x :: StaticInt ) = x
137
142
138
- This returns the dimension(s) of `x` corresponding to `d`.
139
- """
140
- to_dims (x, d) = to_dims (dimnames (x), d)
141
- to_dims (x:: Tuple{Vararg{Symbol}} , d:: Integer ) = Int (d)
142
- to_dims (x:: Tuple{Vararg{Symbol}} , d:: Colon ) = d # `:` is the default for most methods that take `dims`
143
- @inline to_dims (x:: Tuple{Vararg{Symbol}} , d:: Tuple ) = map (i -> to_dims (x, i), d)
144
- @inline function to_dims (x:: Tuple{Vararg{Symbol}} , d:: Symbol ):: Int
145
- i = _sym_to_dim (x, d)
146
- if i === 0
147
- throw (ArgumentError (" Specified name ($(repr (d)) ) does not match any dimension name ($(x) )" ))
148
- end
149
- return i
150
- end
151
- Base. @pure function _sym_to_dim (x:: Tuple{Vararg{Symbol,N}} , sym:: Symbol ) where {N}
152
- for i in 1 : N
153
- getfield (x, i) === sym && return i
154
- end
155
- return 0
143
+ function no_dimname_error (@nospecialize (x), @nospecialize (dim))
144
+ throw (ArgumentError (" ($(repr (dim)) ) does not correspond to any dimension of ($(x) )" ))
156
145
end
157
146
158
147
"""
159
- tuple_issubset
148
+ to_dims(::Type{T}, dim) -> Integer
160
149
161
- A version of `issubset` sepecifically for `Tuple`s of `Symbol`s, that is `@pure`.
162
- This helps it get optimised out of existance. It is less of an abuse of `@pure` than
163
- most of the stuff for making `NamedTuples` work.
150
+ This returns the dimension(s) of `x` corresponding to `d`.
164
151
"""
165
- Base . @pure function tuple_issubset (
166
- lhs :: Tuple{Vararg{Symbol,N}} , rhs :: Tuple{Vararg{Symbol,M}}
167
- ) where {N,M}
168
- N <= M || return false
169
- for a in lhs
170
- found = false
171
- for b in rhs
172
- found |= a === b
173
- end
174
- found || return false
175
- end
176
- return true
152
+ to_dims (x, dim) = to_dims ( typeof (x), dim)
153
+ to_dims ( :: Type{T} , dim :: Integer ) where {T} = _to_int (dim)
154
+ to_dims ( :: Type{T} , dim :: Colon ) where {T} = dim
155
+ function to_dims ( :: Type{T} , dim :: StaticSymbol ) where {T}
156
+ i = find_first_eq (dim, dimnames (T))
157
+ i === nothing && no_dimname_error (T, dim)
158
+ return i
159
+ end
160
+ @inline function to_dims ( :: Type{T} , dim :: Symbol ) where {T}
161
+ i = find_first_eq (dim, Symbol .( dimnames (T)))
162
+ i === nothing && no_dimname_error (T, dim)
163
+ return i
177
164
end
165
+ to_dims (:: Type{T} , dims:: Tuple ) where {T} = map (i -> to_dims (T, i), dims)
178
166
179
- """
180
- order_named_inds(Val( names); kwargs... )
181
- order_named_inds(Val( names), namedtuple )
167
+ #=
168
+ order_named_inds(names, namedtuple )
169
+ order_named_inds(names, subnames, inds )
182
170
183
171
Returns the tuple of index values for an array with `names`, when indexed by keywords.
184
172
Any dimensions not fixed are given as `:`, to make a slice.
185
173
An error is thrown if any keywords are used which do not occur in `nda`'s names.
186
- """
187
- @inline function order_named_inds (val:: Val{L} ; kwargs... ) where {L}
188
- if isempty (kwargs)
189
- return ()
174
+
175
+
176
+ 1. parse into static dimnension names and key words.
177
+ 2. find each dimnames in key words
178
+ 3. if nothing is found use Colon()
179
+ 4. if (ndims - ncolon) === nkwargs then all were found, else error
180
+ =#
181
+ order_named_inds (x:: Tuple , :: NamedTuple{(),Tuple{}} ) = ()
182
+ function order_named_inds (x:: Tuple , nd:: NamedTuple{L} ) where {L}
183
+ return order_named_inds (x, static (Val (L)), Tuple (nd))
184
+ end
185
+ @aggressive_constprop function order_named_inds (
186
+ x:: Tuple{Vararg{Any,N}} ,
187
+ nd:: Tuple ,
188
+ inds:: Tuple
189
+ ) where {N}
190
+
191
+ out = eachop (((x, nd, inds), i) -> order_named_inds (x, nd, inds, i), (x, nd, inds), nstatic (Val (N)))
192
+ _order_named_inds_check (out, length (nd))
193
+ return out
194
+ end
195
+ function order_named_inds (x:: Tuple , nd:: Tuple , inds:: Tuple , :: StaticInt{dim} ) where {dim}
196
+ index = find_first_eq (getfield (x, dim), nd)
197
+ if index === nothing
198
+ return Colon ()
190
199
else
191
- return order_named_inds (val, kwargs. data)
192
- end
193
- end
194
- @generated function order_named_inds (val:: Val{L} , ni:: NamedTuple{K} ) where {L,K}
195
- tuple_issubset (K, L) || throw (DimensionMismatch (" Expected subset of $L , got $K " ))
196
- exs = map (L) do n
197
- if Base. sym_in (n, K)
198
- qn = QuoteNode (n)
199
- :(getfield (ni, $ qn))
200
- else
201
- :(Colon ())
202
- end
200
+ return @inbounds (inds[index])
203
201
end
204
- return Expr (:tuple , exs... )
205
202
end
206
- @generated function _perm_tuple (:: Type{T} , :: Val{P} ) where {T,P}
207
- out = Expr (:curly , :Tuple )
208
- for p in P
209
- push! (out. args, T. parameters[p])
203
+
204
+ ncolon (x:: Tuple{Colon,Vararg} , n:: Int ) = ncolon (tail (x), n + 1 )
205
+ ncolon (x:: Tuple{Any,Vararg} , n:: Int ) = ncolon (tail (x), n)
206
+ ncolon (x:: Tuple{Colon} , n:: Int ) = n + 1
207
+ ncolon (x:: Tuple{Any} , n:: Int ) = n
208
+ function _order_named_inds_check (inds:: Tuple{Vararg{Any,N}} , nkwargs:: Int ) where {N}
209
+ if (N - ncolon (inds, 0 )) != = nkwargs
210
+ error (" Not all keywords matched dimension names." )
210
211
end
211
- Expr ( :block , Expr ( :meta , :inline ), out)
212
+ return nothing
212
213
end
213
214
214
215
"""
@@ -226,14 +227,11 @@ function axes_types(::Type{T}) where {T}
226
227
return axes_types (parent_type (T))
227
228
end
228
229
end
229
- function axes_types (:: Type{T} ) where {T<: Adjoint }
230
- return _perm_tuple ( axes_types (parent_type (T)), Val (( 2 , 1 ) ))
230
+ function axes_types (:: Type{T} ) where {T<: MatAdjTrans }
231
+ return eachop_tuple (_get_tuple, axes_types (parent_type (T)), to_parent_dims (T ))
231
232
end
232
- function axes_types (:: Type{T} ) where {T<: Transpose }
233
- return _perm_tuple (axes_types (parent_type (T)), Val ((2 , 1 )))
234
- end
235
- function axes_types (:: Type{T} ) where {I1,T<: PermutedDimsArray{<:Any,<:Any,I1} }
236
- return _perm_tuple (axes_types (parent_type (T)), Val (I1))
233
+ function axes_types (:: Type{T} ) where {T<: PermutedDimsArray }
234
+ return eachop_tuple (_get_tuple, axes_types (parent_type (T)), to_parent_dims (T))
237
235
end
238
236
function axes_types (:: Type{T} ) where {T<: AbstractRange }
239
237
if known_length (T) === nothing
311
309
Expr (:block , Expr (:meta , :inline ), out)
312
310
end
313
311
314
-
315
-
316
312
"""
317
313
size(A)
318
314
@@ -330,12 +326,7 @@ julia> ArrayInterface.size(A)
330
326
@inline size (A) = Base. size (A)
331
327
@inline size (A, d:: Integer ) = size (A)[Int (d)]
332
328
@inline size (A, d) = Base. size (A, to_dims (A, d))
333
- @inline function size (x:: LinearAlgebra.Adjoint{T,V} ) where {T,V<: AbstractVector{T} }
334
- return (One (), static_length (x))
335
- end
336
- @inline function size (x:: LinearAlgebra.Transpose{T,V} ) where {T,V<: AbstractVector{T} }
337
- return (One (), static_length (x))
338
- end
329
+ @inline size (x:: VecAdjTrans ) = (One (), static_length (x))
339
330
340
331
function size (B:: S ) where {N,NP,T,A<: AbstractArray{T,NP} ,I,S<: SubArray{T,N,A,I} }
341
332
return _size (size (parent (B)), B. indices, map (static_length, B. indices))
357
348
Expr (:block , Expr (:meta , :inline ), t)
358
349
end
359
350
@inline size (v:: AbstractVector ) = (static_length (v),)
360
- @inline size (B:: MatAdjTrans ) = permute (size (parent (B)), Val {(2, 1)} ( ))
351
+ @inline size (B:: MatAdjTrans ) = permute (size (parent (B)), to_parent_dims (B ))
361
352
@inline function size (B:: PermutedDimsArray{T,N,I1,I2,A} ) where {T,N,I1,I2,A}
362
- return permute (size (parent (B)), Val {I1} ( ))
353
+ return permute (size (parent (B)), to_parent_dims (B ))
363
354
end
364
355
@inline size (A:: AbstractArray , :: StaticInt{N} ) where {N} = size (A)[N]
365
356
@inline size (A:: AbstractArray , :: Val{N} ) where {N} = size (A)[N]
0 commit comments