Line data Source code
1 : #
2 : # I am missing a matrix with fixed size columns (fixed row dimension
3 : # M) in StaticArrays.
4 : #
5 : # I don't want to pay the run-time penalty of Base.ReinterpretArray!
6 : # (Got a factor near 2.)
7 : #
8 : # SCMatrix does the job by a bit-wise cast of either a Matrix or a
9 : # Vector{SVector}: It stores the original data (which guarantees
10 : # ownership), and an "unsafe reinterpretation".
11 : #
12 :
13 1 : function unsafe_svector(::Val{M}, A::Matrix{T}) where {M, T}
14 1 : @assert size(A, 1) == M
15 1 : unsafe_wrap(Vector{SVector{M, T}},
16 : convert(Ptr{SVector{M, T}}, Base.pointer(A)), size(A,2);
17 : own = false)
18 : end
19 :
20 :
21 1 : function unsafe_svector(v::Vector{NTuple{M, T}}) where {M, T}
22 1 : unsafe_wrap(Vector{SVector{M, T}},
23 : convert(Ptr{SVector{M, T}}, Base.pointer(v)), length(v);
24 : own = false)
25 : end
26 :
27 : """
28 : v = unsafe_svector(Val(M), A)
29 :
30 : Convert matrix `A` with `M` rows to `v::Vector{SVector{N, T}}` without
31 : taking ownership.
32 :
33 : See also [`unsafe_matrix`](@ref), [`unsafe_ntuple`](@ref), [`SCMatrix`](@ref)
34 : """ unsafe_svector
35 :
36 : """
37 : v = unsafe_ntuple(v)
38 :
39 : Convert matrix `A` with `M` rows to `v::Vector{SVector{N, T}}` without
40 : taking ownership.
41 :
42 : See also [`unsafe_svector`](@ref), [`unsafe_matrix`](@ref), [`SCMatrix`](@ref)
43 : """
44 1 : function unsafe_ntuple(v::Vector{SVector{M, T}}) where {M, T}
45 1 : unsafe_wrap(Vector{NTuple{M, T}},
46 : convert(Ptr{NTuple{M, T}}, Base.pointer(v)), length(v);
47 : own = false)
48 : end
49 :
50 : """
51 : A = unsafe_matrix(v)
52 :
53 : Convert vector `v::Vector{SVector{N, T}` to matrix without taking
54 : ownership.
55 :
56 : See also [`unsafe_svector`](@ref), [`unsafe_ntuple`](@ref), [`SCMatrix`](@ref)
57 : """
58 5 : function unsafe_matrix(v::Vector{SVector{M, T}}) where {M, T}
59 5 : unsafe_wrap(Matrix{T},
60 : convert(Ptr{T}, Base.pointer(v)), (M, length(v));
61 : own = false)
62 : end
63 :
64 : """
65 : SC = scmatrix(Val(M), rand(M, n))
66 : SC = scmatrix([@SVector rand(M) for i in 1:n])
67 : SC = scmatrix(Val(M), [@SVector rand(M) for i in 1:n])
68 : SC === scmatrix(SC)
69 :
70 : Construct matrix `SCMatric{M, T}` with fixed size columns (fixed row
71 : dimension `M`, **static** column size). An `SCMatrix{M, T}` can be
72 : viewed either as a `Matrix{T}` or as a `Vector{SVector{M, T}}`:
73 :
74 : A = matrix(SC)
75 : c::Vector{SVector} = columns(A)
76 :
77 : Requirements for `AbstractMatrix` are delegated to `SCMatrix`:
78 :
79 : - `SC[:, j]` returns an SVector.
80 : - `SC[:, j] = x` writes an entire column.
81 : - The general `getindex!` gives an error: individual elements are
82 : immutable!
83 : - `size`, `ndims` and `length` refer to `matrix(SC)`.
84 : - `matrix(SC)` or `SC[]` gives the `Matrix`
85 : - `columns(SC)` or `SC[:]` gives the `Vector` of columns.
86 :
87 : As an alternative to `SVector`, columns can be interpreted as
88 : `NTuple`s at construction and access as `Vector` of columns:
89 :
90 : SC = scmatrix([ntuple(_ -> rand(), Val(M)) for i in 1:n])
91 : t::Vector{NTuple} = ntuples(A)
92 :
93 : !!! warn
94 : Different from `Matrix` and `SVector`, the `SCMatrix`
95 : constructed from *tuples* `t` does **not** take ownership of `t`!
96 : It is valid only during the lifetime of `t`!
97 :
98 : See also [`scmatrix`](@ref), [`matrix`](@ref), [`columns`](@ref),
99 : [`ntuples`](@ref)
100 : """
101 : struct SCMatrix{M, T} <: AbstractMatrix{T}
102 : mat::Matrix{T}
103 : vec::Vector{SVector{M, T}}
104 :
105 : # Note: Either mat or vec owns the data!
106 :
107 1 : SCMatrix{M, T}(data::Matrix{T}) where {M, T} =
108 : new(data, unsafe_svector(Val(M), data))
109 :
110 5 : SCMatrix{M, T}(data::Vector{SVector{M, T}}) where {M, T} =
111 : new(unsafe_matrix(data), data)
112 : end
113 :
114 0 : @inline Base.ndims(A::SCMatrix) = 2
115 1 : @inline Base.size(A::SCMatrix{M}) where {M} = (M, length(A.vec))
116 :
117 1 : @inline Base.getindex(A::SCMatrix, i::Int) = Base.getindex(A.mat, i)
118 3 : @inline Base.getindex(A::SCMatrix, I::Vararg{Int, 2}) = Base.getindex(A.mat, I...)
119 0 : @inline Base.setindex!(_A::SCMatrix, _v, _i...) = error("SCMatrix columns are immutable!")
120 :
121 3 : @inline Base.getindex(A::SCMatrix, ::Colon, j::Int) = A.vec[j]
122 4 : @inline Base.setindex!(A::SCMatrix, v, ::Colon, j::Int) = A.vec[j] = v
123 :
124 : """
125 : A = matrix(SC)
126 : A = SC[]
127 :
128 : View [`SCMatrix`](@ref) as `Matrix`.
129 :
130 : See also [`SCMatrix`](@ref)
131 : """
132 12 : @inline matrix(A::SCMatrix) = A.mat
133 :
134 : """
135 : c = SC[]
136 :
137 : Synonym for [`matrix`](@ref)
138 :
139 : See also [`SCMatrix`](@ref)
140 : """
141 9 : @inline Base.getindex(A::SCMatrix) = matrix(A)
142 :
143 : """
144 : c = columns(SC)
145 : c = SC[:]
146 :
147 : View [`SCMatrix`](@ref) as `c::Vector{SVector}` of columns.
148 :
149 : See also [`SCMatrix`](@ref), [`ntuples`](@ref)
150 : """
151 11 : @inline columns(A::SCMatrix) = A.vec
152 :
153 : """
154 : t = ntuples(SC)
155 :
156 : Same as [`columns`](@ref), but view [`SCMatrix`](@ref) as
157 : `t::Vector{NTuple}`, i.e., each column is represented as an `NTuple`.
158 :
159 : See also [`SCMatrix`](@ref), [`columns`](@ref)
160 : """
161 1 : @inline ntuples(A::SCMatrix) = unsafe_ntuple(columns(A))
162 :
163 : """
164 : c = SC[:]
165 :
166 : Synonym for [`columns`](@ref)
167 :
168 : See also [`SCMatrix`](@ref)
169 : """
170 8 : @inline Base.getindex(A::SCMatrix, ::Colon) = columns(A)
171 :
172 : # note: show is defined from show(::AbstractMatrix)
173 :
174 1 : scmatrix(::Val{M}, A::Matrix{T}) where {M, T} = SCMatrix{M, T}(A)
175 :
176 4 : scmatrix(x::Vector{SVector{M, T}}) where {M, T} = SCMatrix{M, T}(x)
177 :
178 1 : scmatrix(x::Vector{NTuple{M, T}}) where {M, T} =
179 : SCMatrix{M, T}(unsafe_svector(x))
180 :
181 1 : scmatrix(::Val{M}, x::Vector{SVector{M, T}}) where {M, T} = scmatrix(x)
182 :
183 0 : scmatrix(sc::SCMatrix{M, T}) where {M, T} = sc
184 :
185 : """
186 : SC = scmatrix(Val(M), rand(M, n))
187 : SC = scmatrix([@SVector rand(M) for i in 1:n])
188 : SC = scmatrix(Val(M), [@SVector rand(M) for i in 1:n])
189 : SC = scmatrix([ntuple(_ -> rand(), Val(M)) for i in 1:n])
190 :
191 : SC === scmatrix(SC)
192 :
193 : Construct [`SCMatrix`](@ref).
194 :
195 : !!! note
196 : Construction of a `SCMatrix` from a `SCMatrix` returns the
197 : identical matrix.
198 :
199 : See also [`SCMatrix`](@ref)
200 : """ scmatrix
201 :
202 1 : joinrows(x::Vector{SVector{N, T}}) where {N, T} = joinrows(scmatrix(x))
203 :
204 1 : joinrows(x::SCMatrix{M, T}) where {M, T} = copy(x[]')
205 :
206 : """
207 : X = joinrows(x::Vector{SVector}, Val(N))
208 : X = joinrows(x::SCMatrix)
209 :
210 : Construct `Matrix X` that has vectors `x[i]` as rows.
211 :
212 : See also [`joinrows!`](@ref), [`splitrows`](@ref), [`scmatrix`](@ref)
213 : """
214 :
215 : """
216 : joinrows!(X::AbstractMatrix{T}, x::Vector{SVector{N, T}})
217 :
218 : Copy rows of matrix `X` into `x`.
219 :
220 : !!! warn "precondition"
221 : Requires `size(X) == length(x), N`
222 :
223 : See also [`joinrows`](@ref), [`splitrows!`](@ref), [`scmatrix`](@ref)
224 : """
225 1 : joinrows!(X::Matrix{T}, x::Vector{SVector{N, T}}) where {N, T} =
226 : joinrows!(X, scmatrix(x))
227 :
228 1 : function joinrows!(X::Matrix{T}, x::SCMatrix{M, T}) where {M, T}
229 1 : X' .= x[]
230 1 : X
231 : end
232 :
233 : """
234 : x = splitrows(X, Val(N))
235 :
236 : Store rows of `_ × N` matrix `X` as entries in `x::Vector{SVector{N}}`.
237 :
238 : !!! warn "precondition"
239 : Requires `size(X, 2) == N`!
240 :
241 : See also [`splitrows!`](@ref), [`joinrows`](@ref), [`scmatrix`](@ref)
242 : """
243 1 : function splitrows(X::Matrix{T}, ::Val{N}) where {N, T}
244 1 : n, _ = size(X)
245 2 : x = Vector{SVector{N, T}}(undef, n)
246 :
247 1 : for j in 1:length(x)
248 6 : x[j] = SVector(X[j, 1:N]...)
249 5 : end
250 :
251 1 : x
252 : end
253 :
254 : """
255 : x = splitrows!(x, X[, Val(N)=Val(M)])
256 :
257 : Store rows of `_ × N` matrix `X` as entries in `x::Vector{SVector{M}}`
258 : with `M >= N`. If vector dimension is larger than `N` (i.e., the
259 : number of columns in `X`, the remaining elements of the vectors remain
260 : untouched.
261 :
262 : Overwrites contents of `x`.
263 :
264 : !!! warn "precondition"
265 : Requires `length(x) == size(X, 1)` and `size(X, 2) >= N`!
266 :
267 : See also [`splitrows`](@ref), [`joinrows`](@ref), [`scmatrix`](@ref)
268 : """
269 2 : function splitrows!(x::Vector{SVector{N, T}}, X::Matrix{T},
270 : ::Val{M}=Val(N)) where {N, T, M}
271 2 : for j in 1:length(x)
272 3 : x[j] = SVector(X[j, 1:M]..., x[j][M+1:N]...)
273 5 : end
274 :
275 1 : x
276 : end
|