1
+ # module GetIndex
2
+
3
+ # using ..LinearMaps: LinearMap, AdjointMap, TransposeMap, FillMap, LinearCombination,
4
+ # ScaledMap, UniformScalingMap, WrappedMap
5
+
6
+ # required in Base.to_indices for [:]-indexing
7
+ Base. eachindex (:: IndexLinear , A:: LinearMap ) = (Base. @_inline_meta ; Base. OneTo (length (A)))
8
+ # Base.IndexStyle(::LinearMap) = IndexCartesian()
9
+ # Base.IndexStyle(A::Union{WrappedMap,AdjointMap,TransposeMap,ScaledMap}) = IndexStyle(A.lmap)
10
+
11
+ function Base. checkbounds (A:: LinearMap , i, j)
12
+ Base. @_inline_meta
13
+ Base. checkbounds_indices (Bool, axes (A), (i, j)) || throw (BoundsError (A, (i, j)))
14
+ nothing
15
+ end
16
+ # Linear indexing is explicitly allowed when there is only one (non-cartesian) index
17
+ function Base. checkbounds (A:: LinearMap , i)
18
+ Base. @_inline_meta
19
+ Base. checkindex (Bool, Base. OneTo (length (A)), i) || throw (BoundsError (A, i))
20
+ nothing
21
+ end
22
+
23
+ # dispatch hierarchy
24
+ # Base.getindex (includes bounds checking)
25
+ # -> Base._getindex (conversion of linear indices to cartesian indices)
26
+ # -> _unsafe_getindex
27
+ # main entry point
28
+ Base. @propagate_inbounds function Base. getindex (A:: LinearMap , I... )
29
+ # TODO : introduce some sort of switch?
30
+ Base. @_inline_meta
31
+ @boundscheck checkbounds (A, I... )
32
+ _getindex (A, Base. to_indices (A, I)... )
33
+ end
34
+ # quick pass forward
35
+ Base. @propagate_inbounds Base. getindex (A:: ScaledMap , I... ) = A. λ .* getindex (A. lmap, I... )
36
+ Base. @propagate_inbounds Base. getindex (A:: AdjointMap , i:: Integer ) =
37
+ adjoint (A. lmap[i- 1 + first (axes (A. lmap)[1 ])])
38
+ Base. @propagate_inbounds Base. getindex (A:: AdjointMap , i:: Integer , j:: Integer ) =
39
+ adjoint (A. lmap[j, i])
40
+ Base. @propagate_inbounds Base. getindex (A:: TransposeMap , i:: Integer ) =
41
+ transpose (A. lmap[i- 1 + first (axes (A. lmap)[1 ])])
42
+ Base. @propagate_inbounds Base. getindex (A:: TransposeMap , i:: Integer , j:: Integer ) =
43
+ transpose (A. lmap[j, i])
44
+ Base. @propagate_inbounds Base. getindex (A:: WrappedMap , I... ) = A. lmap[I... ]
45
+ Base. @propagate_inbounds Base. getindex (A:: WrappedMap , i:: Integer ) = A. lmap[i]
46
+ Base. @propagate_inbounds Base. getindex (A:: WrappedMap , i:: Integer , j:: Integer ) = A. lmap[i,j]
47
+
48
+ # Base._getindex, IndexLinear
49
+ # Base.@propagate_inbounds Base._getindex(::IndexLinear, A::LinearMap, i::Integer) = _unsafe_getindex(A, i)
50
+ # Base.@propagate_inbounds function Base._getindex(::IndexLinear, A::LinearMap, i::Integer, j::Integer)
51
+ # Base.@_inline_meta
52
+ # # @boundscheck checkbounds(A, i, j)
53
+ # return _unsafe_getindex(A, Base._sub2ind(axes(A), i, j))
54
+ # end
55
+ # Base._getindex, IndexCartesian
56
+ Base. @propagate_inbounds function _getindex (A:: LinearMap , i:: Integer )
57
+ Base. @_inline_meta
58
+ @boundscheck checkbounds (A, i)
59
+ i1, i2 = Base. _ind2sub (axes (A), i)
60
+ @inbounds r = _unsafe_getindex (A, i1, i2)
61
+ return r
62
+ end
63
+ Base. @propagate_inbounds _getindex (A:: LinearMap , i:: Integer , j:: Integer ) =
64
+ _unsafe_getindex (A, i, j)
65
+
66
+ # #######################
67
+ # scalar indexing
68
+ # #######################
69
+ # fallback via colon-based method
70
+ Base. @propagate_inbounds _unsafe_getindex (A:: LinearMap , i:: Integer , j:: Integer ) =
71
+ (Base. @_inline_meta ; _getindex (A, Base. Slice (axes (A)[1 ]), j)[i])
72
+ # specialized methods
73
+ _unsafe_getindex (A:: FillMap , :: Integer , :: Integer ) = A. λ
74
+ Base. @propagate_inbounds _unsafe_getindex (A:: LinearCombination , i:: Integer , j:: Integer ) =
75
+ sum (a -> getindex (A. maps[a], i, j), eachindex (A. maps))
76
+ _unsafe_getindex (A:: UniformScalingMap , i:: Integer , j:: Integer ) =
77
+ ifelse (i == j, A. λ, zero (eltype (A)))
78
+
79
+ # #######################
80
+ # multidimensional slicing
81
+ # #######################
82
+ Base. @propagate_inbounds function _getindex (A:: LinearMap , i:: Integer , J:: AbstractVector{<:Integer} )
83
+ try
84
+ return (basevec (A, i)' A)[J]
85
+ catch
86
+ x = zeros (eltype (A), size (A, 2 ))
87
+ y = similar (x, eltype (A), size (A, 1 ))
88
+ r = similar (x, eltype (A), length (J))
89
+ @inbounds for (ind, j) in enumerate (J)
90
+ x[j] = one (eltype (A))
91
+ _unsafe_mul! (y, A, x)
92
+ r[ind] = y[i]
93
+ x[j] = zero (eltype (A))
94
+ end
95
+ return r
96
+ end
97
+ end
98
+ Base. @propagate_inbounds _getindex (A:: LinearMap , I:: AbstractVector{<:Integer} , j:: Integer ) =
99
+ (Base. @_inline_meta ; _getindex (A, Base. Slice (axes (A)[1 ]), j)[I])
100
+ Base. @propagate_inbounds function _getindex (A:: LinearMap , Is:: Vararg{AbstractVector{<:Integer},2} )
101
+ shape = Base. index_shape (Is... )
102
+ dest = zeros (eltype (A), shape)
103
+ I, J = Is
104
+ for (ind, ij) in zip (eachindex (dest), Iterators. product (I, J))
105
+ i, j = ij
106
+ dest[ind] = _unsafe_getindex (A, i, j)
107
+ end
108
+ return dest
109
+ end
110
+ Base. @propagate_inbounds function _getindex (A:: LinearMap , I:: AbstractVector{<:Integer} )
111
+ dest = Vector {eltype(A)} (undef, length (I))
112
+ for i in eachindex (dest, I)
113
+ dest[i] = _getindex (A, I[i])
114
+ end
115
+ return dest
116
+ end
117
+ _getindex (A:: LinearMap , :: Base.Slice , :: Base.Slice ) = Matrix (A)
118
+ _getindex (A:: LinearMap , :: Base.Slice ) = vec (Matrix (A))
119
+ function _getindex (A:: LinearMap , i:: Integer , J:: Base.Slice )
120
+ try
121
+ return vec (basevec (A, i)' A)
122
+ catch
123
+ return vec (_getindex (A, i: i, J))
124
+ end
125
+ end
126
+ _getindex (A:: LinearMap , :: Base.Slice , j:: Integer ) = A* basevec (A, j)
127
+ # Needs to be defined for custom LinearMap subtypes
128
+ # Base.@propagate_inbounds function _unsafe_getindex(A::CustomMap, i::Union{Integer,AbstractVector{<:Integer}})
129
+ function _getindex (A:: LinearMap , I:: AbstractVector{<:Integer} , :: Base.Slice )
130
+ x = zeros (eltype (A), size (A, 2 ))
131
+ y = similar (x, eltype (A), size (A, 1 ))
132
+ r = similar (x, eltype (A), (length (I), size (A, 2 )))
133
+ @views @inbounds for j in axes (A)[2 ]
134
+ x[j] = one (eltype (A))
135
+ _unsafe_mul! (y, A, x)
136
+ r[:,j] .= y[I]
137
+ x[j] = zero (eltype (A))
138
+ end
139
+ return r
140
+ end
141
+ function _getindex (A:: LinearMap , :: Base.Slice , J:: AbstractVector{<:Integer} )
142
+ x = zeros (eltype (A), size (A, 2 ))
143
+ y = similar (x, eltype (A), (size (A, 1 ), length (J)))
144
+ @inbounds for (i, j) in enumerate (J)
145
+ x[j] = one (eltype (A))
146
+ _unsafe_mul! (selectdim (y, 2 , i), A, x)
147
+ x[j] = zero (eltype (A))
148
+ end
149
+ return y
150
+ end
151
+
152
+ # helpers
153
+ function basevec (A, i:: Integer )
154
+ x = zeros (eltype (A), size (A, 2 ))
155
+ @inbounds x[i] = one (eltype (A))
156
+ return x
157
+ end
158
+
159
+ nogetindex_error () = error (" indexing not allowed for LinearMaps; consider setting `LinearMaps.allowgetindex = true`" )
160
+
161
+ # end # module
0 commit comments