LCOV - code coverage report
Current view: top level - src - staticarrays.jl (source / functions) Hit Total Coverage
Test: on branch nothing Lines: 43 46 93.5 %
Date: 2025-02-19 11:29:30 Functions: 0 0 -

          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

Generated by: LCOV version 1.16