@@ -800,8 +800,9 @@ Return the vector of _canonical_ lower bounds on the parameters, `θ`.
800800Note that this method does not distinguish between constrained optimization and
801801unconstrained optimization with post-fit canonicalization.
802802"""
803- lowerbd (m:: LinearMixedModel{T} ) where {T} =
804- [(pm[2 ] == pm[3 ]) ? zero (T) : T (- Inf ) for pm in m. parmap]
803+ function lowerbd (m:: LinearMixedModel{T} ) where {T}
804+ return [(pm[2 ] == pm[3 ]) ? zero (T) : T (- Inf ) for pm in m. parmap]
805+ end
805806
806807function mkparmap (reterms:: Vector{<:AbstractReMat{T}} ) where {T}
807808 parmap = NTuple{3 ,Int}[]
@@ -1133,82 +1134,101 @@ end
11331134Base. show (io:: IO , m:: LinearMixedModel ) = Base. show (io, MIME (" text/plain" ), m)
11341135
11351136"""
1136- _coord(A::AbstractMatrix)
1137+ _findnz(A::AbstractMatrix)
1138+
1139+ Return the positions and values of the nonzeros in `A` as an (I, J, V) tuple
11371140
1138- Return the positions and values of the nonzeros in `A` as a
1139- `NamedTuple{(:i, :j, :v), Tuple{Vector{Int32}, Vector{Int32}, Vector{Float64}}}`
1141+ When possible, methods for this generic pass through to methods for `SparseArrays.findnz`.
1142+ The exceptions are the `Matrix` and `LinearAlgebra.Diagonal` classes where our defining a
1143+ `findnz` method would be type piracy.
11401144"""
1141- function _coord (A:: Diagonal )
1142- return (i= Int32 .(axes (A, 1 )), j= Int32 .(axes (A, 2 )), v= A. diag)
1143- end
11441145
1145- function _coord (A:: UniformBlockDiagonal )
1146- dat = A. data
1147- r, c, k = size (dat)
1148- blk = repeat (r .* (0 : (k - 1 )); inner= r * c)
1146+ function _findnz (A:: Matrix )
1147+ m, n = size (A)
11491148 return (
1150- i = Int32 .( repeat (1 : r ; outer= c * k) .+ blk ),
1151- j = Int32 .( repeat (1 : c; inner = r, outer = k) .+ blk ),
1152- v = vec (dat ),
1149+ repeat (axes (A, 1 ) ; outer= n ),
1150+ repeat (axes (A, 2 ); inner = m ),
1151+ vec (A ),
11531152 )
11541153end
11551154
1156- function _coord (A:: SparseMatrixCSC{T,Int32} ) where {T}
1157- rv = rowvals (A)
1158- cv = similar (rv)
1159- for j in axes (A, 2 ), k in nzrange (A, j)
1160- cv[k] = j
1161- end
1162- return (i= rv, j= cv, v= nonzeros (A))
1155+ function _findnz (A:: Diagonal )
1156+ return (axes (A, 1 ), axes (A, 2 ), A. diag)
11631157end
11641158
1165- _coord (A :: BlockedSparse ) = _coord (A . cscmat )
1159+ _findnz (x :: AbstractMatrix ) = findnz (x )
11661160
1167- function _coord (A:: Matrix )
1168- m, n = size (A)
1161+ function SparseArrays. findnz (A:: UniformBlockDiagonal )
1162+ dat = A. data
1163+ r, c, k = size (dat)
1164+ blk = repeat (r .* (0 : (k - 1 )); inner= r * c)
11691165 return (
1170- i = Int32 .( repeat (axes (A, 1 ) ; outer= n)) ,
1171- j = Int32 .( repeat (axes (A, 2 ) ; inner= m)) ,
1172- v = vec (A ),
1166+ repeat (1 : r ; outer= c * k) .+ blk ,
1167+ repeat (1 : c ; inner= r, outer = k) .+ blk ,
1168+ vec (dat ),
11731169 )
11741170end
11751171
1176- """
1177- sparseL(m::LinearMixedModel; fname::Symbol=first(fnames(m)), full::Bool=false)
1178-
1179- Return the lower Cholesky factor `L` as a `SparseMatrix{T,Int32}`.
1172+ SparseArrays. findnz (A:: BlockedSparse ) = findnz (A. cscmat)
11801173
1181- `full` indicates whether the parts of `L` associated with the fixed-effects and response
1182- are to be included.
1183-
1184- `fname` specifies the first grouping factor to include. Blocks to the left of the block corresponding
1185- to `fname` are dropped. The default is the first, i.e., leftmost block and hence all blocks.
1186- """
1187- function sparseL (
1188- m:: LinearMixedModel{T} ; fname:: Symbol = first (fnames (m)), full:: Bool = false
1174+ function sparsemat (
1175+ typ:: Symbol , m:: LinearMixedModel{T} ; fname:: Symbol = first (fnames (m)), full:: Bool = false
11891176) where {T}
1190- L, reterms = m. L, m. reterms
1177+ reterms = m. reterms
1178+ if typ ∉ (:A , :L )
1179+ throw (ArgumentError (" typ passed as $typ should be :A or :L" ))
1180+ end
1181+ bmat = getproperty (m, typ)
11911182 sblk = findfirst (isequal (fname), fnames (m))
11921183 if isnothing (sblk)
11931184 throw (ArgumentError (" fname = $fname is not the name of a grouping factor" ))
11941185 end
11951186 blks = sblk: (length (reterms) + full)
11961187 rowoffset, coloffset = 0 , 0
1197- val = (i= Int32[], j= Int32[], v= T[])
1188+ I = Int32[]
1189+ J = Int32[]
1190+ V = T[]
11981191 for i in blks, j in first (blks): i
1199- Lblk = L [block (i, j)]
1200- cblk = _coord (Lblk)
1201- append! (val . i, cblk. i .+ Int32 (rowoffset))
1202- append! (val . j , cblk. j .+ Int32 (coloffset))
1203- append! (val . v, cblk. v )
1192+ Lblk = bmat [block (i, j)]
1193+ cblk = _findnz (Lblk)
1194+ append! (I, first ( cblk) .+ Int32 (rowoffset))
1195+ append! (J , cblk[ 2 ] .+ Int32 (coloffset))
1196+ append! (V, last ( cblk) )
12041197 if i == j
12051198 coloffset = 0
12061199 rowoffset += size (Lblk, 1 )
12071200 else
12081201 coloffset += size (Lblk, 2 )
12091202 end
12101203 end
1211- return dropzeros! (tril! (sparse (val... )))
1204+ return tril! (sparse (I, J, V))
1205+ end
1206+
1207+ """
1208+ sparseL(m::LinearMixedModel; fname::Symbol=first(fnames(m)), full::Bool=false)
1209+
1210+ Return the lower Cholesky factor `L` as a `SparseMatrix{T,Int32}`.
1211+
1212+ `full` indicates whether the parts of `L` associated with the fixed-effects and response
1213+ are to be included.
1214+
1215+ `fname` specifies the first grouping factor to include. Blocks to the left of the block corresponding
1216+ to `fname` are dropped. The default is the first, i.e., leftmost block and hence all blocks.
1217+
1218+ The matrix that is returned is lower-triangular but has not been wrapped in `LowerTriangular`.
1219+ """
1220+ function sparseL (m:: LinearMixedModel ; fname:: Symbol = first (fnames (m)), full:: Bool = false )
1221+ return dropzeros! (sparsemat (:L , m; fname, full))
1222+ end
1223+
1224+ """
1225+ sparseA(m::LinearMixedModel; fname::Symbol=first(fnames(m)), full::Bool=false)
1226+
1227+ Same as [`sparseL`](@ref) but returning the sparse lower triangle of the symmetric `A` matrix.
1228+ Most of the time the result is wrapped as, e.g. `Symmetric(sparseM(m; full=true), :L)`
1229+ """
1230+ function sparseA (m:: LinearMixedModel ; fname:: Symbol = first (fnames (m)), full:: Bool = false )
1231+ return sparsemat (:A , m; fname, full)
12121232end
12131233
12141234"""
0 commit comments