Repository: JuliaStats/MixedModels.jl (julia)

Issue:
σs needs to learn the fields in Diagonal
```julia
julia> slp = MixedModels.dataset(:sleepstudy)
Arrow.Table with 180 rows, 3 columns, and schema:
 :subj      String
 :days      Int8
 :reaction  Float64

julia> m1 = fit(MixedModel, @formula(reaction ~ 1 + days + zerocorr(1+days|subj)), slp)
Linear mixed model fit by maximum likelihood
 reaction ~ 1 + days + MixedModels.ZeroCorr((1 + days | subj))
   logLik   -2 logLik     AIC       AICc        BIC    
  -876.0016  1752.0033  1762.0033  1762.3481  1777.9680

Variance components:
            Column    Variance Std.Dev.   Corr.
subj     (Intercept)  584.25897 24.17145
         days          33.63281  5.79938   .  
Residual              653.11578 25.55613
 Number of obs: 180; levels of grouping factors: 18

  Fixed-effects parameters:
──────────────────────────────────────────────────
                Coef.  Std. Error      z  Pr(>|z|)
──────────────────────────────────────────────────
(Intercept)  251.405      6.70771  37.48    <1e-99
days          10.4673     1.51931   6.89    <1e-11
──────────────────────────────────────────────────

julia> m1.σs
ERROR: type Diagonal has no field data
Stacktrace:
 [1] getproperty
   @ ./Base.jl:33 [inlined]
 [2] σs(A::ReMat{Float64, 2}, sc::Float64)
   @ MixedModels ~/.julia/packages/MixedModels/HXYeP/src/remat.jl:526
 [3] (::MixedModels.var"#97#98"{Float64})(t::ReMat{Float64, 2})
   @ MixedModels ./none:0
 [4] iterate(::Base.Generator{Vector{AbstractReMat{Float64}}, MixedModels.var"#97#98"{Float64}})
   @ Base ./generator.jl:47
 [5] σs(m::LinearMixedModel{Float64})
   @ MixedModels ~/.julia/packages/MixedModels/HXYeP/src/mixedmodel.jl:108
 [6] getproperty(m::LinearMixedModel{Float64}, s::Symbol)
   @ MixedModels ~/.julia/packages/MixedModels/HXYeP/src/linearmixedmodel.jl:534
 [7] top-level scope
   @ REPL[8]:1
```
For `Diagonal` the desired field is called `diag`.

Pull request description:
- Add internal methods for σs for `ReMat{T,S}` so the case of a Diagonal λ is handled properly
- Add a test
- Closes #531

Patch:
diff --git a/src/remat.jl b/src/remat.jl
index 5f21c4569..c469c4b61 100644
--- a/src/remat.jl
+++ b/src/remat.jl
@@ -522,11 +522,17 @@ function σs(A::ReMat{T,1}, sc::T) where {T}
     NamedTuple{(Symbol(only(A.cnames)),)}(sc*abs(only(A.λ.data)),)
 end
 
-function σs(A::ReMat{T}, sc::T) where {T}
-    λ = A.λ.data
-    NamedTuple{(Symbol.(A.cnames)...,)}(ntuple(i -> sc*norm(view(λ,i,1:i)), size(λ, 1)))
+function _σs(λ::LowerTriangular{T}, sc::T, cnames) where {T}
+    λ = λ.data
+    NamedTuple{(Symbol.(cnames)...,)}(ntuple(i -> sc*norm(view(λ,i,1:i)), size(λ, 1)))
+end
+
+function _σs(λ::Diagonal{T}, sc::T, cnames) where {T}
+    NamedTuple{(Symbol.(cnames)...,)}(((sc .* λ.diag)...,))
 end
 
+σs(A::ReMat{T}, sc::T) where {T} = _σs(A.λ, sc, A.cnames)
+
 function σρs(A::ReMat{T,1}, sc::T) where {T}
     NamedTuple{(:σ,:ρ)}(
         (NamedTuple{(Symbol(only(A.cnames)),)}((sc*abs(only(A.λ.data)),)), ())


Test patch:
diff --git a/test/pls.jl b/test/pls.jl
index 173eeeb1e..f59259654 100644
--- a/test/pls.jl
+++ b/test/pls.jl
@@ -355,6 +355,9 @@ end
     @test size(fmnc) == (180,2,36,1)
     @test fmnc.optsum.initial == ones(2)
     @test lowerbd(fmnc) == zeros(2)
+    sigmas = fmnc.σs
+    @test length(only(sigmas)) == 2
+    @test first(only(sigmas)) ≈ 24.171449484676224 atol=1e-4
 
     @testset "zerocorr PCA" begin
         @test length(fmnc.rePCA) == 1