From b106430df02466eb2fdfa2f8ff4bb858c086ee6e Mon Sep 17 00:00:00 2001 From: Milan Bouchet-Valat Date: Wed, 4 May 2022 15:02:24 +0200 Subject: [PATCH 01/51] Stop exporting removed `describeblocks` (#612) This makes StatsKit tests fail when checking that no exported function conflicts with other packages it reexports. --- src/MixedModels.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/MixedModels.jl b/src/MixedModels.jl index b8fc26e8f..17db28ec5 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -76,7 +76,6 @@ export @formula, cond, condVar, condVartables, - describeblocks, deviance, dispersion, dispersion_parameter, From cf3a6f1a32c69047535cef76e6a1b4b9462510c6 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Tue, 17 May 2022 13:01:33 -0500 Subject: [PATCH 02/51] Simplify BLAS configuration printing (#597) * Simplify BLAS configuration printing * Add NEWS.md item --- NEWS.md | 5 +++++ test/runtests.jl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index b52fae73b..26dbd562d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.6.4 Release Notes +======================== +* Simplify printing of BLAS configuration in tests. [#597] + MixedModels v4.6.3 Release Notes ======================== * Add precompile statements to speed up first `LinearMixedModel` and Bernoulli `GeneralizedLinearModel` fit [#608] @@ -336,6 +340,7 @@ Package dependencies [#577]: https://github.com/JuliaStats/MixedModels.jl/issues/577 [#578]: https://github.com/JuliaStats/MixedModels.jl/issues/578 [#588]: https://github.com/JuliaStats/MixedModels.jl/issues/588 +[#597]: https://github.com/JuliaStats/MixedModels.jl/issues/597 [#598]: https://github.com/JuliaStats/MixedModels.jl/issues/598 [#603]: https://github.com/JuliaStats/MixedModels.jl/issues/603 [#604]: https://github.com/JuliaStats/MixedModels.jl/issues/604 diff --git a/test/runtests.jl b/test/runtests.jl index 419373425..bac90db8a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,7 +5,7 @@ import LinearAlgebra: BLAS # there seem to be processor-specific issues and knowing this is helpful println(versioninfo()) @static if VERSION ≥ v"1.7.0-DEV.620" - @show getproperty.(BLAS.get_config().loaded_libs, :libname) + println(BLAS.get_config()) else @show BLAS.vendor() if startswith(string(BLAS.vendor()), "openblas") From 621f88b1f594ea0827d9ac7e8628113dd2121bef Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 17 May 2022 18:57:00 -0500 Subject: [PATCH 03/51] support transformed response for predict (#614) * support transformed response for predict * NEWS and patch bump * more tests * remove some progress bars in tests --- NEWS.md | 2 ++ Project.toml | 2 +- src/predict.jl | 5 +++-- test/bootstrap.jl | 19 ++++++++++++------- test/predict.jl | 26 ++++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index 26dbd562d..129fa2f19 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ MixedModels v4.6.4 Release Notes ======================== +* Support transformed responses in `predict` [#614] * Simplify printing of BLAS configuration in tests. [#597] MixedModels v4.6.3 Release Notes @@ -345,3 +346,4 @@ Package dependencies [#603]: https://github.com/JuliaStats/MixedModels.jl/issues/603 [#604]: https://github.com/JuliaStats/MixedModels.jl/issues/604 [#608]: https://github.com/JuliaStats/MixedModels.jl/issues/608 +[#614]: https://github.com/JuliaStats/MixedModels.jl/issues/614 diff --git a/Project.toml b/Project.toml index 9210ee3aa..e9d971566 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.6.3" +version = "4.6.4" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/predict.jl b/src/predict.jl index 1aef3675a..9aa0d7a5e 100644 --- a/src/predict.jl +++ b/src/predict.jl @@ -102,8 +102,9 @@ function _predict(m::MixedModel{T}, newdata, β; new_re_levels) where {T} # we get type stability via constant propogation on `new_re_levels` y, mnew = let ytemp = ones(T, length(first(newdata))) f, contr = _abstractify_grouping(m.formula) - respname = Symbol(f.lhs) - if !(respname in Tables.columnnames(newdata)) || any(ismissing, newdata[respname]) + respvars = StatsModels.termvars(f.lhs) + if !issubset(respvars, Tables.columnnames(newdata)) || + any(any(ismissing, Tables.getcolumn(newdata, col)) for col in respvars) throw( ArgumentError( "Response column must be initialized to a non-missing numeric value.", diff --git a/test/bootstrap.jl b/test/bootstrap.jl index 8779c262a..c532c69b9 100644 --- a/test/bootstrap.jl +++ b/test/bootstrap.jl @@ -70,7 +70,8 @@ end # 2. test method for default RNG parametricbootstrap(1, fm, β=[1], σ=1) - bsamp = parametricbootstrap(MersenneTwister(1234321), 100, fm, use_threads=false) + bsamp = parametricbootstrap(MersenneTwister(1234321), 100, fm; + use_threads=false, hide_progress=true) @test isa(propertynames(bsamp), Vector{Symbol}) @test length(bsamp.objective) == 100 @test keys(first(bsamp.fits)) == (:objective, :σ, :β, :se, :θ) @@ -93,7 +94,8 @@ end @test propertynames(coefp) == [:iter, :coefname, :β, :se, :z, :p] @testset "threaded bootstrap" begin - bsamp_threaded = parametricbootstrap(MersenneTwister(1234321), 100, fm, use_threads=true) + bsamp_threaded = parametricbootstrap(MersenneTwister(1234321), 100, fm; + use_threads=true, hide_progress=true) # even though it's bad practice with floating point, exact equality should # be a valid test here -- if everything is working right, then it's the exact # same operations occuring within each bootstrap sample, which IEEE 754 @@ -106,7 +108,8 @@ end @testset "zerocorr + Base.length + ftype" begin fmzc = models(:sleepstudy)[2] - pbzc = parametricbootstrap(MersenneTwister(42), 5, fmzc, Float16) + pbzc = parametricbootstrap(MersenneTwister(42), 5, fmzc, Float16; + hide_progress=true) @test length(pbzc) == 5 @test Tables.istable(shortestcovint(pbzc)) @test typeof(pbzc) == MixedModelBootstrap{Float16} @@ -116,8 +119,9 @@ end form_zc_not = @formula(rt_trunc ~ 1 + spkr * prec * load + (1 + spkr + prec + load | subj) + zerocorr(1 + spkr + prec + load | item)) - fmzcnot = fit(MixedModel, form_zc_not, dataset(:kb07)) - pbzcnot = parametricbootstrap(MersenneTwister(42), 2, fmzcnot, Float16) + fmzcnot = fit(MixedModel, form_zc_not, dataset(:kb07); progress=false) + pbzcnot = parametricbootstrap(MersenneTwister(42), 2, fmzcnot, Float16; + hide_progress=true) end @testset "Bernoulli simulate! and GLMM boostrap" begin @@ -125,7 +129,7 @@ end # need a model with fast=false to test that we only # copy the optimizer constraints for θ and not β gm0 = fit(MixedModel, first(gfms[:contra]), contra, Bernoulli(), fast=false, progress=false) - bs = parametricbootstrap(StableRNG(42), 100, gm0) + bs = parametricbootstrap(StableRNG(42), 100, gm0; hide_progress=true) # make sure we're not copying @test length(bs.lowerbd) == length(gm0.θ) bsci = filter!(:type => ==("β"), DataFrame(shortestcovint(bs))) @@ -145,7 +149,8 @@ end @test mean(apar.value) ≈ σbar # can't specify dispersion for families without that parameter - @test_throws ArgumentError parametricbootstrap(StableRNG(42), 100, gm0; σ=2) + @test_throws ArgumentError parametricbootstrap(StableRNG(42), 100, gm0; + σ=2, hide_progress=true) @test sum(issingular(bs)) == 0 end end diff --git a/test/predict.jl b/test/predict.jl index e4c0f1317..466828dd2 100644 --- a/test/predict.jl +++ b/test/predict.jl @@ -76,6 +76,32 @@ end @test_throws ArgumentError predict(m, slpm) end + @testset "transformed response" begin + slp1 = subset(slp, :days => ByRow(>(0))) + # this model probably doesn't make much sense, but it has two + # variables on the left hand side in a FunctionTerm + m = fit(MixedModel, @formula(reaction / days ~ 1 + (1|subj)), slp1) + # make sure that we're getting the transformation + @test response(m) ≈ slp1.reaction ./ slp1.days + @test_throws ArgumentError predict(m, slp[:, Not(:reaction)]) + # these currently use approximate equality + # because of floating point, but realistically + # this should be exactly equal in most cases + @test predict(m) ≈ fitted(m) + @test predict(m, slp1) ≈ fitted(m) + + + m = fit(MixedModel, @formula(log10(reaction) ~ 1 + days + (1|subj)), slp1) + # make sure that we're getting the transformation + @test response(m) ≈ log10.(slp1.reaction) + @test_throws ArgumentError predict(m, slp[:, Not(:reaction)]) + # these currently use approximate equality + # because of floating point, but realistically + # this should be exactly equal in most cases + @test predict(m) ≈ fitted(m) + @test predict(m, slp1) ≈ fitted(m) + end + @testset "GLMM" begin contra = dataset(:contra) for fast in [true, false] From 1b3f701293c33fe023b0d2678b6ae9d83d6d75bc Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 20 May 2022 16:05:19 +0000 Subject: [PATCH 04/51] attempt rescaling of poorly scaled problems (#615) * attempt rescaling of poorly scaled problems * fix try-catch * recover better from bad parameter value * rearrange some checks * test for rescaling in first step * white space * note on tests * NEWS + Patch bump --- NEWS.md | 7 +++++++ Project.toml | 2 +- src/linearmixedmodel.jl | 37 ++++++++++++++++++++++++++++--------- test/pls.jl | 16 ++++++++++++++++ 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index 129fa2f19..0cf7ce998 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +MixedModels v4.6.5 Release Notes +======================== +* Attempt recovery when the initial parameter values lead to an invalid covariance matrix by rescaling [#615] +* Return `finitial` when the optimizer drifts into a portion of the parameter space that yields a (numerically) invalid covariance matrix [#615] + + MixedModels v4.6.4 Release Notes ======================== * Support transformed responses in `predict` [#614] @@ -347,3 +353,4 @@ Package dependencies [#604]: https://github.com/JuliaStats/MixedModels.jl/issues/604 [#608]: https://github.com/JuliaStats/MixedModels.jl/issues/608 [#614]: https://github.com/JuliaStats/MixedModels.jl/issues/614 +[#615]: https://github.com/JuliaStats/MixedModels.jl/issues/615 diff --git a/Project.toml b/Project.toml index e9d971566..892c40013 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.6.4" +version = "4.6.5" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index 5655fe99e..92ed27fda 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -428,6 +428,11 @@ function fit!( if optsum.feval > 0 throw(ArgumentError("This model has already been fitted. Use refit!() instead.")) end + if all(==(first(m.y)), m.y) + throw( + ArgumentError("The response is constant and thus model fitting has failed") + ) + end opt = Opt(optsum) optsum.REML = REML prog = ProgressUnknown("Minimizing"; showspeed=true) @@ -436,7 +441,18 @@ function fit!( fitlog = optsum.fitlog function obj(x, g) isempty(g) || throw(ArgumentError("g should be empty for this objective")) - val = objective(updateL!(setθ!(m, x))) + val = try + objective(updateL!(setθ!(m, x))) + catch ex + # This can happen when the optimizer drifts into an area where + # there isn't enough shrinkage. Why finitial? Generally, it will + # be the (near) worst case scenario value, so the optimizer won't + # view it as an optimum. Using Inf messes up the quadratic + # approximation in BOBYQA. + ex isa PosDefException || rethrow() + iter == 0 && rethrow() + m.optsum.finitial + end iszero(rem(iter, thin)) && push!(fitlog, (copy(x), val)) progress && ProgressMeter.next!(prog; showvalues=[(:objective, val)]) iter += 1 @@ -445,14 +461,17 @@ function fit!( NLopt.min_objective!(opt, obj) try optsum.finitial = obj(optsum.initial, T[]) - catch PosDefException - if all(==(first(m.y)), m.y) - throw( - ArgumentError("The response is constant and thus model fitting has failed") - ) - else - rethrow() - end + catch ex + ex isa PosDefException || rethrow() + # give it one more try with a massive change in scaling + @info "Initial step failed, rescaling initial guess and trying again." + @warn """Failure of the initial step is often indicative of a model specification + that is not well supported by the data and/or a poorly scaled model. + """ + optsum.initial ./= + (isempty(m.sqrtwts) ? 1.0 : maximum(m.sqrtwts)^2) * + maximum(response(m)) + optsum.finitial = obj(optsum.initial, T[]) end empty!(fitlog) push!(fitlog, (copy(optsum.initial), optsum.finitial)) diff --git a/test/pls.jl b/test/pls.jl index 18cfe9375..27dadc144 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -605,3 +605,19 @@ end # that we're starting to support a non trivial type hierarchy @test typeof(re) == Vector{AbstractReMat{Float64}} end + +@testset "recovery from misscaling" begin + model = fit(MixedModel, + @formula(reaction ~ 1 + days + zerocorr(1+fulldummy(days)|subj)), + MixedModels.dataset(:sleepstudy); + progress=false, + contrasts=Dict(:days => HelmertCoding(), + :subj => Grouping())) + fm1 = MixedModels.unfit!(deepcopy(model)) + fm1.optsum.initial .*= 1e8 + @test_logs (:info, r"Initial step failed") (:warn, r"Failure of the initial step") fit!(fm1; progress=false) + @test objective(fm1) ≈ objective(model) rtol=0.1 + # it would be great to test the handling of PosDefException after the first iteration + # but this is surprisingly hard to trigger in a reliable way across platforms + # just because of the vagaries of floating point. +end From e2f48bbd0be637ef709e347dc39370d58d168d39 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 1 Jun 2022 17:57:45 +0000 Subject: [PATCH 05/51] fix dependent column test on Apple silicon (#622) --- test/pivot.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/pivot.jl b/test/pivot.jl index ea40fdf19..13c141222 100644 --- a/test/pivot.jl +++ b/test/pivot.jl @@ -32,9 +32,14 @@ end @testset "dependentcolumn" begin mm = modelmatrix(@formula(Y ~ 1 + U + V + Z), simdat) r, pivot = statsrank(mm) - perm = [1,2,4,3] + # V is just mean-centered U + # so either V or U gets pivoted out + # perm1 = [1,2,4,3] # x86-64 OpenBLAS + # perm2 = [1,3,4,2] # Apple M1 @test r == 3 - @test pivot == perm + @test pivot[1] == 1 # intercept remains + @test pivot[3] == 4 # z doesn't get pivoted + @test pivot[4] in [2, 3] end @testset "qr missing cells" begin From 3c192f52d55e16fed4d6076f34f6bbaf731dcf57 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 14 Jun 2022 18:40:25 +0000 Subject: [PATCH 06/51] Create docs-cleanup.yml (#624) --- .github/workflows/docs-cleanup.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/docs-cleanup.yml diff --git a/.github/workflows/docs-cleanup.yml b/.github/workflows/docs-cleanup.yml new file mode 100644 index 000000000..e34565255 --- /dev/null +++ b/.github/workflows/docs-cleanup.yml @@ -0,0 +1,26 @@ +# remove PR previews once they're merged +# +name: Doc Preview Cleanup +on: + pull_request: + types: [closed] +jobs: + doc-preview-cleanup: + runs-on: ubuntu-latest + steps: + - name: Checkout gh-pages branch + uses: actions/checkout@v2 + with: + ref: gh-pages + - name: Delete preview and history + push changes + run: | + if [ -d "previews/PR$PRNUM" ]; then + git config user.name "Documenter.jl" + git config user.email "documenter@juliadocs.github.io" + git rm -rf "previews/PR$PRNUM" + git commit -m "delete preview" + git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree}) + git push --force origin gh-pages-new:gh-pages + fi + env: + PRNUM: ${{ github.event.number }} From 73ad7f14d2cf27f6f06a1e0182e95829167e3419 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Thu, 28 Jul 2022 13:39:19 +0000 Subject: [PATCH 07/51] loosen type restriction on filename for optsum serialization and rename arg (#628) * loosen type restriction on filename for optsum serialization and rename arg * NEWS * oh type ambiguities --- NEWS.md | 5 +++++ Project.toml | 2 +- src/serialization.jl | 12 ++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index 0cf7ce998..e2918c3c1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.7.0 Release Notes +============================== +* Relax type restriction for filename in `saveoptsum` and `restoreoptsum!`. Users can now pass any type with an appropriate `open` method, e.g. `<:AbstractPath`. [#628] + MixedModels v4.6.5 Release Notes ======================== * Attempt recovery when the initial parameter values lead to an invalid covariance matrix by rescaling [#615] @@ -354,3 +358,4 @@ Package dependencies [#608]: https://github.com/JuliaStats/MixedModels.jl/issues/608 [#614]: https://github.com/JuliaStats/MixedModels.jl/issues/614 [#615]: https://github.com/JuliaStats/MixedModels.jl/issues/615 +[#628]: https://github.com/JuliaStats/MixedModels.jl/issues/628 diff --git a/Project.toml b/Project.toml index 892c40013..2fb0fe716 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.6.5" +version = "4.7.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/serialization.jl b/src/serialization.jl index b5065988d..9fb2b25e7 100644 --- a/src/serialization.jl +++ b/src/serialization.jl @@ -1,6 +1,6 @@ """ restoreoptsum!(m::LinearMixedModel, io::IO) - restoreoptsum!(m::LinearMixedModel, fnm::AbstractString) + restoreoptsum!(m::LinearMixedModel, filename) Read, check, and restore the `optsum` field from a JSON stream or filename. """ @@ -40,15 +40,15 @@ function restoreoptsum!(m::LinearMixedModel{T}, io::IO) where {T} return m end -function restoreoptsum!(m::LinearMixedModel, fnm::AbstractString) - open(fnm, "r") do io +function restoreoptsum!(m::LinearMixedModel{T}, filename) where {T} + open(filename, "r") do io restoreoptsum!(m, io) end end """ saveoptsum(io::IO, m::LinearMixedModel) - saveoptsum(fnm::AbstractString, m::LinearMixedModel) + saveoptsum(filename, m::LinearMixedModel) Save `m.optsum` (w/o the `lowerbd` field) in JSON format to an IO stream or a file @@ -56,8 +56,8 @@ The reason for omitting the `lowerbd` field is because it often contains `-Inf` values that are not allowed in JSON. """ saveoptsum(io::IO, m::LinearMixedModel) = JSON3.write(io, m.optsum) -function saveoptsum(fnm::AbstractString, m::LinearMixedModel) - open(fnm, "w") do io +function saveoptsum(filename, m::LinearMixedModel) + open(filename, "w") do io saveoptsum(io, m) end end From 04c27249bc1ed4af22afb36da5d563d60562a4ee Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Sun, 28 Aug 2022 21:26:53 -0500 Subject: [PATCH 08/51] Avoid repeating first objective evaluation in fit! (#637) * Avoid repeating first objective evaluation in fit! * Bump version, add NEWS.md item. * Add a reference to the PR in NEWS.md * Update src/linearmixedmodel.jl for formatting --- NEWS.md | 6 ++++++ Project.toml | 2 +- src/linearmixedmodel.jl | 38 +++++++++++++++++++++----------------- test/pls.jl | 2 +- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/NEWS.md b/NEWS.md index e2918c3c1..9fc21707c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +MixedModels v4.7.1 Release Notes +============================== +* Avoid repeating initial objective evaluation in `fit!` method for `LinearMixedModel` +* Ensure that the number of function evaluations from NLopt corresponds to `length(m.optsum.fitlog) when `isone(thin)`. [#637] + MixedModels v4.7.0 Release Notes ============================== * Relax type restriction for filename in `saveoptsum` and `restoreoptsum!`. Users can now pass any type with an appropriate `open` method, e.g. `<:AbstractPath`. [#628] @@ -359,3 +364,4 @@ Package dependencies [#614]: https://github.com/JuliaStats/MixedModels.jl/issues/614 [#615]: https://github.com/JuliaStats/MixedModels.jl/issues/615 [#628]: https://github.com/JuliaStats/MixedModels.jl/issues/628 +[#637]: https://github.com/JuliaStats/MixedModels.jl/issues/637 diff --git a/Project.toml b/Project.toml index 2fb0fe716..dba9d56fc 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.7.0" +version = "4.7.1" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index 92ed27fda..c9093202f 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -441,37 +441,41 @@ function fit!( fitlog = optsum.fitlog function obj(x, g) isempty(g) || throw(ArgumentError("g should be empty for this objective")) - val = try - objective(updateL!(setθ!(m, x))) - catch ex - # This can happen when the optimizer drifts into an area where - # there isn't enough shrinkage. Why finitial? Generally, it will - # be the (near) worst case scenario value, so the optimizer won't - # view it as an optimum. Using Inf messes up the quadratic - # approximation in BOBYQA. - ex isa PosDefException || rethrow() - iter == 0 && rethrow() - m.optsum.finitial + iter += 1 + val = if isone(iter) && x == optsum.initial + optsum.finitial + else + try + objective(updateL!(setθ!(m, x))) + catch ex + # This can happen when the optimizer drifts into an area where + # there isn't enough shrinkage. Why finitial? Generally, it will + # be the (near) worst case scenario value, so the optimizer won't + # view it as an optimum. Using Inf messes up the quadratic + # approximation in BOBYQA. + ex isa PosDefException || rethrow() + optsum.finitial + end end - iszero(rem(iter, thin)) && push!(fitlog, (copy(x), val)) progress && ProgressMeter.next!(prog; showvalues=[(:objective, val)]) - iter += 1 + !isone(iter) && iszero(rem(iter, thin)) && push!(fitlog, (copy(x), val)) return val end NLopt.min_objective!(opt, obj) try - optsum.finitial = obj(optsum.initial, T[]) + # use explicit evaluation w/o calling opt to avoid confusing iteration count + optsum.finitial = objective(updateL!(setθ!(m, optsum.initial))) catch ex ex isa PosDefException || rethrow() # give it one more try with a massive change in scaling - @info "Initial step failed, rescaling initial guess and trying again." - @warn """Failure of the initial step is often indicative of a model specification + @info "Initial objective evaluation failed, rescaling initial guess and trying again." + @warn """Failure of the initial evaluation is often indicative of a model specification that is not well supported by the data and/or a poorly scaled model. """ optsum.initial ./= (isempty(m.sqrtwts) ? 1.0 : maximum(m.sqrtwts)^2) * maximum(response(m)) - optsum.finitial = obj(optsum.initial, T[]) + optsum.finitial = objective(updateL!(setθ!(m, optsum.initial))) end empty!(fitlog) push!(fitlog, (copy(optsum.initial), optsum.finitial)) diff --git a/test/pls.jl b/test/pls.jl index 27dadc144..b0f7746d5 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -615,7 +615,7 @@ end :subj => Grouping())) fm1 = MixedModels.unfit!(deepcopy(model)) fm1.optsum.initial .*= 1e8 - @test_logs (:info, r"Initial step failed") (:warn, r"Failure of the initial step") fit!(fm1; progress=false) + @test_logs (:info, r"Initial objective evaluation failed") (:warn, r"Failure of the initial ") fit!(fm1; progress=false) @test objective(fm1) ≈ objective(model) rtol=0.1 # it would be great to test the handling of PosDefException after the first iteration # but this is surprisingly hard to trigger in a reliable way across platforms From f11e0d7ca689efe70ddccc115115e05caf77cc4c Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Thu, 1 Sep 2022 08:45:19 -0500 Subject: [PATCH 09/51] Extend rankUpdate! method to allow for upper tri (#636) * Extend rankUpdate! method to allow for upper tri * rankUpdate! upper-sym from sparse. * add more checks for one-based indexing and more `PosDefException` checks. * add `@inbounds` qualifiers Co-authored-by: Phillip Alday --- src/MixedModels.jl | 2 +- src/linalg/cholUnblocked.jl | 7 ++- src/linalg/logdet.jl | 14 ++--- src/linalg/rankUpdate.jl | 117 ++++++++++++++++++++++-------------- test/linalg.jl | 3 + 5 files changed, 87 insertions(+), 56 deletions(-) diff --git a/src/MixedModels.jl b/src/MixedModels.jl index 17db28ec5..f9670dd26 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -21,7 +21,7 @@ using StructTypes using Tables using LinearAlgebra: BlasFloat, BlasReal, HermOrSym, PosDefException, copytri! -using Base: Ryu +using Base: Ryu, require_one_based_indexing using GLM: Link, canonicallink, linkfun, linkinv using StatsModels: TableRegressionModel diff --git a/src/linalg/cholUnblocked.jl b/src/linalg/cholUnblocked.jl index 229a9914f..b430e324a 100644 --- a/src/linalg/cholUnblocked.jl +++ b/src/linalg/cholUnblocked.jl @@ -9,7 +9,12 @@ because these are part of the inner calculations in a blocked Cholesky factoriza function cholUnblocked! end function cholUnblocked!(D::Diagonal{T}, ::Type{Val{:L}}) where {T<:AbstractFloat} - map!(sqrt, D.diag, D.diag) + Ddiag = D.diag + @inbounds for i in eachindex(Ddiag) + (ddi = Ddiag[i]) ≤ zero(T) && throw(PosDefException(i)) + Ddiag[i] = sqrt(ddi) + end + return D end diff --git a/src/linalg/logdet.jl b/src/linalg/logdet.jl index d1e246c5e..e4e084a72 100644 --- a/src/linalg/logdet.jl +++ b/src/linalg/logdet.jl @@ -12,7 +12,7 @@ function LD(d::UniformBlockDiagonal{T}) where {T} return sum(log, dat[j, j, k] for j in axes(dat, 2), k in axes(dat, 3)) end -LD(d::DenseMatrix{T}) where {T} = sum(log, d[k] for k in diagind(d)) +LD(d::DenseMatrix{T}) where {T} = @inbounds sum(log, d[k] for k in diagind(d)) """ logdet(m::LinearMixedModel) @@ -25,15 +25,11 @@ lower Cholesky factor. """ function LinearAlgebra.logdet(m::LinearMixedModel{T}) where {T} L = m.L - nre = m.dims.nretrms - s = LD(first(L)) - for j in 2:nre - s += LD(L[kp1choose2(j)]) - end + @inbounds s = sum(j -> LD(L[kp1choose2(j)]), axes(m.reterms, 1)) if m.optsum.REML lastL = last(L) - s += LD(lastL) # this adds the log of sqrtpwrss - s -= log(last(lastL)) + s += LD(lastL) # this includes the log of sqrtpwrss + s -= log(last(lastL)) # so we need to subtract it from the sum end - return s + s + return s + s # multiply by 2 b/c the desired det is of the symmetric mat, not the factor end diff --git a/src/linalg/rankUpdate.jl b/src/linalg/rankUpdate.jl index f73e2d879..6ee6e78fc 100644 --- a/src/linalg/rankUpdate.jl +++ b/src/linalg/rankUpdate.jl @@ -3,7 +3,7 @@ rankUpdate!(C, A, α) rankUpdate!(C, A, α, β) -A rank-k update, C := β*C + α*A'A, of a Hermitian (Symmetric) matrix. +A rank-k update, C := α*A'A + β*C, of a Hermitian (Symmetric) matrix. `α` and `β` both default to 1.0. When `α` is -1.0 this is a downdate operation. The name `rankUpdate!` is borrowed from [https://github.com/andreasnoack/LinearAlgebra.jl] @@ -17,8 +17,9 @@ function rankUpdate!(C::AbstractMatrix, a::AbstractArray, α, β) end function rankUpdate!(C::HermOrSym{T,S}, a::StridedVector{T}, α, β) where {T,S} - isone(β) || throw(ArgumentError("isone(β) is false")) - BLAS.syr!(C.uplo, T(α), a, C.data) + Cd = C.data + isone(β) || rmul!(C.uplo == 'L' ? LowerTriangular(Cd) : UpperTriangular(Cd), β) + BLAS.syr!(C.uplo, T(α), a, Cd) return C ## to ensure that the return value is HermOrSym end @@ -27,21 +28,58 @@ function rankUpdate!(C::HermOrSym{T,S}, A::StridedMatrix{T}, α, β) where {T,S} return C end +""" + _columndot(rv, nz, rngi, rngj) + +Return the dot product of two columns, with `nzrange`s `rngi` and `rngj`, of a sparse matrix defined by rowvals `rv` and nonzeros `nz` +""" +function _columndot(rv, nz, rngi, rngj) + accum = zero(eltype(nz)) + (isempty(rngi) || isempty(rngj)) && return accum + ni, nj = length(rngi), length(rngj) + i = j = 1 + while i ≤ ni && j ≤ nj + @inbounds ri, rj = rv[rngi[i]], rv[rngj[j]] + if ri == rj + @inbounds accum += nz[rngi[i]] * nz[rngj[j]] + i += 1 + j += 1 + elseif ri < rj + i += 1 + else + j += 1 + end + end + return accum +end + function rankUpdate!(C::HermOrSym{T,S}, A::SparseMatrixCSC{T}, α, β) where {T,S} - A.m == size(C, 2) || throw(DimensionMismatch()) - C.uplo == 'L' || throw(ArgumentError("C.uplo must be 'L'")) - Cd, rv, nz = C.data, rowvals(A), nonzeros(A) - isone(β) || rmul!(LowerTriangular(Cd), β) - @inbounds for jj in 1:(A.n) - rangejj = nzrange(A, jj) - lenrngjj = length(rangejj) - for (k, j) in enumerate(rangejj) - anzj = α * nz[j] - colj = view(Cd, :, rv[j]) - for i in k:lenrngjj - kk = rangejj[i] - colj[rv[kk]] += nz[kk] * anzj + require_one_based_indexing(C, A) + m, n = size(A) + Cd, rv, nz = C.data, A.rowval, A.nzval + lower = C.uplo == 'L' + (lower ? m : n) == size(C, 2) || throw(DimensionMismatch()) + isone(β) || rmul!(lower ? LowerTriangular(Cd) : UpperTriangular(Cd), β) + if lower + @inbounds for jj in axes(A, 2) + rangejj = nzrange(A, jj) + lenrngjj = length(rangejj) + for (k, j) in enumerate(rangejj) + anzj = α * nz[j] + rvj = rv[j] + for i in k:lenrngjj + kk = rangejj[i] + Cd[rv[kk], rvj] += nz[kk] * anzj + end + end + end + else + @inbounds for j in axes(C, 2) + rngj = nzrange(A, j) + for i in 1:(j - 1) + Cd[i, j] += α * _columndot(rv, nz, nzrange(A, i), rngj) end + Cd[j, j] += α * sum(i -> abs2(nz[i]), rngj) end end return C @@ -55,11 +93,12 @@ function rankUpdate!( C::HermOrSym{T,Diagonal{T,Vector{T}}}, A::StridedMatrix{T}, α, β ) where {T,S} Cdiag = C.data.diag - @. Cdiag = β * Cdiag + require_one_based_indexing(Cdiag, A) + length(Cdiag) == size(A, 1) || throw(DimensionMismatch()) + isone(β) || rmul!(Cdiag, β) - for i in 1:length(Cdiag) - Arow = view(A, i, :) - Cdiag[i] = Cdiag[i] + α * Arow'Arow + @inbounds for i in eachindex(Cdiag) + Cdiag[i] += α * sum(abs2, view(A, i, :)) end return C @@ -69,18 +108,19 @@ function rankUpdate!( C::HermOrSym{T,UniformBlockDiagonal{T}}, A::StridedMatrix{T}, α, β ) where {T,S} Cdat = C.data.data - isone(β) || (Cdat .*= β) + require_one_based_indexing(Cdat, A) + isone(β) || rmul!(Cdat, β) blksize = size(Cdat, 1) for k in axes(Cdat, 3) ioffset = (k - 1) * blksize joffset = (k - 1) * blksize - for i in 1:blksize, j in 1:i + for i in axes(Cdat, 1), j in 1:i iind = ioffset + i jind = joffset + j AtAij = 0 for idx in axes(A, 2) - # because the second is actually A', we swap index orders + # because the second multiplicant is from A', swap index order AtAij += A[iind, idx] * A[jind, idx] end Cdat[i, j, k] += α * AtAij @@ -94,13 +134,16 @@ function rankUpdate!( C::HermOrSym{T,Diagonal{T,Vector{T}}}, A::SparseMatrixCSC{T}, α, β ) where {T} dd = C.data.diag + require_one_based_indexing(dd, A) A.m == length(dd) || throw(DimensionMismatch()) isone(β) || rmul!(dd, β) all(isone.(diff(A.colptr))) || throw(ArgumentError("Columns of A must have exactly 1 nonzero")) + for (r, nz) in zip(rowvals(A), nonzeros(A)) dd[r] += α * abs2(nz) end + return C end @@ -113,37 +156,21 @@ function rankUpdate!( ) where {T,S} Ac = A.cscmat cp = Ac.colptr - all(diff(cp) .== S) || + all(==(S), diff(cp)) || throw(ArgumentError("Columns of A must have exactly $S nonzeros")) Cdat = C.data.data + require_one_based_indexing(Ac, Cdat) + j, k, l = size(Cdat) S == j == k && div(Ac.m, S) == l || throw(DimensionMismatch("div(A.cscmat.m, S) ≠ size(C.data.data, 3)")) nz = Ac.nzval rv = Ac.rowval - for j in 1:(Ac.n) + + @inbounds for j in axes(Ac, 2) nzr = nzrange(Ac, j) BLAS.syr!('L', α, view(nz, nzr), view(Cdat, :, :, div(rv[last(nzr)], S))) end - return C -end -#= I don't think Diagonal A can occur after the terms with the same grouping factor have been amalgamated. -function rankUpdate!(C::HermOrSym{T,Diagonal{T}}, A::Diagonal{T}, α, β) where {T} - Cdiag = C.data.diag - if length(Cdiag) ≠ length(A.diag) - throw(DimensionMismatch("length(C.data.diag) ≠ length(A.diag)")) - end - - Cdiag .= β .* Cdiag .+ α .* abs2.(A.diag) - C -end -function rankUpdate!(C::HermOrSym{T,Matrix{T}}, A::Diagonal{T}, α, β) where {T} - Adiag, Cdata = A.diag, C.data - length(Adiag) == size(C, 2) || throw(DimensionMismatch()) - for (i, a) in zip(diagind(Cdata), Adiag) - Cdata[i] = β * Cdata[i] + α * abs2(a) - end - C + return C end -=# diff --git a/test/linalg.jl b/test/linalg.jl index b011c2d3d..32e69a8f6 100644 --- a/test/linalg.jl +++ b/test/linalg.jl @@ -58,6 +58,9 @@ end # in < 1.6, typeof(x) == Array{Int64, 2} err = ErrorException("We haven't implemented a method for $(typeof(x)), $(typeof(x)). Please file an issue on GitHub."); @test_throws ErrorException rankUpdate!(x, x, 1, 1); + L21 = sprand(MersenneTwister(42), 100, 1000, 0.05) + L22L = rankUpdate!(Symmetric(zeros(100, 100), :L), L21, 1.0, 1.0) + @test L22L ≈ rankUpdate!(Symmetric(zeros(100, 100), :U), sparse(transpose(L21)), 1.0, 1.0) end #= I don't see this testset as meaningful b/c diagonal A does not occur after amalgamation of ReMat's for the same grouping factor - D.B. From 70e3dc8fb17a800f88068082c18d81758c4e5ba7 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 4 Oct 2022 21:53:30 +0000 Subject: [PATCH 10/51] improve "API" docs (#645) * move to StatsAPI, ditch import for using * fix some docs * methods we've implemented and/or exported * slight rearrangement * tweaks * drop unused type parameter --- Project.toml | 2 + docs/Project.toml | 2 + docs/make.jl | 3 +- docs/src/api.md | 63 +++++++++++++++++++++++++++++- docs/src/constructors.md | 8 ++-- src/MixedModels.jl | 15 +++---- src/Xymat.jl | 10 ++--- src/generalizedlinearmixedmodel.jl | 24 ++++++------ src/linalg/rankUpdate.jl | 4 +- src/linearmixedmodel.jl | 37 +++++++++++------- src/mixedmodel.jl | 46 +++++++++++----------- src/predict.jl | 10 ++--- src/remat.jl | 19 ++++----- 13 files changed, 156 insertions(+), 87 deletions(-) diff --git a/Project.toml b/Project.toml index dba9d56fc..3a8539013 100644 --- a/Project.toml +++ b/Project.toml @@ -19,6 +19,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +StatsAPI = "82ae8749-77ed-4fe6-ae5f-f523153014b0" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d" @@ -36,6 +37,7 @@ NLopt = "0.5, 0.6" PooledArrays = "0.5, 1" ProgressMeter = "1.7" StaticArrays = "0.11, 0.12, 1" +StatsAPI = "1.5" StatsBase = "0.31, 0.32, 0.33" StatsFuns = "0.8, 0.9, 1" StatsModels = "0.6.23" diff --git a/docs/Project.toml b/docs/Project.toml index a324dcd51..e1581a96f 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -7,6 +7,7 @@ FreqTables = "da1fdf0e-e0ff-5433-a45f-9bb5ff651cb1" Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004" MixedModels = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +StatsAPI = "82ae8749-77ed-4fe6-ae5f-f523153014b0" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d" @@ -16,4 +17,5 @@ DataFrames = "1" Documenter = "0.26,0.27" FreqTables = "0.4" Gadfly = "1" +StatsAPI = "1.5" StatsBase = "0.33" diff --git a/docs/make.jl b/docs/make.jl index da9380635..c9cb034ab 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,6 +1,7 @@ using Documenter -using StatsBase using MixedModels +using StatsAPI +using StatsBase makedocs(; sitename="MixedModels", diff --git a/docs/src/api.md b/docs/src/api.md index 8336d3e75..bdf8ceb8f 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -1,6 +1,6 @@ # API -In addition to its own functionality, MixedModels.jl also implements extensive support for the `StatsBase.StatisticalModel` and `StatsBase.RegressionModel` API. +In addition to its own functionality, MixedModels.jl also implements extensive support for the [`StatsAPI.StatisticalModel`](https://github.com/JuliaStats/StatsAPI.jl/blob/main/src/statisticalmodel.jl) and [`StatsAPI.RegressionModel`](https://github.com/JuliaStats/StatsAPI.jl/blob/main/src/regressionmodel.jl) API. ## Types @@ -16,6 +16,67 @@ Private = false Order = [:function] ``` +## Methods from `StatsAPI.jl`, `StatsBase.jl`, `StatsModels.jl` and `GLM.jl` + +```julia +aic +aicc +bic +coef +coefnames +coeftable +deviance +dispersion +dispersion_parameter +dof +dof_residual +fit +fit! +fitted +formula +isfitted +islinear +leverage +loglikelihood +meanresponse +modelmatrix +model_response +nobs +predict +residuals +response +responsename +StatsModels.lrtest # not exported +std +stderror +vcov +weights +``` + +### MixedModels.jl "alternatives" and extensions to StatsAPI and GLM functions + +The following are MixedModels.jl-specific functions and not simply methods for functions defined in StatsAPI and GLM.jl. + +```julia +coefpvalues +condVar +condVarTables +fitted! +fixef +fixefnames +likelihoodratiotest # not exported +pwrss +ranef +raneftables +refit! +shortestcovint +sdest +simulate +simulate! +stderrror! +varest +``` + ## Non-Exported Functions Note that unless discussed elsewhere in the online documentation, non-exported functions should be considered implementation details. diff --git a/docs/src/constructors.md b/docs/src/constructors.md index 507e7c808..4f34a1832 100644 --- a/docs/src/constructors.md +++ b/docs/src/constructors.md @@ -262,18 +262,18 @@ sort(deviances) # Extractor functions -`LinearMixedModel` and `GeneralizedLinearMixedModel` are subtypes of `StatsBase.RegressionModel` which, in turn, is a subtype of `StatsBase.StatisticalModel`. +`LinearMixedModel` and `GeneralizedLinearMixedModel` are subtypes of `StatsAPI.RegressionModel` which, in turn, is a subtype of `StatsBase.StatisticalModel`. Many of the generic extractors defined in the `StatsBase` package have methods for these models. ## Model-fit statistics The statistics describing the quality of the model fit include ```@docs -loglikelihood(::StatisticalModel) +loglikelihood aic bic -dof(::StatisticalModel) -nobs(::StatisticalModel) +dof +nobs ``` ```@example Main loglikelihood(fm1) diff --git a/src/MixedModels.jl b/src/MixedModels.jl index f9670dd26..11fc01e78 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -15,6 +15,7 @@ using ProgressMeter using SparseArrays using StaticArrays using Statistics +using StatsAPI using StatsBase using StatsModels using StructTypes @@ -22,17 +23,12 @@ using Tables using LinearAlgebra: BlasFloat, BlasReal, HermOrSym, PosDefException, copytri! using Base: Ryu, require_one_based_indexing -using GLM: Link, canonicallink, linkfun, linkinv +using DataAPI: levels, refpool, refarray, refvalue +using GLM: Link, canonicallink, linkfun, linkinv, dispersion, dispersion_parameter +using NLopt: Opt using StatsModels: TableRegressionModel - using StatsFuns: log2π, normccdf -import Base: * -import DataAPI: levels, refpool, refarray, refvalue -import GLM: dispersion, dispersion_parameter -import NLopt: Opt -import StatsBase: fit, fit! - export @formula, AbstractReMat, Bernoulli, @@ -130,14 +126,13 @@ export @formula, sparseL, std, stderror, + stderror!, updateL!, varest, vcov, weights, zerocorr -import Base: ==, * - """ MixedModel diff --git a/src/Xymat.jl b/src/Xymat.jl index f95eea7bb..e1bf8deca 100644 --- a/src/Xymat.jl +++ b/src/Xymat.jl @@ -3,7 +3,7 @@ Term with an explicit, constant matrix representation -Typically, an `FeTerm` represents the model matrix for the fixed effects. +Typically, an `FeTerm` represents the model matrix for the fixed effects. !!! note `FeTerm` is not the same as [`FeMat`](@ref)! @@ -23,10 +23,10 @@ end """ FeTerm(X::AbstractMatrix, cnms) - + Convenience constructor for [`FeTerm`](@ref) that computes the rank and pivot with unit weights. -See the vignette "[Rank deficiency in mixed-effects models](@ref)" for more information on the +See the vignette "[Rank deficiency in mixed-effects models](@ref)" for more information on the computation of the rank and pivot. """ function FeTerm(X::AbstractMatrix{T}, cnms) where {T} @@ -45,7 +45,7 @@ end """ FeTerm(X::SparseMatrixCSC, cnms) - + Convenience constructor for a sparse [`FeTerm`](@ref) assuming full rank, identity pivot and unit weights. Note: automatic rank deficiency handling may be added to this method in the future, as discused in @@ -110,7 +110,7 @@ Base.getindex(A::FeMat, i, j) = getindex(A.xy, i, j) Base.length(A::FeMat) = length(A.xy) -function *(adjA::Adjoint{T,<:FeMat{T}}, B::FeMat{T}) where {T} +function Base.:(*)(adjA::Adjoint{T,<:FeMat{T}}, B::FeMat{T}) where {T} return adjoint(adjA.parent.wtxy) * B.wtxy end diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index 87048b023..fce0ffc5b 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -53,12 +53,12 @@ struct GeneralizedLinearMixedModel{T<:AbstractFloat,D<:Distribution} <: MixedMod mult::Vector{T} end -function StatsBase.coef(m::GeneralizedLinearMixedModel{T}) where {T} +function StatsAPI.coef(m::GeneralizedLinearMixedModel{T}) where {T} piv = m.LMM.feterm.piv return invpermute!(copyto!(fill(T(-0.0), length(piv)), m.β), piv) end -function StatsBase.coeftable(m::GeneralizedLinearMixedModel) +function StatsAPI.coeftable(m::GeneralizedLinearMixedModel) co = coef(m) se = stderror(m) z = co ./ se @@ -82,7 +82,7 @@ If the distribution `D` does not have a scale parameter the Laplace approximatio is the squared length of the conditional modes, ``u``, plus the determinant of ``Λ'Z'WZΛ + I``, plus the sum of the squared deviance residuals. """ -function StatsBase.deviance(m::GeneralizedLinearMixedModel{T}, nAGQ=1) where {T} +function StatsAPI.deviance(m::GeneralizedLinearMixedModel{T}, nAGQ=1) where {T} nAGQ == 1 && return T(sum(m.resp.devresid) + logdet(m) + sum(u -> sum(abs2, u), m.u)) u = vec(first(m.u)) u₀ = vec(first(m.u₀)) @@ -109,7 +109,7 @@ function StatsBase.deviance(m::GeneralizedLinearMixedModel{T}, nAGQ=1) where {T} return sum(devc0) - 2 * (sum(log, mult) + sum(log, sd)) end -StatsBase.deviance(m::GeneralizedLinearMixedModel) = deviance(m, m.optsum.nAGQ) +StatsAPI.deviance(m::GeneralizedLinearMixedModel) = deviance(m, m.optsum.nAGQ) fixef(m::GeneralizedLinearMixedModel) = m.β @@ -161,7 +161,7 @@ GLM.dispersion_parameter(m::GeneralizedLinearMixedModel) = dispersion_parameter( Distributions.Distribution(m::GeneralizedLinearMixedModel{T,D}) where {T,D} = D -function fit( +function StatsAPI.fit( ::Type{GeneralizedLinearMixedModel}, f::FormulaTerm, tbl, @@ -172,7 +172,7 @@ function fit( return fit(GeneralizedLinearMixedModel, f, columntable(tbl), d, l; kwargs...) end -function fit( +function StatsAPI.fit( ::Type{GeneralizedLinearMixedModel}, f::FormulaTerm, tbl::Tables.ColumnTable, @@ -188,7 +188,7 @@ function fit( ) end -function fit( +function StatsAPI.fit( ::Type{MixedModel}, f::FormulaTerm, tbl, @@ -238,7 +238,7 @@ default is the empty set. The `init_from_lmm` functionality is experimental and may change or be removed entirely without being considered a breaking change. """ -function fit!( +function StatsAPI.fit!( m::GeneralizedLinearMixedModel{T}; verbose::Bool=false, fast::Bool=false, @@ -324,7 +324,7 @@ function fit!( return m end -StatsBase.fitted(m::GeneralizedLinearMixedModel) = m.resp.mu +StatsAPI.fitted(m::GeneralizedLinearMixedModel) = m.resp.mu function GeneralizedLinearMixedModel( f::FormulaTerm, @@ -465,11 +465,11 @@ end getθ(m::GeneralizedLinearMixedModel) = copy(m.θ) getθ!(v::AbstractVector{T}, m::GeneralizedLinearMixedModel{T}) where {T} = copyto!(v, m.θ) -StatsBase.islinear(m::GeneralizedLinearMixedModel) = isa(GLM.Link, GLM.IdentityLink) +StatsAPI.islinear(m::GeneralizedLinearMixedModel) = isa(GLM.Link, GLM.IdentityLink) GLM.Link(m::GeneralizedLinearMixedModel) = GLM.Link(m.resp) -function StatsBase.loglikelihood(m::GeneralizedLinearMixedModel{T}) where {T} +function StatsAPI.loglikelihood(m::GeneralizedLinearMixedModel{T}) where {T} accum = zero(T) # adapted from GLM.jl # note the use of loglik_obs to handle the different parameterizations @@ -776,7 +776,7 @@ function varest(m::GeneralizedLinearMixedModel{T}) where {T} return dispersion_parameter(m) ? dispersion(m, true) : missing end -function StatsBase.weights(m::GeneralizedLinearMixedModel{T}) where {T} +function StatsAPI.weights(m::GeneralizedLinearMixedModel{T}) where {T} wts = m.wt return isempty(wts) ? ones(T, nobs(m)) : wts end diff --git a/src/linalg/rankUpdate.jl b/src/linalg/rankUpdate.jl index 6ee6e78fc..e12662323 100644 --- a/src/linalg/rankUpdate.jl +++ b/src/linalg/rankUpdate.jl @@ -91,7 +91,7 @@ end function rankUpdate!( C::HermOrSym{T,Diagonal{T,Vector{T}}}, A::StridedMatrix{T}, α, β -) where {T,S} +) where {T} Cdiag = C.data.diag require_one_based_indexing(Cdiag, A) length(Cdiag) == size(A, 1) || throw(DimensionMismatch()) @@ -106,7 +106,7 @@ end function rankUpdate!( C::HermOrSym{T,UniformBlockDiagonal{T}}, A::StridedMatrix{T}, α, β -) where {T,S} +) where {T} Cdat = C.data.data require_one_based_indexing(Cdat, A) isone(β) || rmul!(Cdat, β) diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index c9093202f..418ed6b90 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -174,7 +174,7 @@ function LinearMixedModel( ) end -function fit( +function StatsAPI.fit( ::Type{LinearMixedModel}, f::FormulaTerm, tbl; @@ -198,7 +198,7 @@ function fit( ) end -function fit( +function StatsAPI.fit( ::Type{LinearMixedModel}, f::FormulaTerm, tbl::Tables.ColumnTable; @@ -220,7 +220,7 @@ function _offseterr() ) end -function fit( +function StatsAPI.fit( ::Type{MixedModel}, f::FormulaTerm, tbl; @@ -239,7 +239,7 @@ function fit( end end -function fit( +function StatsAPI.fit( ::Type{MixedModel}, f::FormulaTerm, tbl, @@ -265,19 +265,19 @@ function fit( end end -function StatsBase.coef(m::LinearMixedModel{T}) where {T} +function StatsAPI.coef(m::LinearMixedModel{T}) where {T} piv = m.feterm.piv return invpermute!(fixef!(similar(piv, T), m), piv) end βs(m::LinearMixedModel) = NamedTuple{(Symbol.(coefnames(m))...,)}(coef(m)) -function StatsBase.coefnames(m::LinearMixedModel) +function StatsAPI.coefnames(m::LinearMixedModel) Xtrm = m.feterm return invpermute!(copy(Xtrm.cnames), Xtrm.piv) end -function StatsBase.coeftable(m::LinearMixedModel) +function StatsAPI.coeftable(m::LinearMixedModel) co = coef(m) se = stderror!(similar(co), m) z = co ./ se @@ -385,7 +385,7 @@ function createAL(reterms::Vector{AbstractReMat{T}}, Xy::FeMat{T}) where {T} return A, L end -StatsBase.deviance(m::LinearMixedModel) = objective(m) +StatsAPI.deviance(m::LinearMixedModel) = objective(m) GLM.dispersion(m::LinearMixedModel, sqr::Bool=false) = sqr ? varest(m) : sdest(m) @@ -416,7 +416,7 @@ objective, if the optimization takes more than one second or so. At every `thin`th iteration is recorded in `fitlog`, optimization progress is saved in `m.optsum.fitlog`. """ -function fit!( +function StatsAPI.fit!( m::LinearMixedModel{T}; progress::Bool=true, REML::Bool=false, @@ -510,6 +510,13 @@ function fit!( return m end +""" + fitted!(v::AbstractArray{T}, m::LinearMixedModel{T}) + +Overwrite `v` with the fitted values from `m`. + +See also `fitted`. +""" function fitted!(v::AbstractArray{T}, m::LinearMixedModel{T}) where {T} ## FIXME: Create and use `effects(m) -> β, b` w/o calculating β twice Xtrm = m.feterm @@ -520,7 +527,7 @@ function fitted!(v::AbstractArray{T}, m::LinearMixedModel{T}) where {T} return v end -StatsBase.fitted(m::LinearMixedModel{T}) where {T} = fitted!(Vector{T}(undef, nobs(m)), m) +StatsAPI.fitted(m::LinearMixedModel{T}) where {T} = fitted!(Vector{T}(undef, nobs(m)), m) """ fixef!(v::Vector{T}, m::MixedModel{T}) @@ -648,7 +655,7 @@ function Base.getproperty(m::LinearMixedModel{T}, s::Symbol) where {T} end end -StatsBase.islinear(m::LinearMixedModel) = true +StatsAPI.islinear(m::LinearMixedModel) = true """ _3blockL(::LinearMixedModel) @@ -699,7 +706,7 @@ for the model in the sense that this sum is the dimension of the span of columns of the model matrix. With a bit of hand waving a similar argument could be made for linear mixed-effects models. The hat matrix is of the form ``[ZΛ X][L L']⁻¹[ZΛ X]'``. """ -function StatsBase.leverage(m::LinearMixedModel{T}) where {T} +function StatsAPI.leverage(m::LinearMixedModel{T}) where {T} # To obtain the diagonal elements solve L⁻¹[ZΛ X]'eⱼ # where eⱼ is the j'th basis vector in Rⁿ and evaluate the squared length of the solution. # The fact that the [1,1] block of L is always UniformBlockDiagonal @@ -740,7 +747,7 @@ function StatsBase.leverage(m::LinearMixedModel{T}) where {T} return value end -function StatsBase.loglikelihood(m::LinearMixedModel) +function StatsAPI.loglikelihood(m::LinearMixedModel) if m.optsum.REML throw(ArgumentError("loglikelihood not available for models fit by REML")) end @@ -1149,7 +1156,7 @@ function stderror!(v::AbstractVector{Tv}, m::LinearMixedModel{T}) where {Tv,T} return v end -function StatsBase.stderror(m::LinearMixedModel{T}) where {T} +function StatsAPI.stderror(m::LinearMixedModel{T}) where {T} return stderror!(similar(m.feterm.piv, T), m) end @@ -1243,7 +1250,7 @@ function varest(m::LinearMixedModel) return isnothing(m.optsum.sigma) ? pwrss(m) / ssqdenom(m) : m.optsum.sigma end -function StatsBase.weights(m::LinearMixedModel) +function StatsAPI.weights(m::LinearMixedModel) rtwts = m.sqrtwts return isempty(rtwts) ? ones(eltype(rtwts), nobs(m)) : abs2.(rtwts) end diff --git a/src/mixedmodel.jl b/src/mixedmodel.jl index ba4e010a1..45812ad3f 100644 --- a/src/mixedmodel.jl +++ b/src/mixedmodel.jl @@ -14,7 +14,7 @@ function MixedModel( return LinearMixedModel(f, tbl; kwargs...) end -function StatsBase.coefnames(m::MixedModel) +function StatsAPI.coefnames(m::MixedModel) Xtrm = m.feterm return invpermute!(copy(Xtrm.cnames), Xtrm.piv) end @@ -26,7 +26,7 @@ Return a vector of condition numbers of the λ matrices for the random-effects t """ LinearAlgebra.cond(m::MixedModel) = cond.(m.λ) -function StatsBase.dof(m::MixedModel) +function StatsAPI.dof(m::MixedModel) return m.feterm.rank + length(m.parmap) + dispersion_parameter(m) end @@ -36,21 +36,21 @@ end Return the residual degrees of freedom of the model. !!! note - The residual degrees of freedom for mixed-effects models is not clearly defined due to partial pooling. - The classical `nobs(m) - dof(m)` fails to capture the extra freedom granted by the random effects, but - `nobs(m) - nranef(m)` would overestimate the freedom granted by the random effects. `nobs(m) - sum(leverage(m))` - provides a nice balance based on the relative influence of each observation, but is computationally - expensive for large models. This problem is also fundamentally related to [long-standing debates](https://bbolker.github.io/mixedmodels-misc/glmmFAQ.html#why-doesnt-lme4-display-denominator-degrees-of-freedomp-values-what-other-options-do-i-have) - about the appropriate treatment of the denominator degrees of freedom for ``F``-tests. - In the future, MixedModels.jl may provide additional methods allowing the user to choose the computation - to use. + The residual degrees of freedom for mixed-effects models is not clearly defined due to partial pooling. + The classical `nobs(m) - dof(m)` fails to capture the extra freedom granted by the random effects, but + `nobs(m) - nranef(m)` would overestimate the freedom granted by the random effects. `nobs(m) - sum(leverage(m))` + provides a nice balance based on the relative influence of each observation, but is computationally + expensive for large models. This problem is also fundamentally related to [long-standing debates](https://bbolker.github.io/mixedmodels-misc/glmmFAQ.html#why-doesnt-lme4-display-denominator-degrees-of-freedomp-values-what-other-options-do-i-have) + about the appropriate treatment of the denominator degrees of freedom for ``F``-tests. + In the future, MixedModels.jl may provide additional methods allowing the user to choose the computation + to use. !!! warning - Currently, the residual degrees of freedom is computed as `nobs(m) - dof(m)`, but this may change in - the future without being considered a breaking change because there is no canonical definition of the - residual degrees of freedom in a mixed-effects model. + Currently, the residual degrees of freedom is computed as `nobs(m) - dof(m)`, but this may change in + the future without being considered a breaking change because there is no canonical definition of the + residual degrees of freedom in a mixed-effects model. """ -function StatsBase.dof_residual(m::MixedModel) +function StatsAPI.dof_residual(m::MixedModel) # a better estimate might be nobs(m) - sum(leverage(m)) # this version subtracts the number of variance parameters which isn't really a dimensional # and doesn't even agree with the definition for linear models @@ -72,9 +72,9 @@ issingular(m::MixedModel, θ=m.θ) = any(lowerbd(m) .== θ) issingular(m::GeneralizedLinearMixedModel, θ=m.optsum.final) = any(lowerbd(m) .== θ) # FIXME: better to base this on m.optsum.returnvalue -StatsBase.isfitted(m::MixedModel) = m.optsum.feval > 0 +StatsAPI.isfitted(m::MixedModel) = m.optsum.feval > 0 -StatsBase.meanresponse(m::MixedModel) = mean(m.y) +StatsAPI.meanresponse(m::MixedModel) = mean(m.y) """ modelmatrix(m::MixedModel) @@ -84,11 +84,11 @@ Returns the model matrix `X` for the fixed-effects parameters, as returned by [` This is always the full model matrix in the original column order and from a field in the model struct. It should be copied if it is to be modified. """ -StatsBase.modelmatrix(m::MixedModel) = m.feterm.x +StatsAPI.modelmatrix(m::MixedModel) = m.feterm.x -StatsBase.nobs(m::MixedModel) = length(m.y) +StatsAPI.nobs(m::MixedModel) = length(m.y) -StatsBase.predict(m::MixedModel) = fitted(m) +StatsAPI.predict(m::MixedModel) = fitted(m) function retbl(mat, trm) return merge( @@ -106,7 +106,7 @@ function raneftables(m::MixedModel{T}; uscale=false) where {T} return NamedTuple{fnames(m)}((map(retbl, ranef(m; uscale=uscale), m.reterms)...,)) end -StatsBase.residuals(m::MixedModel) = response(m) .- fitted(m) +StatsAPI.residuals(m::MixedModel) = response(m) .- fitted(m) """ response(m::MixedModel) @@ -117,9 +117,9 @@ For a linear mixed model this is a `view` of the last column of the `XyMat` fiel For a generalized linear mixed model this is the `m.resp.y` field. In either case it should be copied if it is to be modified. """ -StatsBase.response(m::MixedModel) = m.y +StatsAPI.response(m::MixedModel) = m.y -function StatsBase.responsename(m::MixedModel) +function StatsAPI.responsename(m::MixedModel) cnm = coefnames(m.formula.lhs) return isa(cnm, Vector{String}) ? first(cnm) : cnm end @@ -152,7 +152,7 @@ end Returns the variance-covariance matrix of the fixed effects. If `corr` is `true`, the correlation of the fixed effects is returned instead. """ -function StatsBase.vcov(m::MixedModel; corr=false) +function StatsAPI.vcov(m::MixedModel; corr=false) Xtrm = m isa GeneralizedLinearMixedModel ? m.LMM.feterm : m.feterm iperm = invperm(Xtrm.piv) p = length(iperm) diff --git a/src/predict.jl b/src/predict.jl index 9aa0d7a5e..9440d3158 100644 --- a/src/predict.jl +++ b/src/predict.jl @@ -1,7 +1,7 @@ """ - StatsBase.predict(m::LinearMixedModel, newdata; + StatsAPI.predict(m::LinearMixedModel, newdata; new_re_levels=:missing) - StatsBase.predict(m::GeneralizedLinearMixedModel, newdata; + StatsAPI.predict(m::GeneralizedLinearMixedModel, newdata; new_re_levels=:missing, type=:response) Predict response for new data. @@ -60,13 +60,13 @@ difference between these terms, then you probably want `type=:response`. Regression weights are not yet supported in prediction. Similarly, offsets are also not supported for `GeneralizedLinearMixedModel`. """ -function StatsBase.predict( +function StatsAPI.predict( m::LinearMixedModel, newdata::Tables.ColumnTable; new_re_levels=:missing ) return _predict(m, newdata, m.β; new_re_levels) end -function StatsBase.predict( +function StatsAPI.predict( m::GeneralizedLinearMixedModel, newdata::Tables.ColumnTable; new_re_levels=:population, @@ -207,7 +207,7 @@ function _predict(m::MixedModel{T}, newdata, β; new_re_levels) where {T} end # yup, I got lazy on this one -- let the dispatched method handle kwarg checking -function StatsBase.predict(m::MixedModel, newdata; kwargs...) +function StatsAPI.predict(m::MixedModel, newdata; kwargs...) return predict(m, columntable(newdata); kwargs...) end diff --git a/src/remat.jl b/src/remat.jl index 6fa9ede53..fc350d9b0 100644 --- a/src/remat.jl +++ b/src/remat.jl @@ -160,7 +160,7 @@ Return a `Bool` indicator matrix of the potential non-zeros in `A.λ` """ function indmat end -indmat(rt::ReMat{T,1}) where {T} = ones(Bool, 1, 1) +indmat(::ReMat{T,1}) where {T} = ones(Bool, 1, 1) indmat(rt::ReMat{T,S}) where {T,S} = reshape([i in rt.inds for i in 1:abs2(S)], S, S) nlevs(A::ReMat) = length(A.levels) @@ -253,7 +253,7 @@ function LinearAlgebra.mul!( return C end -function *(adjA::Adjoint{T,<:ReMat{T,1}}, B::ReMat{T,1}) where {T} +function Base.:(*)(adjA::Adjoint{T,<:ReMat{T,1}}, B::ReMat{T,1}) where {T} A = adjA.parent return if A === B mul!(Diagonal(Vector{T}(undef, size(B, 2))), adjA, B) @@ -262,8 +262,9 @@ function *(adjA::Adjoint{T,<:ReMat{T,1}}, B::ReMat{T,1}) where {T} end end -*(adjA::Adjoint{T,<:ReMat{T}}, B::ReMat{T}) where {T} = adjA.parent.adjA * sparse(B) -function *(adjA::Adjoint{T,<:FeMat{T}}, B::ReMat{T}) where {T} +Base.:(*)(adjA::Adjoint{T,<:ReMat{T}}, B::ReMat{T}) where {T} = adjA.parent.adjA * sparse(B) + +function Base.:(*)(adjA::Adjoint{T,<:FeMat{T}}, B::ReMat{T}) where {T} return mul!(Matrix{T}(undef, size(adjA.parent, 2), size(B, 2)), adjA, B) end @@ -468,7 +469,7 @@ function LinearAlgebra.mul!( return y end -function *(adjA::Adjoint{T,<:ReMat{T,S}}, B::ReMat{T,P}) where {T,S,P} +function Base.:(*)(adjA::Adjoint{T,<:ReMat{T,S}}, B::ReMat{T,P}) where {T,S,P} A = adjA.parent if A === B return mul!(UniformBlockDiagonal(Array{T}(undef, S, S, nlevs(A))), adjA, A) @@ -492,11 +493,11 @@ end # TODO: use DataAPI PCA(A::ReMat{T,S}; corr::Bool=true) where {T,S} = PCA(A.λ, A.cnames; corr=corr) -refarray(A::ReMat) = A.refs +DataAPI.refarray(A::ReMat) = A.refs -refpool(A::ReMat) = A.levels +DataAPI.refpool(A::ReMat) = A.levels -refvalue(A::ReMat, i::Integer) = A.levels[i] +DataAPI.refvalue(A::ReMat, i::Integer) = A.levels[i] function reweight!(A::ReMat, sqrtwts::Vector) if length(sqrtwts) > 0 @@ -700,7 +701,7 @@ function corrmat(A::ReMat{T}) where {T} return Symmetric(λnorm * λnorm', :L) end -vsize(A::ReMat{T,S}) where {T,S} = S +vsize(::ReMat{T,S}) where {T,S} = S function zerocorr!(A::ReMat{T}) where {T} λ = A.λ = Diagonal(A.λ) From 72ac0e13556f5f4965191f91e07a365314b456ce Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Wed, 5 Oct 2022 12:54:53 -0500 Subject: [PATCH 11/51] Combine updateL! operations on diagonal blocks (#648) * Combine updateL! operations on diagonal blocks * Update NEWS, etc. * Style enforcement * Remove redundant method, bump version number --- NEWS.md | 5 +++++ Project.toml | 2 +- src/arraytypes.jl | 8 -------- src/linearmixedmodel.jl | 10 +++++----- src/precompile_MixedModels.jl | 4 ++-- src/remat.jl | 35 ++++++++++++++++++++++------------- test/UniformBlockDiagonal.jl | 10 +++++----- 7 files changed, 40 insertions(+), 34 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9fc21707c..5b5bdaa01 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.7.2 Release Notes +============================== +* Replace separate calls to `copyto!` and `scaleinflate!` in `updateL!` with `copyscaleinflate!` [#648] + MixedModels v4.7.1 Release Notes ============================== * Avoid repeating initial objective evaluation in `fit!` method for `LinearMixedModel` @@ -365,3 +369,4 @@ Package dependencies [#615]: https://github.com/JuliaStats/MixedModels.jl/issues/615 [#628]: https://github.com/JuliaStats/MixedModels.jl/issues/628 [#637]: https://github.com/JuliaStats/MixedModels.jl/issues/637 +[#648]: https://github.com/JuliaStats/MixedModels.jl/issues/648 diff --git a/Project.toml b/Project.toml index 3a8539013..dd3c0f00c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.7.1" +version = "4.7.2" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/arraytypes.jl b/src/arraytypes.jl index 5d41a63ab..9354bfdcb 100644 --- a/src/arraytypes.jl +++ b/src/arraytypes.jl @@ -12,14 +12,6 @@ function Base.axes(A::UniformBlockDiagonal) return (Base.OneTo(m * l), Base.OneTo(n * l)) end -function Base.copyto!(dest::UniformBlockDiagonal{T}, src::UniformBlockDiagonal{T}) where {T} - sdat = src.data - ddat = dest.data - size(ddat) == size(sdat) || throw(DimensionMismatch("")) - copyto!(ddat, sdat) - return dest -end - function Base.copyto!(dest::Matrix{T}, src::UniformBlockDiagonal{T}) where {T} size(dest) == size(src) || throw(DimensionMismatch("")) fill!(dest, zero(T)) diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index 418ed6b90..fc502ca44 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -1210,14 +1210,14 @@ This is the crucial step in evaluating the objective, given a new parameter valu function updateL!(m::LinearMixedModel{T}) where {T} A, L, reterms = m.A, m.L, m.reterms k = length(reterms) - for (l, a) in zip(L, A) # copy each element of A to corresponding element of L - copyto!(l, a) # For some reason copyto!.(L, A) allocates a lot of memory - end + copyto!(last(m.L), last(m.A)) # ensure the fixed-effects:response block is copied for j in eachindex(reterms) # pre- and post-multiply by Λ, add I to diagonal cj = reterms[j] - scaleinflate!(L[kp1choose2(j)], cj) + diagind = kp1choose2(j) + copyscaleinflate!(L[diagind], A[diagind], cj) for i in (j + 1):(k + 1) # postmultiply column by Λ - rmulΛ!(L[block(i, j)], cj) + bij = block(i, j) + rmulΛ!(copyto!(L[bij], A[bij]), cj) end for jj in 1:(j - 1) # premultiply row by Λ' lmulΛ!(cj', L[block(j, jj)]) diff --git a/src/precompile_MixedModels.jl b/src/precompile_MixedModels.jl index e4e2b190f..2ff92d965 100644 --- a/src/precompile_MixedModels.jl +++ b/src/precompile_MixedModels.jl @@ -24,7 +24,7 @@ end # time: 2.1690955 Base.precompile(Tuple{typeof(adjA),Vector{Int32},Matrix{Float64}}) # time: 0.11642844 Base.precompile(Tuple{typeof(apply_schema),Term,MultiSchema{FullRank},UnionAll}) # time: 0.0992202 Base.precompile(Tuple{typeof(fit),Type{GeneralizedLinearMixedModel},FormulaTerm,NamedTuple,Bernoulli,LogitLink}) # time: 0.09839547 - Base.precompile(Tuple{typeof(scaleinflate!),UniformBlockDiagonal{Float64},ReMat{Float64, 2}}) # time: 0.07856259 + Base.precompile(Tuple{typeof(copyscaleinflate!),UniformBlockDiagonal{Float64},UniformBlockDiagonal{Float64},ReMat{Float64, 2}}) # time: 0.07856259 Base.precompile(Tuple{typeof(*),Adjoint{Float64, ReMat{Float64, 2}},ReMat{Float64, 2}}) # time: 0.064247385 let fbody = try Base.bodyfunction(which(fit, (Type{LinearMixedModel},FormulaTerm,NamedTuple,))) catch missing end if !ismissing(fbody) @@ -38,7 +38,7 @@ end # time: 0.0641711 Base.precompile(Tuple{typeof(LD),UniformBlockDiagonal{Float64}}) # time: 0.029826526 Base.precompile(Tuple{typeof(*),Adjoint{Float64, ReMat{Float64, 1}},ReMat{Float64, 1}}) # time: 0.02977296 Base.precompile(Tuple{typeof(GLM.wrkresp!),SubArray{Float64, 1, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true},GLM.GlmResp{Vector{Float64}, Bernoulli{Float64}, LogitLink}}) # time: 0.022571307 - Base.precompile(Tuple{typeof(scaleinflate!),Diagonal{Float64, Vector{Float64}},ReMat{Float64, 1}}) # time: 0.014116756 + Base.precompile(Tuple{typeof(copyscaleinflate!),Diagonal{Float64, Vector{Float64}},Diagonal{Float64, Vector{Float64}},ReMat{Float64, 1}}) # time: 0.014116756 Base.precompile(Tuple{typeof(cholUnblocked!),UniformBlockDiagonal{Float64},Type{Val{:L}}}) # time: 0.011265205 Base.precompile(Tuple{Core.Type{MixedModels.GeneralizedLinearMixedModel{Float64, Distributions.Bernoulli}},LinearMixedModel,Any,Any,Vector,Any,Any,Any,Any,Any,Any,Any,Any,Any,Any}) # time: 0.010291444 Base.precompile(Tuple{typeof(apply_schema),RandomEffectsTerm,MultiSchema{FullRank},Type{LinearMixedModel}}) # time: 0.009160354 diff --git a/src/remat.jl b/src/remat.jl index fc350d9b0..11103b966 100644 --- a/src/remat.jl +++ b/src/remat.jl @@ -550,31 +550,35 @@ function rowlengths(A::ReMat) end """ - scaleinflate!(L::AbstractMatrix, Λ::ReMat) + copyscaleinflate!(L::AbstractMatrix, A::AbstractMatrix, Λ::ReMat) -Overwrite L with `Λ'LΛ + I` +Overwrite L with `Λ'AΛ + I` """ -function scaleinflate! end +function copyscaleinflate! end -function scaleinflate!(Ljj::Diagonal{T}, Λj::ReMat{T,1}) where {T} - Ljjd = Ljj.diag - broadcast!((x, λsqr) -> x * λsqr + 1, Ljjd, Ljjd, abs2(only(Λj.λ.data))) +function copyscaleinflate!(Ljj::Diagonal{T}, Ajj::Diagonal{T}, Λj::ReMat{T,1}) where {T} + Ldiag, Adiag = Ljj.diag, Ajj.diag + broadcast!((x, λsqr) -> x * λsqr + one(T), Ldiag, Adiag, abs2(only(Λj.λ.data))) return Ljj end -function scaleinflate!(Ljj::Matrix{T}, Λj::ReMat{T,1}) where {T} +function copyscaleinflate!(Ljj::Matrix{T}, Ajj::Diagonal{T}, Λj::ReMat{T,1}) where {T} + fill!(Ljj, zero(T)) lambsq = abs2(only(Λj.λ.data)) - @inbounds for i in diagind(Ljj) - Ljj[i] *= lambsq - Ljj[i] += one(T) + @inbounds for (i, a) in enumerate(Ajj.diag) + Ljj[i, i] = lambsq * a + one(T) end return Ljj end -function scaleinflate!(Ljj::UniformBlockDiagonal{T}, Λj::ReMat{T,S}) where {T,S} +function copyscaleinflate!( + Ljj::UniformBlockDiagonal{T}, + Ajj::UniformBlockDiagonal{T}, + Λj::ReMat{T,S} +) where {T,S} λ = Λj.λ dind = diagind(S, S) - Ldat = Ljj.data + Ldat = copyto!(Ljj.data, Ajj.data) for k in axes(Ldat, 3) f = view(Ldat, :, :, k) lmul!(λ', rmul!(f, λ)) @@ -585,7 +589,12 @@ function scaleinflate!(Ljj::UniformBlockDiagonal{T}, Λj::ReMat{T,S}) where {T,S return Ljj end -function scaleinflate!(Ljj::Matrix{T}, Λj::ReMat{T,S}) where {T,S} +function copyscaleinflate!( + Ljj::Matrix{T}, + Ajj::UniformBlockDiagonal{T}, + Λj::ReMat{T,S} +) where {T,S} + copyto!(Ljj, Ajj) n = LinearAlgebra.checksquare(Ljj) q, r = divrem(n, S) iszero(r) || throw(DimensionMismatch("size(Ljj, 1) is not a multiple of S")) diff --git a/test/UniformBlockDiagonal.jl b/test/UniformBlockDiagonal.jl index 4ff35d50d..158b06a4d 100644 --- a/test/UniformBlockDiagonal.jl +++ b/test/UniformBlockDiagonal.jl @@ -42,12 +42,12 @@ const LMM = LinearMixedModel @test view(ex22.data, :, :, 3) == reshape(9:12, (2,2)) end - @testset "scaleinflate" begin - MixedModels.scaleinflate!(copyto!(Lblk, ex22), vf1) + @testset "copyscaleinflate" begin + MixedModels.copyscaleinflate!(Lblk, ex22, vf1) @test view(Lblk.data, :, :, 1) == [2. 3.; 2. 5.] setθ!(vf1, [1.,1.,1.]) Λ = vf1.λ - MixedModels.scaleinflate!(copyto!(Lblk, ex22), vf1) + MixedModels.copyscaleinflate!(Lblk, ex22, vf1) target = Λ'view(ex22.data, :, :, 1)*Λ + I @test view(Lblk.data, :, :, 1) == target end @@ -61,7 +61,7 @@ const LMM = LinearMixedModel @test vf1.λ == LowerTriangular(Matrix(I, 2, 2)) setθ!(vf2, [1.75, 0.0, 1.0]) A11 = vf1'vf1 - L11 = MixedModels.cholUnblocked!(MixedModels.scaleinflate!(copyto!(UniformBlockDiagonal(fill(0., size(A11.data))), A11), vf1), Val{:L}) + L11 = MixedModels.cholUnblocked!(MixedModels.copyscaleinflate!(UniformBlockDiagonal(fill(0., size(A11.data))), A11, vf1), Val{:L}) L21 = vf2'vf1 @test isa(L21, BlockedSparse) @test L21[1,1] == 30.0 @@ -74,6 +74,6 @@ const LMM = LinearMixedModel # rdiv!(L21, adjoint(LowerTriangular(L11))) # @test_broken L21.colblocks[1] == rdiv!(L21cb1, adjoint(LowerTriangular(L11.facevec[1]))) A22 = vf2'vf2 - L22 = MixedModels.scaleinflate!(copyto!(UniformBlockDiagonal(fill(0., size(A22.data))), A22), vf2) + L22 = MixedModels.copyscaleinflate!(UniformBlockDiagonal(fill(0., size(A22.data))), A22, vf2) end end From a33131cd867f1b9efa722784f0aacc779f63d843 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Thu, 6 Oct 2022 14:44:01 +0000 Subject: [PATCH 12/51] better error msg for models without random effects (#651) * better error msg for models without random effects * news * use the supertype * more safety * LTS test compat * change release notes to new patch * patch bump --- NEWS.md | 5 +++++ Project.toml | 2 +- src/linearmixedmodel.jl | 9 +++++++++ test/misc.jl | 18 ++++++++++++++++++ test/runtests.jl | 1 + 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/misc.jl diff --git a/NEWS.md b/NEWS.md index 5b5bdaa01..e87202392 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.7.3 Release Notes +============================== +* More informative error message for formulae lacking random effects [#651] + MixedModels v4.7.2 Release Notes ============================== * Replace separate calls to `copyto!` and `scaleinflate!` in `updateL!` with `copyscaleinflate!` [#648] @@ -370,3 +374,4 @@ Package dependencies [#628]: https://github.com/JuliaStats/MixedModels.jl/issues/628 [#637]: https://github.com/JuliaStats/MixedModels.jl/issues/637 [#648]: https://github.com/JuliaStats/MixedModels.jl/issues/648 +[#651]: https://github.com/JuliaStats/MixedModels.jl/issues/651 diff --git a/Project.toml b/Project.toml index dd3c0f00c..192d882aa 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.7.2" +version = "4.7.3" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index fc502ca44..99647bfa0 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -46,6 +46,9 @@ function LinearMixedModel( ) return LinearMixedModel(f::FormulaTerm, Tables.columntable(tbl); contrasts, wts, σ) end +const _MISSING_RE_ERROR = ArgumentError( + "Formula contains no random effects; this isn't a mixed model. Perhaps you want to use GLM.jl?", +) function LinearMixedModel( f::FormulaTerm, tbl::Tables.ColumnTable; contrasts=Dict{Symbol,Any}(), wts=[], σ=nothing @@ -62,6 +65,11 @@ function LinearMixedModel( rethrow(e) end form = apply_schema(f, sch, LinearMixedModel) + + if form.rhs isa MatrixTerm || !any(x -> isa(x, AbstractReTerm), form.rhs) + throw(_MISSING_RE_ERROR) + end + # tbl, _ = StatsModels.missing_omit(tbl, form) y, Xs = modelcols(form, tbl) @@ -119,6 +127,7 @@ function LinearMixedModel( push!(feterms, FeTerm(x, isa(cnames, String) ? [cnames] : collect(cnames))) end end + isempty(reterms) && throw(_MISSING_RE_ERROR) return LinearMixedModel(convert(Array{T}, y), only(feterms), reterms, form, wts, σ) end diff --git a/test/misc.jl b/test/misc.jl new file mode 100644 index 000000000..1a89d4b5d --- /dev/null +++ b/test/misc.jl @@ -0,0 +1,18 @@ +using MixedModels +using Test + +using MixedModels: dataset + +@testset "formula misspecification" begin + dyestuff = dataset(:dyestuff) + + @test MixedModel(@formula(yield ~ 0 + (1|batch)), dyestuff) isa LinearMixedModel + @test MixedModel(@formula(yield ~ 1 + (1|batch)), dyestuff) isa LinearMixedModel + @test_throws MixedModels._MISSING_RE_ERROR MixedModel(@formula(yield ~ 0 + batch), dyestuff) + @test_throws MixedModels._MISSING_RE_ERROR MixedModel(@formula(yield ~ 1), dyestuff) + + @test MixedModel(@formula(yield ~ 0 + (1|batch)), dyestuff, Poisson()) isa GeneralizedLinearMixedModel + @test MixedModel(@formula(yield ~ 1 + (1|batch)), dyestuff, Poisson()) isa GeneralizedLinearMixedModel + @test_throws MixedModels._MISSING_RE_ERROR MixedModel(@formula(yield ~ 0 + batch), dyestuff, Poisson()) + @test_throws MixedModels._MISSING_RE_ERROR MixedModel(@formula(yield ~ 1), dyestuff, Poisson()) +end diff --git a/test/runtests.jl b/test/runtests.jl index bac90db8a..1e40d26d7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -14,6 +14,7 @@ else end include("utilities.jl") +include("misc.jl") include("pivot.jl") include("UniformBlockDiagonal.jl") include("linalg.jl") From 0debf0614af94a17a4bca6799ab092d4f7a4e4da Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Thu, 6 Oct 2022 17:32:38 +0000 Subject: [PATCH 13/51] exploration from issue 638 (#646) - adds an `issues` directory where scripts, `Project.toml` and `Manifest.toml` files relevant to a particular issue can be stored. --- issues/638/Manifest.toml | 695 +++++++++++++++++++++++++++++++++++++++ issues/638/Project.toml | 9 + issues/638/main.jl | 131 ++++++++ 3 files changed, 835 insertions(+) create mode 100644 issues/638/Manifest.toml create mode 100644 issues/638/Project.toml create mode 100644 issues/638/main.jl diff --git a/issues/638/Manifest.toml b/issues/638/Manifest.toml new file mode 100644 index 000000000..9fdcf5991 --- /dev/null +++ b/issues/638/Manifest.toml @@ -0,0 +1,695 @@ +# This file is machine-generated - editing it directly is not advised + +[[ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[Arrow]] +deps = ["ArrowTypes", "BitIntegers", "CodecLz4", "CodecZstd", "DataAPI", "Dates", "Mmap", "PooledArrays", "SentinelArrays", "Tables", "TimeZones", "UUIDs"] +git-tree-sha1 = "4e7aa2021204bd9456ad3e87372237e84ee2c3c1" +uuid = "69666777-d1a9-59fb-9406-91d4454c9d45" +version = "2.3.0" + +[[ArrowTypes]] +deps = ["UUIDs"] +git-tree-sha1 = "a0633b6d6efabf3f76dacd6eb1b3ec6c42ab0552" +uuid = "31f734f8-188a-4ce0-8406-c8a06bd891cd" +version = "1.2.1" + +[[Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[BenchmarkTools]] +deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] +git-tree-sha1 = "4c10eee4af024676200bc7752e536f858c6b8f93" +uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +version = "1.3.1" + +[[BitIntegers]] +deps = ["Random"] +git-tree-sha1 = "5a814467bda636f3dde5c4ef83c30dd0a19928e0" +uuid = "c3b6d118-76ef-56ca-8cc7-ebb389d030a1" +version = "0.2.6" + +[[Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.8+0" + +[[CEnum]] +git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90" +uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" +version = "0.4.2" + +[[CSV]] +deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings"] +git-tree-sha1 = "873fb188a4b9d76549b81465b1f75c82aaf59238" +uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +version = "0.10.4" + +[[Calculus]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" +uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" +version = "0.5.1" + +[[ChainRulesCore]] +deps = ["Compat", "LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "e7ff6cadf743c098e08fca25c91103ee4303c9bb" +uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +version = "1.15.6" + +[[ChangesOfVariables]] +deps = ["ChainRulesCore", "LinearAlgebra", "Test"] +git-tree-sha1 = "38f7a08f19d8810338d4f5085211c7dfa5d5bdd8" +uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" +version = "0.1.4" + +[[CodecBzip2]] +deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"] +git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7" +uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd" +version = "0.7.2" + +[[CodecLz4]] +deps = ["Lz4_jll", "TranscodingStreams"] +git-tree-sha1 = "59fe0cb37784288d6b9f1baebddbf75457395d40" +uuid = "5ba52731-8f18-5e0d-9241-30f10d1ec561" +version = "0.4.0" + +[[CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.0" + +[[CodecZstd]] +deps = ["CEnum", "TranscodingStreams", "Zstd_jll"] +git-tree-sha1 = "849470b337d0fa8449c21061de922386f32949d9" +uuid = "6b39b394-51ab-5f42-8807-6242bab2b4c2" +version = "0.7.2" + +[[CommonSubexpressions]] +deps = ["MacroTools", "Test"] +git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" +uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" +version = "0.3.0" + +[[Compat]] +deps = ["Dates", "LinearAlgebra", "UUIDs"] +git-tree-sha1 = "5856d3031cdb1f3b2b6340dfdc66b6d9a149a374" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "4.2.0" + +[[CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "0.5.2+0" + +[[Crayons]] +git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" +uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" +version = "4.1.1" + +[[DataAPI]] +git-tree-sha1 = "46d2680e618f8abd007bce0c3026cb0c4a8f2032" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.12.0" + +[[DataFrames]] +deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Random", "Reexport", "SnoopPrecompile", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] +git-tree-sha1 = "1df8f72c05cc83c1e6907f393312d3b009bcc3d4" +uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +version = "1.4.0" + +[[DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.13" + +[[DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[DensityInterface]] +deps = ["InverseFunctions", "Test"] +git-tree-sha1 = "80c3e8639e3353e5d2912fb3a1916b8455e2494b" +uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d" +version = "0.4.0" + +[[DiffResults]] +deps = ["StaticArraysCore"] +git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" +uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +version = "1.1.0" + +[[DiffRules]] +deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] +git-tree-sha1 = "992a23afdb109d0d2f8802a30cf5ae4b1fe7ea68" +uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" +version = "1.11.1" + +[[Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[Distributions]] +deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Test"] +git-tree-sha1 = "0d7d213133d948c56e8c2d9f4eab0293491d8e4a" +uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" +version = "0.25.75" + +[[DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "5158c2b41018c5f7eb1470d558127ac274eca0c9" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.1" + +[[Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[DualNumbers]] +deps = ["Calculus", "NaNMath", "SpecialFunctions"] +git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" +uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" +version = "0.6.8" + +[[ExprTools]] +git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d" +uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" +version = "0.1.8" + +[[FilePathsBase]] +deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"] +git-tree-sha1 = "e27c4ebe80e8699540f2d6c805cc12203b614f12" +uuid = "48062228-2e41-5def-b9a4-89aafe57970f" +version = "0.9.20" + +[[FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[FillArrays]] +deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] +git-tree-sha1 = "87519eb762f85534445f5cda35be12e32759ee14" +uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" +version = "0.13.4" + +[[Formatting]] +deps = ["Printf"] +git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" +uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" +version = "0.4.2" + +[[ForwardDiff]] +deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"] +git-tree-sha1 = "187198a4ed8ccd7b5d99c41b69c679269ea2b2d4" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "0.10.32" + +[[Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" + +[[GLM]] +deps = ["Distributions", "LinearAlgebra", "Printf", "Reexport", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "StatsModels"] +git-tree-sha1 = "039118892476c2bf045a43b88fcb75ed566000ff" +uuid = "38e38edf-8417-5370-95a0-9cbb8c7f171a" +version = "1.8.0" + +[[HypergeometricFunctions]] +deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions", "Test"] +git-tree-sha1 = "709d864e3ed6e3545230601f94e11ebc65994641" +uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" +version = "0.3.11" + +[[InlineStrings]] +deps = ["Parsers"] +git-tree-sha1 = "d0ca109edbae6b4cc00e751a29dcb15a124053d6" +uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" +version = "1.2.0" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[InverseFunctions]] +deps = ["Test"] +git-tree-sha1 = "49510dfcb407e572524ba94aeae2fced1f3feb0f" +uuid = "3587e190-3f89-42d0-90ee-14403ec27112" +version = "0.1.8" + +[[InvertedIndices]] +git-tree-sha1 = "bee5f1ef5bf65df56bdd2e40447590b272a5471f" +uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" +version = "1.1.0" + +[[IrrationalConstants]] +git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.1.1" + +[[IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + +[[JLLWrappers]] +deps = ["Preferences"] +git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.4.1" + +[[JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.3" + +[[JSON3]] +deps = ["Dates", "Mmap", "Parsers", "StructTypes", "UUIDs"] +git-tree-sha1 = "f1572de22c866dc92aea032bc89c2b137cbddd6a" +uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +version = "1.10.0" + +[[LazyArtifacts]] +deps = ["Artifacts", "Pkg"] +uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" + +[[LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.3" + +[[LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "7.84.0+0" + +[[LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.10.2+0" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[LinearAlgebra]] +deps = ["Libdl", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[LogExpFunctions]] +deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "94d9c52ca447e23eac0c0f074effbcd38830deb5" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.18" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[Lz4_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "5d494bc6e85c4c9b626ee0cab05daa4085486ab1" +uuid = "5ced341a-0733-55b8-9ab6-a4889d929147" +version = "1.9.3+0" + +[[MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.9" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[MathOptInterface]] +deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "Printf", "SparseArrays", "SpecialFunctions", "Test", "Unicode"] +git-tree-sha1 = "2284cb18c8670fd5c57ad010ce9bd4e2901692d2" +uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" +version = "1.8.2" + +[[MathProgBase]] +deps = ["LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "9abbe463a1e9fc507f12a69e7f29346c2cdc472c" +uuid = "fdba3010-5040-5b88-9595-932c9decdf73" +version = "0.7.8" + +[[MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.0+0" + +[[Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.0.2" + +[[MixedModels]] +deps = ["Arrow", "DataAPI", "Distributions", "GLM", "JSON3", "LazyArtifacts", "LinearAlgebra", "Markdown", "NLopt", "PooledArrays", "ProgressMeter", "Random", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "StatsFuns", "StatsModels", "StructTypes", "Tables"] +git-tree-sha1 = "eb09b8b591d0c2e551ef68c30810fd3d1bb7c946" +uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" +version = "4.7.1" + +[[Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[Mocking]] +deps = ["ExprTools"] +git-tree-sha1 = "748f6e1e4de814b101911e64cc12d83a6af66782" +uuid = "78c3b35d-d492-501b-9361-3d52fe80e533" +version = "0.7.2" + +[[MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2022.2.1" + +[[MutableArithmetics]] +deps = ["LinearAlgebra", "SparseArrays", "Test"] +git-tree-sha1 = "4e675d6e9ec02061800d6cfb695812becbd03cdf" +uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" +version = "1.0.4" + +[[NLopt]] +deps = ["MathOptInterface", "MathProgBase", "NLopt_jll"] +git-tree-sha1 = "5a7e32c569200a8a03c3d55d286254b0321cd262" +uuid = "76087f3c-5699-56af-9a33-bf431cd00edd" +version = "0.6.5" + +[[NLopt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9b1f15a08f9d00cdb2761dcfa6f453f5d0d6f973" +uuid = "079eb43e-fd8e-5478-9966-2cf3e3edb778" +version = "2.7.1+0" + +[[NaNMath]] +deps = ["OpenLibm_jll"] +git-tree-sha1 = "a7c3d1da1189a1c2fe843a3bfa04d18d20eb3211" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.0.1" + +[[NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.20+0" + +[[OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.1+0" + +[[OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.5+0" + +[[OrderedCollections]] +git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.4.1" + +[[PDMats]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "cf494dca75a69712a72b80bc48f59dcf3dea63ec" +uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" +version = "0.11.16" + +[[Parsers]] +deps = ["Dates"] +git-tree-sha1 = "3d5bf43e3e8b412656404ed9466f1dcbf7c50269" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.4.0" + +[[Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.8.0" + +[[PooledArrays]] +deps = ["DataAPI", "Future"] +git-tree-sha1 = "a6062fe4063cdafe78f4a0a81cfffb89721b30e7" +uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" +version = "1.4.2" + +[[Preferences]] +deps = ["TOML"] +git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.3.0" + +[[PrettyTables]] +deps = ["Crayons", "Formatting", "Markdown", "Reexport", "StringManipulation", "Tables"] +git-tree-sha1 = "460d9e154365e058c4d886f6f7d6df5ffa1ea80e" +uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" +version = "2.1.2" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[Profile]] +deps = ["Printf"] +uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" + +[[ProgressMeter]] +deps = ["Distributed", "Printf"] +git-tree-sha1 = "d7a7aef8f8f2d537104f170139553b14dfe39fe9" +uuid = "92933f4c-e287-5a05-a399-4b506db050ca" +version = "1.7.2" + +[[QuadGK]] +deps = ["DataStructures", "LinearAlgebra"] +git-tree-sha1 = "3c009334f45dfd546a16a57960a821a1a023d241" +uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" +version = "2.5.0" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["SHA", "Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[RecipesBase]] +deps = ["SnoopPrecompile"] +git-tree-sha1 = "612a4d76ad98e9722c8ba387614539155a59e30c" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.3.0" + +[[Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[Rmath]] +deps = ["Random", "Rmath_jll"] +git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f" +uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" +version = "0.7.0" + +[[Rmath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7" +uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" +version = "0.3.0+0" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[Scratch]] +deps = ["Dates"] +git-tree-sha1 = "f94f779c94e58bf9ea243e77a37e16d9de9126bd" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.1.1" + +[[SentinelArrays]] +deps = ["Dates", "Random"] +git-tree-sha1 = "c0f56940fc967f3d5efed58ba829747af5f8b586" +uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" +version = "1.3.15" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[ShiftedArrays]] +git-tree-sha1 = "503688b59397b3307443af35cd953a13e8005c16" +uuid = "1277b4bf-5013-50f5-be3d-901d8477a67a" +version = "2.0.0" + +[[SnoopPrecompile]] +git-tree-sha1 = "f604441450a3c0569830946e5b33b78c928e1a85" +uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" +version = "1.0.1" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.0.1" + +[[SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[SpecialFunctions]] +deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "d75bda01f8c31ebb72df80a46c88b25d1c79c56d" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.1.7" + +[[StaticArrays]] +deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] +git-tree-sha1 = "f86b3a049e5d05227b10e15dbb315c5b90f14988" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.5.9" + +[[StaticArraysCore]] +git-tree-sha1 = "6b7ba252635a5eff6a0b0664a41ee140a1c9e72a" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.4.0" + +[[Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "f9af7f195fb13589dd2e2d57fdb401717d2eb1f6" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.5.0" + +[[StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "d1bf48bfcc554a3761a133fe3a9bb01488e06916" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.33.21" + +[[StatsFuns]] +deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] +git-tree-sha1 = "5783b877201a82fc0014cbf381e7e6eb130473a4" +uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +version = "1.0.1" + +[[StatsModels]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Printf", "REPL", "ShiftedArrays", "SparseArrays", "StatsBase", "StatsFuns", "Tables"] +git-tree-sha1 = "a5e15f27abd2692ccb61a99e0854dfb7d48017db" +uuid = "3eaba693-59b7-5ba5-a881-562e759f1c8d" +version = "0.6.33" + +[[StringManipulation]] +git-tree-sha1 = "46da2434b41f41ac3594ee9816ce5541c6096123" +uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" +version = "0.3.0" + +[[StructTypes]] +deps = ["Dates", "UUIDs"] +git-tree-sha1 = "ca4bccb03acf9faaf4137a9abc1881ed1841aa70" +uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" +version = "1.10.0" + +[[SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" + +[[TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.0" + +[[TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] +git-tree-sha1 = "2d7164f7b8a066bcfa6224e67736ce0eb54aef5b" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.9.0" + +[[Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.1" + +[[Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[TimeZones]] +deps = ["Dates", "Downloads", "InlineStrings", "LazyArtifacts", "Mocking", "Printf", "RecipesBase", "Scratch", "Unicode"] +git-tree-sha1 = "d634a3641062c040fc8a7e2a3ea17661cc159688" +uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53" +version = "1.9.0" + +[[TranscodingStreams]] +deps = ["Random", "Test"] +git-tree-sha1 = "8a75929dcd3c38611db2f8d08546decb514fcadf" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.9.9" + +[[UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[WeakRefStrings]] +deps = ["DataAPI", "InlineStrings", "Parsers"] +git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" +uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" +version = "1.4.2" + +[[Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.12+3" + +[[Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.2+0" + +[[libblastrampoline_jll]] +deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.1.1+0" + +[[nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.48.0+0" + +[[p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+0" diff --git a/issues/638/Project.toml b/issues/638/Project.toml new file mode 100644 index 000000000..f4bf0e09d --- /dev/null +++ b/issues/638/Project.toml @@ -0,0 +1,9 @@ +[deps] +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a" +MixedModels = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" + +[compat] +MixedModels = "4" diff --git a/issues/638/main.jl b/issues/638/main.jl new file mode 100644 index 000000000..08856d421 --- /dev/null +++ b/issues/638/main.jl @@ -0,0 +1,131 @@ +using CSV +using DataFrames +using Downloads +using GLM +using MixedModels + +const CSV_URL = "https://github.com/JuliaStats/MixedModels.jl/files/9649005/data.csv" + +data = CSV.read(Downloads.download(CSV_URL), DataFrame) + +model_form = @formula(y ~ v1 + v2 + v3 + v4 + v5 + + (1 | pl3) + ((0 + v1) | pl3) + + (1 | pl5) + ((0 + v2) | pl5) + + ((0 + v3) | pl5) + ((0 + v4) | pl5) + + ((0 + v5) | pl5)) + +wts = data[!, :w] +contrasts = Dict(:pl3 => Grouping(), :pl5 => Grouping()); +# contrasts = Dict(:pl3 => DummyCoding(), :pl5 => DummyCoding()); + +lm(@formula(y ~ v1 + v2 + v3 + v4 + v5), data; wts) +# y ~ 1 + v1 + v2 + v3 + v4 + v5 + +# Coefficients: +# ───────────────────────────────────────────────────────────────────────────────────── +# Coef. Std. Error t Pr(>|t|) Lower 95% Upper 95% +# ───────────────────────────────────────────────────────────────────────────────────── +# (Intercept) -0.000575762 0.000112393 -5.12 <1e-06 -0.000796048 -0.000355476 +# v1 -0.934877 0.00206077 -453.65 <1e-99 -0.938916 -0.930838 +# v2 -1.81368 0.00188045 -964.49 <1e-99 -1.81736 -1.80999 +# v3 0.160488 0.000510854 314.16 <1e-99 0.159487 0.16149 +# v4 1.5533 0.00112932 1375.43 <1e-99 1.55108 1.55551 +# v5 1.16306 0.000691772 1681.28 <1e-99 1.16171 1.16442 +# ───────────────────────────────────────────────────────────────────────────────────── + +# R> summary(fm1) +# Linear mixed model fit by REML ['lmerMod'] +# Formula: y ~ v1 + v2 + v3 + v4 + v5 + (1 | pl3) + ((0 + v1) | pl3) + (1 | +# pl5) + ((0 + v2) | pl5) + ((0 + v3) | pl5) + ((0 + v4) | +# pl5) + ((0 + v5) | pl5) +# Data: data +# Weights: data$w + +# REML criterion at convergence: 221644.3 + +# Scaled residuals: +# Min 1Q Median 3Q Max +# -13.8621 -0.4886 -0.1377 0.1888 27.0177 + +# Random effects: +# Groups Name Variance Std.Dev. +# pl5 v5 0.1602787 0.400348 +# pl5.1 v4 0.2347256 0.484485 +# pl5.2 v3 0.0473713 0.217649 +# pl5.3 v2 2.3506900 1.533196 +# pl5.4 (Intercept) 0.0000168 0.004099 +# pl3 v1 2.2690948 1.506351 +# pl3.1 (Intercept) 0.0000000 0.000000 +# Residual 2.5453766 1.595424 +# Number of obs: 133841, groups: pl5, 467; pl3, 79 + +# Fixed effects: +# Estimate Std. Error t value +# (Intercept) -0.0007544 0.0008626 -0.875 +# v1 -1.5365362 0.1839652 -8.352 +# v2 -1.2907640 0.0927009 -13.924 +# v3 0.2111352 0.0161907 13.041 +# v4 0.9270981 0.0663387 13.975 +# v5 0.4402297 0.0390687 11.268 + + +# R> summary(refitML(fm1)) +# Linear mixed model fit by maximum likelihood ['lmerMod'] +# Formula: y ~ v1 + v2 + v3 + v4 + v5 + (1 | pl3) + ((0 + v1) | pl3) + (1 | +# pl5) + ((0 + v2) | pl5) + ((0 + v3) | pl5) + ((0 + v4) | +# pl5) + ((0 + v5) | pl5) +# Data: data +# Weights: data$w + +# AIC BIC logLik deviance df.resid +# 221640.9 221778.1 -110806.4 221612.9 133827 + +# Scaled residuals: +# Min 1Q Median 3Q Max +# -13.8622 -0.4886 -0.1377 0.1888 27.0129 + +# Random effects: +# Groups Name Variance Std.Dev. +# pl5 v5 1.615e-01 0.401829 +# pl5.1 v4 2.353e-01 0.485084 +# pl5.2 v3 4.693e-02 0.216635 +# pl5.3 v2 2.331e+00 1.526889 +# pl5.4 (Intercept) 1.651e-05 0.004064 +# pl3 v1 2.206e+00 1.485228 +# pl3.1 (Intercept) 0.000e+00 0.000000 +# Residual 2.545e+00 1.595419 +# Number of obs: 133841, groups: pl5, 467; pl3, 79 + +# Fixed effects: +# Estimate Std. Error t value +# (Intercept) -0.0007564 0.0008610 -0.878 +# v1 -1.5349996 0.1815460 -8.455 +# v2 -1.2912605 0.0923754 -13.978 +# v3 0.2111613 0.0161330 13.089 +# v4 0.9269805 0.0664061 13.959 +# v5 0.4399864 0.0391905 11.227 + +rtheta = [0.2515021687220257, 0.302059138995283, 0.1358219097194424, 0.9552822736385025, 0.0025389884728883316, 0.8849907215339659, 0.0] +r2jperm = [5, 4, 3, 2, 1, 7, 6] + +fm1_unweighted = fit(MixedModel, model_form, data; contrasts) + +fm1_weighted = LinearMixedModel(model_form, data; wts, contrasts) +# doesn't help +copy!(fm1_weighted.optsum.initial, fm1_unweighted.optsum.final) + +fit!(fm1_weighted) + +fm1 = fit(MixedModel, model_form, data; contrasts, wts) + +# also doesn't help +updateL!(setθ!(fm1_weighted, rtheta[r2jperm])) + +# nor does this work +slopes_form = @formula(y ~ 0 + v1 + v2 + v3 + v4 + v5 + + ((0 + v1) | pl3) + (1| pl5) + + ((0 + v2) | pl5) + + ((0 + v3) | pl5) + ((0 + v4) | pl5) + + ((0 + v5) | pl5)) + +fm2 = LinearMixedModel(slopes_form, data; wts, contrasts) From a7d6eb3b57f357128b0700a91e0041f9cbe59958 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Thu, 6 Oct 2022 17:36:07 +0000 Subject: [PATCH 14/51] tinkerings on 641 (#647) --- issues/641/Manifest.toml | 1408 ++++++++++++++++++++++++++++++++++++++ issues/641/Project.toml | 7 + issues/641/main.jl | 82 +++ 3 files changed, 1497 insertions(+) create mode 100644 issues/641/Manifest.toml create mode 100644 issues/641/Project.toml create mode 100644 issues/641/main.jl diff --git a/issues/641/Manifest.toml b/issues/641/Manifest.toml new file mode 100644 index 000000000..3b83b50b4 --- /dev/null +++ b/issues/641/Manifest.toml @@ -0,0 +1,1408 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.8.2" +manifest_format = "2.0" +project_hash = "1908e0382f87daa6892757412db2314b88138175" + +[[deps.AbstractFFTs]] +deps = ["ChainRulesCore", "LinearAlgebra"] +git-tree-sha1 = "69f7020bd72f069c219b5e8c236c1fa90d2cb409" +uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" +version = "1.2.1" + +[[deps.AbstractTrees]] +git-tree-sha1 = "5c0b629df8a5566a06f5fef5100b53ea56e465a0" +uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" +version = "0.4.2" + +[[deps.Adapt]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "195c5505521008abea5aee4f96930717958eac6f" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "3.4.0" + +[[deps.Animations]] +deps = ["Colors"] +git-tree-sha1 = "e81c509d2c8e49592413bfb0bb3b08150056c79d" +uuid = "27a7e980-b3e6-11e9-2bcd-0b925532e340" +version = "0.4.1" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Arrow]] +deps = ["ArrowTypes", "BitIntegers", "CodecLz4", "CodecZstd", "DataAPI", "Dates", "Mmap", "PooledArrays", "SentinelArrays", "Tables", "TimeZones", "UUIDs"] +git-tree-sha1 = "4e7aa2021204bd9456ad3e87372237e84ee2c3c1" +uuid = "69666777-d1a9-59fb-9406-91d4454c9d45" +version = "2.3.0" + +[[deps.ArrowTypes]] +deps = ["UUIDs"] +git-tree-sha1 = "a0633b6d6efabf3f76dacd6eb1b3ec6c42ab0552" +uuid = "31f734f8-188a-4ce0-8406-c8a06bd891cd" +version = "1.2.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Automa]] +deps = ["Printf", "ScanByte", "TranscodingStreams"] +git-tree-sha1 = "d50976f217489ce799e366d9561d56a98a30d7fe" +uuid = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b" +version = "0.8.2" + +[[deps.AxisAlgorithms]] +deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] +git-tree-sha1 = "66771c8d21c8ff5e3a93379480a2307ac36863f7" +uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" +version = "1.0.1" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.BenchmarkTools]] +deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] +git-tree-sha1 = "4c10eee4af024676200bc7752e536f858c6b8f93" +uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +version = "1.3.1" + +[[deps.BitIntegers]] +deps = ["Random"] +git-tree-sha1 = "5a814467bda636f3dde5c4ef83c30dd0a19928e0" +uuid = "c3b6d118-76ef-56ca-8cc7-ebb389d030a1" +version = "0.2.6" + +[[deps.Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.8+0" + +[[deps.CEnum]] +git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90" +uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" +version = "0.4.2" + +[[deps.CSV]] +deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings"] +git-tree-sha1 = "873fb188a4b9d76549b81465b1f75c82aaf59238" +uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +version = "0.10.4" + +[[deps.Cairo]] +deps = ["Cairo_jll", "Colors", "Glib_jll", "Graphics", "Libdl", "Pango_jll"] +git-tree-sha1 = "d0b3f8b4ad16cb0a2988c6788646a5e6a17b6b1b" +uuid = "159f3aea-2a34-519c-b102-8c37f9878175" +version = "1.0.5" + +[[deps.CairoMakie]] +deps = ["Base64", "Cairo", "Colors", "FFTW", "FileIO", "FreeType", "GeometryBasics", "LinearAlgebra", "Makie", "SHA"] +git-tree-sha1 = "387e0102f240244102814cf73fe9fbbad82b9e9e" +uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +version = "0.8.13" + +[[deps.Cairo_jll]] +deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" +uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" +version = "1.16.1+1" + +[[deps.Calculus]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" +uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" +version = "0.5.1" + +[[deps.ChainRulesCore]] +deps = ["Compat", "LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "e7ff6cadf743c098e08fca25c91103ee4303c9bb" +uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +version = "1.15.6" + +[[deps.ChangesOfVariables]] +deps = ["ChainRulesCore", "LinearAlgebra", "Test"] +git-tree-sha1 = "38f7a08f19d8810338d4f5085211c7dfa5d5bdd8" +uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" +version = "0.1.4" + +[[deps.CodecBzip2]] +deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"] +git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7" +uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd" +version = "0.7.2" + +[[deps.CodecLz4]] +deps = ["Lz4_jll", "TranscodingStreams"] +git-tree-sha1 = "59fe0cb37784288d6b9f1baebddbf75457395d40" +uuid = "5ba52731-8f18-5e0d-9241-30f10d1ec561" +version = "0.4.0" + +[[deps.CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.0" + +[[deps.CodecZstd]] +deps = ["CEnum", "TranscodingStreams", "Zstd_jll"] +git-tree-sha1 = "849470b337d0fa8449c21061de922386f32949d9" +uuid = "6b39b394-51ab-5f42-8807-6242bab2b4c2" +version = "0.7.2" + +[[deps.ColorBrewer]] +deps = ["Colors", "JSON", "Test"] +git-tree-sha1 = "61c5334f33d91e570e1d0c3eb5465835242582c4" +uuid = "a2cac450-b92f-5266-8821-25eda20663c8" +version = "0.4.0" + +[[deps.ColorSchemes]] +deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Random"] +git-tree-sha1 = "1fd869cc3875b57347f7027521f561cf46d1fcd8" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.19.0" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.4" + +[[deps.ColorVectorSpace]] +deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] +git-tree-sha1 = "d08c20eef1f2cbc6e60fd3612ac4340b89fea322" +uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" +version = "0.9.9" + +[[deps.Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.8" + +[[deps.CommonSubexpressions]] +deps = ["MacroTools", "Test"] +git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" +uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" +version = "0.3.0" + +[[deps.Compat]] +deps = ["Dates", "LinearAlgebra", "UUIDs"] +git-tree-sha1 = "5856d3031cdb1f3b2b6340dfdc66b6d9a149a374" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "4.2.0" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "0.5.2+0" + +[[deps.Contour]] +git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781" +uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" +version = "0.6.2" + +[[deps.Crayons]] +git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" +uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" +version = "4.1.1" + +[[deps.DataAPI]] +git-tree-sha1 = "46d2680e618f8abd007bce0c3026cb0c4a8f2032" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.12.0" + +[[deps.DataFrames]] +deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Random", "Reexport", "SnoopPrecompile", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] +git-tree-sha1 = "1df8f72c05cc83c1e6907f393312d3b009bcc3d4" +uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +version = "1.4.0" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.13" + +[[deps.DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.DensityInterface]] +deps = ["InverseFunctions", "Test"] +git-tree-sha1 = "80c3e8639e3353e5d2912fb3a1916b8455e2494b" +uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d" +version = "0.4.0" + +[[deps.DiffResults]] +deps = ["StaticArraysCore"] +git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" +uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +version = "1.1.0" + +[[deps.DiffRules]] +deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] +git-tree-sha1 = "992a23afdb109d0d2f8802a30cf5ae4b1fe7ea68" +uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" +version = "1.11.1" + +[[deps.Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[deps.Distributions]] +deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Test"] +git-tree-sha1 = "0d7d213133d948c56e8c2d9f4eab0293491d8e4a" +uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" +version = "0.25.75" + +[[deps.DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "5158c2b41018c5f7eb1470d558127ac274eca0c9" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.1" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.DualNumbers]] +deps = ["Calculus", "NaNMath", "SpecialFunctions"] +git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" +uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" +version = "0.6.8" + +[[deps.EarCut_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e3290f2d49e661fbd94046d7e3726ffcb2d41053" +uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" +version = "2.2.4+0" + +[[deps.Expat_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bad72f730e9e91c08d9427d5e8db95478a3c323d" +uuid = "2e619515-83b5-522b-bb60-26c02a35a201" +version = "2.4.8+0" + +[[deps.ExprTools]] +git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d" +uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" +version = "0.1.8" + +[[deps.Extents]] +git-tree-sha1 = "5e1e4c53fa39afe63a7d356e30452249365fba99" +uuid = "411431e0-e8b7-467b-b5e0-f676ba4f2910" +version = "0.1.1" + +[[deps.FFMPEG]] +deps = ["FFMPEG_jll"] +git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" +version = "0.4.1" + +[[deps.FFMPEG_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Pkg", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "74faea50c1d007c85837327f6775bea60b5492dd" +uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" +version = "4.4.2+2" + +[[deps.FFTW]] +deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] +git-tree-sha1 = "90630efff0894f8142308e334473eba54c433549" +uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" +version = "1.5.0" + +[[deps.FFTW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea" +uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" +version = "3.3.10+0" + +[[deps.FileIO]] +deps = ["Pkg", "Requires", "UUIDs"] +git-tree-sha1 = "94f5101b96d2d968ace56f7f2db19d0a5f592e28" +uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +version = "1.15.0" + +[[deps.FilePathsBase]] +deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"] +git-tree-sha1 = "e27c4ebe80e8699540f2d6c805cc12203b614f12" +uuid = "48062228-2e41-5def-b9a4-89aafe57970f" +version = "0.9.20" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FillArrays]] +deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] +git-tree-sha1 = "87519eb762f85534445f5cda35be12e32759ee14" +uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" +version = "0.13.4" + +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[deps.Fontconfig_jll]] +deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" +uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" +version = "2.13.93+0" + +[[deps.Formatting]] +deps = ["Printf"] +git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" +uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" +version = "0.4.2" + +[[deps.ForwardDiff]] +deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"] +git-tree-sha1 = "187198a4ed8ccd7b5d99c41b69c679269ea2b2d4" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "0.10.32" + +[[deps.FreeType]] +deps = ["CEnum", "FreeType2_jll"] +git-tree-sha1 = "cabd77ab6a6fdff49bfd24af2ebe76e6e018a2b4" +uuid = "b38be410-82b0-50bf-ab77-7b57e271db43" +version = "4.0.0" + +[[deps.FreeType2_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" +uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" +version = "2.10.4+0" + +[[deps.FreeTypeAbstraction]] +deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics"] +git-tree-sha1 = "b5c7fe9cea653443736d264b85466bad8c574f4a" +uuid = "663a7486-cb36-511b-a19d-713bb74d65c9" +version = "0.9.9" + +[[deps.FriBidi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" +uuid = "559328eb-81f9-559d-9380-de523a88c83c" +version = "1.0.10+0" + +[[deps.Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" + +[[deps.GLM]] +deps = ["Distributions", "LinearAlgebra", "Printf", "Reexport", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "StatsModels"] +git-tree-sha1 = "039118892476c2bf045a43b88fcb75ed566000ff" +uuid = "38e38edf-8417-5370-95a0-9cbb8c7f171a" +version = "1.8.0" + +[[deps.GeoInterface]] +deps = ["Extents"] +git-tree-sha1 = "fb28b5dc239d0174d7297310ef7b84a11804dfab" +uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" +version = "1.0.1" + +[[deps.GeometryBasics]] +deps = ["EarCut_jll", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] +git-tree-sha1 = "12a584db96f1d460421d5fb8860822971cdb8455" +uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +version = "0.4.4" + +[[deps.Gettext_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" +uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" +version = "0.21.0+0" + +[[deps.Glib_jll]] +deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "fb83fbe02fe57f2c068013aa94bcdf6760d3a7a7" +uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" +version = "2.74.0+1" + +[[deps.Graphics]] +deps = ["Colors", "LinearAlgebra", "NaNMath"] +git-tree-sha1 = "d61890399bc535850c4bf08e4e0d3a7ad0f21cbd" +uuid = "a2bd30eb-e257-5431-a919-1863eab51364" +version = "1.1.2" + +[[deps.Graphite2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" +uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" +version = "1.3.14+0" + +[[deps.GridLayoutBase]] +deps = ["GeometryBasics", "InteractiveUtils", "Observables"] +git-tree-sha1 = "678d136003ed5bceaab05cf64519e3f956ffa4ba" +uuid = "3955a311-db13-416c-9275-1d80ed98e5e9" +version = "0.9.1" + +[[deps.Grisu]] +git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" +uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" +version = "1.0.2" + +[[deps.HarfBuzz_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] +git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" +uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" +version = "2.8.1+1" + +[[deps.HypergeometricFunctions]] +deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions", "Test"] +git-tree-sha1 = "709d864e3ed6e3545230601f94e11ebc65994641" +uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" +version = "0.3.11" + +[[deps.ImageCore]] +deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"] +git-tree-sha1 = "acf614720ef026d38400b3817614c45882d75500" +uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534" +version = "0.9.4" + +[[deps.ImageIO]] +deps = ["FileIO", "IndirectArrays", "JpegTurbo", "LazyModules", "Netpbm", "OpenEXR", "PNGFiles", "QOI", "Sixel", "TiffImages", "UUIDs"] +git-tree-sha1 = "342f789fd041a55166764c351da1710db97ce0e0" +uuid = "82e4d734-157c-48bb-816b-45c225c6df19" +version = "0.6.6" + +[[deps.Imath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "87f7662e03a649cffa2e05bf19c303e168732d3e" +uuid = "905a6f67-0a94-5f89-b386-d35d92009cd1" +version = "3.1.2+0" + +[[deps.IndirectArrays]] +git-tree-sha1 = "012e604e1c7458645cb8b436f8fba789a51b257f" +uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959" +version = "1.0.0" + +[[deps.Inflate]] +git-tree-sha1 = "5cd07aab533df5170988219191dfad0519391428" +uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" +version = "0.1.3" + +[[deps.InlineStrings]] +deps = ["Parsers"] +git-tree-sha1 = "d0ca109edbae6b4cc00e751a29dcb15a124053d6" +uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" +version = "1.2.0" + +[[deps.IntelOpenMP_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c" +uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" +version = "2018.0.3+2" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.Interpolations]] +deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] +git-tree-sha1 = "f67b55b6447d36733596aea445a9f119e83498b6" +uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" +version = "0.14.5" + +[[deps.IntervalSets]] +deps = ["Dates", "Random", "Statistics"] +git-tree-sha1 = "3f91cd3f56ea48d4d2a75c2a65455c5fc74fa347" +uuid = "8197267c-284f-5f27-9208-e0e47529a953" +version = "0.7.3" + +[[deps.InverseFunctions]] +deps = ["Test"] +git-tree-sha1 = "49510dfcb407e572524ba94aeae2fced1f3feb0f" +uuid = "3587e190-3f89-42d0-90ee-14403ec27112" +version = "0.1.8" + +[[deps.InvertedIndices]] +git-tree-sha1 = "bee5f1ef5bf65df56bdd2e40447590b272a5471f" +uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" +version = "1.1.0" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.1.1" + +[[deps.Isoband]] +deps = ["isoband_jll"] +git-tree-sha1 = "f9b6d97355599074dc867318950adaa6f9946137" +uuid = "f1662d9f-8043-43de-a69a-05efc1cc6ff4" +version = "0.1.1" + +[[deps.IterTools]] +git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" +uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" +version = "1.4.0" + +[[deps.IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + +[[deps.JLLWrappers]] +deps = ["Preferences"] +git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.4.1" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.3" + +[[deps.JSON3]] +deps = ["Dates", "Mmap", "Parsers", "StructTypes", "UUIDs"] +git-tree-sha1 = "f1572de22c866dc92aea032bc89c2b137cbddd6a" +uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +version = "1.10.0" + +[[deps.JpegTurbo]] +deps = ["CEnum", "FileIO", "ImageCore", "JpegTurbo_jll", "TOML"] +git-tree-sha1 = "a77b273f1ddec645d1b7c4fd5fb98c8f90ad10a5" +uuid = "b835a17e-a41a-41e7-81f0-2f016b05efe0" +version = "0.1.1" + +[[deps.JpegTurbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b53380851c6e6664204efb2e62cd24fa5c47e4ba" +uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" +version = "2.1.2+0" + +[[deps.KernelDensity]] +deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] +git-tree-sha1 = "9816b296736292a80b9a3200eb7fbb57aaa3917a" +uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" +version = "0.6.5" + +[[deps.LAME_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" +uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" +version = "3.100.1+0" + +[[deps.LZO_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" +uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" +version = "2.10.1+0" + +[[deps.LaTeXStrings]] +git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.0" + +[[deps.LazyArtifacts]] +deps = ["Artifacts", "Pkg"] +uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" + +[[deps.LazyModules]] +git-tree-sha1 = "a560dd966b386ac9ae60bdd3a3d3a326062d3c3e" +uuid = "8cdb02fc-e678-4876-92c5-9defec4f444e" +version = "0.3.1" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.3" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "7.84.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.10.2+0" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.Libffi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" +uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" +version = "3.2.2+1" + +[[deps.Libgcrypt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] +git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" +uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" +version = "1.8.7+0" + +[[deps.Libgpg_error_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" +uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" +version = "1.42.0+0" + +[[deps.Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.16.1+1" + +[[deps.Libmount_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" +uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" +version = "2.35.0+0" + +[[deps.Libuuid_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" +uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" +version = "2.36.0+0" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.LogExpFunctions]] +deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "94d9c52ca447e23eac0c0f074effbcd38830deb5" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.18" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.Lz4_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "5d494bc6e85c4c9b626ee0cab05daa4085486ab1" +uuid = "5ced341a-0733-55b8-9ab6-a4889d929147" +version = "1.9.3+0" + +[[deps.MKL_jll]] +deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"] +git-tree-sha1 = "41d162ae9c868218b1f3fe78cba878aa348c2d26" +uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" +version = "2022.1.0+0" + +[[deps.MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.9" + +[[deps.Makie]] +deps = ["Animations", "Base64", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "Distributions", "DocStringExtensions", "FFMPEG", "FileIO", "FixedPointNumbers", "Formatting", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageIO", "IntervalSets", "Isoband", "KernelDensity", "LaTeXStrings", "LinearAlgebra", "MakieCore", "Markdown", "Match", "MathTeXEngine", "Observables", "OffsetArrays", "Packing", "PlotUtils", "PolygonOps", "Printf", "Random", "RelocatableFolders", "Serialization", "Showoff", "SignedDistanceFields", "SparseArrays", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "UnicodeFun"] +git-tree-sha1 = "b0323393a7190c9bf5b03af442fc115756df8e59" +uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" +version = "0.17.13" + +[[deps.MakieCore]] +deps = ["Observables"] +git-tree-sha1 = "fbf705d2bdea8fc93f1ae8ca2965d8e03d4ca98c" +uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b" +version = "0.4.0" + +[[deps.MappedArrays]] +git-tree-sha1 = "e8b359ef06ec72e8c030463fe02efe5527ee5142" +uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900" +version = "0.4.1" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.Match]] +git-tree-sha1 = "1d9bc5c1a6e7ee24effb93f175c9342f9154d97f" +uuid = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf" +version = "1.2.0" + +[[deps.MathOptInterface]] +deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "Printf", "SparseArrays", "SpecialFunctions", "Test", "Unicode"] +git-tree-sha1 = "2284cb18c8670fd5c57ad010ce9bd4e2901692d2" +uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" +version = "1.8.2" + +[[deps.MathProgBase]] +deps = ["LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "9abbe463a1e9fc507f12a69e7f29346c2cdc472c" +uuid = "fdba3010-5040-5b88-9595-932c9decdf73" +version = "0.7.8" + +[[deps.MathTeXEngine]] +deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "Test"] +git-tree-sha1 = "114ef48a73aea632b8aebcb84f796afcc510ac7c" +uuid = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" +version = "0.4.3" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.0+0" + +[[deps.Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.0.2" + +[[deps.MixedModels]] +deps = ["Arrow", "DataAPI", "Distributions", "GLM", "JSON3", "LazyArtifacts", "LinearAlgebra", "Markdown", "NLopt", "PooledArrays", "ProgressMeter", "Random", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "StatsFuns", "StatsModels", "StructTypes", "Tables"] +git-tree-sha1 = "eb09b8b591d0c2e551ef68c30810fd3d1bb7c946" +uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" +version = "4.7.1" + +[[deps.MixedModelsMakie]] +deps = ["DataFrames", "Distributions", "KernelDensity", "LinearAlgebra", "Makie", "MixedModels", "Printf", "SpecialFunctions", "StatsBase"] +git-tree-sha1 = "017733e9b37529e0492974c00480993925a64666" +uuid = "b12ae82c-6730-437f-aff9-d2c38332a376" +version = "0.3.15" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.Mocking]] +deps = ["ExprTools"] +git-tree-sha1 = "748f6e1e4de814b101911e64cc12d83a6af66782" +uuid = "78c3b35d-d492-501b-9361-3d52fe80e533" +version = "0.7.2" + +[[deps.MosaicViews]] +deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"] +git-tree-sha1 = "b34e3bc3ca7c94914418637cb10cc4d1d80d877d" +uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389" +version = "0.3.3" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2022.2.1" + +[[deps.MutableArithmetics]] +deps = ["LinearAlgebra", "SparseArrays", "Test"] +git-tree-sha1 = "4e675d6e9ec02061800d6cfb695812becbd03cdf" +uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" +version = "1.0.4" + +[[deps.NLopt]] +deps = ["MathOptInterface", "MathProgBase", "NLopt_jll"] +git-tree-sha1 = "5a7e32c569200a8a03c3d55d286254b0321cd262" +uuid = "76087f3c-5699-56af-9a33-bf431cd00edd" +version = "0.6.5" + +[[deps.NLopt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9b1f15a08f9d00cdb2761dcfa6f453f5d0d6f973" +uuid = "079eb43e-fd8e-5478-9966-2cf3e3edb778" +version = "2.7.1+0" + +[[deps.NaNMath]] +deps = ["OpenLibm_jll"] +git-tree-sha1 = "a7c3d1da1189a1c2fe843a3bfa04d18d20eb3211" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.0.1" + +[[deps.Netpbm]] +deps = ["FileIO", "ImageCore"] +git-tree-sha1 = "18efc06f6ec36a8b801b23f076e3c6ac7c3bf153" +uuid = "f09324ee-3d7c-5217-9330-fc30815ba969" +version = "1.0.2" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.Observables]] +git-tree-sha1 = "5a9ea4b9430d511980c01e9f7173739595bbd335" +uuid = "510215fc-4207-5dde-b226-833fc4488ee2" +version = "0.5.2" + +[[deps.OffsetArrays]] +deps = ["Adapt"] +git-tree-sha1 = "1ea784113a6aa054c5ebd95945fa5e52c2f378e7" +uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" +version = "1.12.7" + +[[deps.Ogg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" +version = "1.3.5+1" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.20+0" + +[[deps.OpenEXR]] +deps = ["Colors", "FileIO", "OpenEXR_jll"] +git-tree-sha1 = "327f53360fdb54df7ecd01e96ef1983536d1e633" +uuid = "52e1d378-f018-4a11-a4be-720524705ac7" +version = "0.3.2" + +[[deps.OpenEXR_jll]] +deps = ["Artifacts", "Imath_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "923319661e9a22712f24596ce81c54fc0366f304" +uuid = "18a262bb-aa17-5467-a713-aee519bc75cb" +version = "3.1.1+0" + +[[deps.OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.1+0" + +[[deps.OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e60321e3f2616584ff98f0a4f18d98ae6f89bbb3" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "1.1.17+0" + +[[deps.OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.5+0" + +[[deps.Opus_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +uuid = "91d4177d-7536-5919-b921-800302f37372" +version = "1.3.2+0" + +[[deps.OrderedCollections]] +git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.4.1" + +[[deps.PCRE2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" +version = "10.40.0+0" + +[[deps.PDMats]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "cf494dca75a69712a72b80bc48f59dcf3dea63ec" +uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" +version = "0.11.16" + +[[deps.PNGFiles]] +deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"] +git-tree-sha1 = "e925a64b8585aa9f4e3047b8d2cdc3f0e79fd4e4" +uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883" +version = "0.3.16" + +[[deps.Packing]] +deps = ["GeometryBasics"] +git-tree-sha1 = "1155f6f937fa2b94104162f01fa400e192e4272f" +uuid = "19eb6ba3-879d-56ad-ad62-d5c202156566" +version = "0.4.2" + +[[deps.PaddedViews]] +deps = ["OffsetArrays"] +git-tree-sha1 = "03a7a85b76381a3d04c7a1656039197e70eda03d" +uuid = "5432bcbf-9aad-5242-b902-cca2824c8663" +version = "0.5.11" + +[[deps.Pango_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "84a314e3926ba9ec66ac097e3635e270986b0f10" +uuid = "36c8627f-9965-5494-a995-c6b170f724f3" +version = "1.50.9+0" + +[[deps.Parsers]] +deps = ["Dates"] +git-tree-sha1 = "3d5bf43e3e8b412656404ed9466f1dcbf7c50269" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.4.0" + +[[deps.Pixman_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" +uuid = "30392449-352a-5448-841d-b1acce4e97dc" +version = "0.40.1+0" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.8.0" + +[[deps.PkgVersion]] +deps = ["Pkg"] +git-tree-sha1 = "f6cf8e7944e50901594838951729a1861e668cb8" +uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688" +version = "0.3.2" + +[[deps.PlotUtils]] +deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "SnoopPrecompile", "Statistics"] +git-tree-sha1 = "21303256d239f6b484977314674aef4bb1fe4420" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "1.3.1" + +[[deps.PolygonOps]] +git-tree-sha1 = "77b3d3605fc1cd0b42d95eba87dfcd2bf67d5ff6" +uuid = "647866c9-e3ac-4575-94e7-e3d426903924" +version = "0.1.2" + +[[deps.PooledArrays]] +deps = ["DataAPI", "Future"] +git-tree-sha1 = "a6062fe4063cdafe78f4a0a81cfffb89721b30e7" +uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" +version = "1.4.2" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.3.0" + +[[deps.PrettyTables]] +deps = ["Crayons", "Formatting", "Markdown", "Reexport", "StringManipulation", "Tables"] +git-tree-sha1 = "460d9e154365e058c4d886f6f7d6df5ffa1ea80e" +uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" +version = "2.1.2" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.Profile]] +deps = ["Printf"] +uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" + +[[deps.ProgressMeter]] +deps = ["Distributed", "Printf"] +git-tree-sha1 = "d7a7aef8f8f2d537104f170139553b14dfe39fe9" +uuid = "92933f4c-e287-5a05-a399-4b506db050ca" +version = "1.7.2" + +[[deps.QOI]] +deps = ["ColorTypes", "FileIO", "FixedPointNumbers"] +git-tree-sha1 = "18e8f4d1426e965c7b532ddd260599e1510d26ce" +uuid = "4b34888f-f399-49d4-9bb3-47ed5cae4e65" +version = "1.0.0" + +[[deps.QuadGK]] +deps = ["DataStructures", "LinearAlgebra"] +git-tree-sha1 = "3c009334f45dfd546a16a57960a821a1a023d241" +uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" +version = "2.5.0" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA", "Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Ratios]] +deps = ["Requires"] +git-tree-sha1 = "dc84268fe0e3335a62e315a3a7cf2afa7178a734" +uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" +version = "0.4.3" + +[[deps.RecipesBase]] +deps = ["SnoopPrecompile"] +git-tree-sha1 = "612a4d76ad98e9722c8ba387614539155a59e30c" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.3.0" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "22c5201127d7b243b9ee1de3b43c408879dff60f" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "0.3.0" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[deps.Rmath]] +deps = ["Random", "Rmath_jll"] +git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f" +uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" +version = "0.7.0" + +[[deps.Rmath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7" +uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" +version = "0.3.0+0" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.SIMD]] +git-tree-sha1 = "7dbc15af7ed5f751a82bf3ed37757adf76c32402" +uuid = "fdea26ae-647d-5447-a871-4b548cad5224" +version = "3.4.1" + +[[deps.ScanByte]] +deps = ["Libdl", "SIMD"] +git-tree-sha1 = "2436b15f376005e8790e318329560dcc67188e84" +uuid = "7b38b023-a4d7-4c5e-8d43-3f3097f304eb" +version = "0.3.3" + +[[deps.Scratch]] +deps = ["Dates"] +git-tree-sha1 = "f94f779c94e58bf9ea243e77a37e16d9de9126bd" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.1.1" + +[[deps.SentinelArrays]] +deps = ["Dates", "Random"] +git-tree-sha1 = "c0f56940fc967f3d5efed58ba829747af5f8b586" +uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" +version = "1.3.15" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + +[[deps.ShiftedArrays]] +git-tree-sha1 = "503688b59397b3307443af35cd953a13e8005c16" +uuid = "1277b4bf-5013-50f5-be3d-901d8477a67a" +version = "2.0.0" + +[[deps.Showoff]] +deps = ["Dates", "Grisu"] +git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" +uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" +version = "1.0.3" + +[[deps.SignedDistanceFields]] +deps = ["Random", "Statistics", "Test"] +git-tree-sha1 = "d263a08ec505853a5ff1c1ebde2070419e3f28e9" +uuid = "73760f76-fbc4-59ce-8f25-708e95d2df96" +version = "0.4.0" + +[[deps.Sixel]] +deps = ["Dates", "FileIO", "ImageCore", "IndirectArrays", "OffsetArrays", "REPL", "libsixel_jll"] +git-tree-sha1 = "8fb59825be681d451c246a795117f317ecbcaa28" +uuid = "45858cf5-a6b0-47a3-bbea-62219f50df47" +version = "0.1.2" + +[[deps.SnoopPrecompile]] +git-tree-sha1 = "f604441450a3c0569830946e5b33b78c928e1a85" +uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" +version = "1.0.1" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.0.1" + +[[deps.SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[deps.SpecialFunctions]] +deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "d75bda01f8c31ebb72df80a46c88b25d1c79c56d" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.1.7" + +[[deps.StackViews]] +deps = ["OffsetArrays"] +git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c" +uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15" +version = "0.1.1" + +[[deps.StaticArrays]] +deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] +git-tree-sha1 = "f86b3a049e5d05227b10e15dbb315c5b90f14988" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.5.9" + +[[deps.StaticArraysCore]] +git-tree-sha1 = "6b7ba252635a5eff6a0b0664a41ee140a1c9e72a" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.4.0" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[deps.StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "f9af7f195fb13589dd2e2d57fdb401717d2eb1f6" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.5.0" + +[[deps.StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "d1bf48bfcc554a3761a133fe3a9bb01488e06916" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.33.21" + +[[deps.StatsFuns]] +deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] +git-tree-sha1 = "5783b877201a82fc0014cbf381e7e6eb130473a4" +uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +version = "1.0.1" + +[[deps.StatsModels]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Printf", "REPL", "ShiftedArrays", "SparseArrays", "StatsBase", "StatsFuns", "Tables"] +git-tree-sha1 = "a5e15f27abd2692ccb61a99e0854dfb7d48017db" +uuid = "3eaba693-59b7-5ba5-a881-562e759f1c8d" +version = "0.6.33" + +[[deps.StringManipulation]] +git-tree-sha1 = "46da2434b41f41ac3594ee9816ce5541c6096123" +uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" +version = "0.3.0" + +[[deps.StructArrays]] +deps = ["Adapt", "DataAPI", "StaticArraysCore", "Tables"] +git-tree-sha1 = "8c6ac65ec9ab781af05b08ff305ddc727c25f680" +uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +version = "0.6.12" + +[[deps.StructTypes]] +deps = ["Dates", "UUIDs"] +git-tree-sha1 = "ca4bccb03acf9faaf4137a9abc1881ed1841aa70" +uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" +version = "1.10.0" + +[[deps.SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.0" + +[[deps.TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[deps.Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] +git-tree-sha1 = "2d7164f7b8a066bcfa6224e67736ce0eb54aef5b" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.9.0" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.1" + +[[deps.TensorCore]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" +uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" +version = "0.1.1" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.TiffImages]] +deps = ["ColorTypes", "DataStructures", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "Mmap", "OffsetArrays", "PkgVersion", "ProgressMeter", "UUIDs"] +git-tree-sha1 = "70e6d2da9210371c927176cb7a56d41ef1260db7" +uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69" +version = "0.6.1" + +[[deps.TimeZones]] +deps = ["Dates", "Downloads", "InlineStrings", "LazyArtifacts", "Mocking", "Printf", "RecipesBase", "Scratch", "Unicode"] +git-tree-sha1 = "d634a3641062c040fc8a7e2a3ea17661cc159688" +uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53" +version = "1.9.0" + +[[deps.TranscodingStreams]] +deps = ["Random", "Test"] +git-tree-sha1 = "8a75929dcd3c38611db2f8d08546decb514fcadf" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.9.9" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.UnicodeFun]] +deps = ["REPL"] +git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" +uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" +version = "0.4.1" + +[[deps.WeakRefStrings]] +deps = ["DataAPI", "InlineStrings", "Parsers"] +git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" +uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" +version = "1.4.2" + +[[deps.WoodburyMatrices]] +deps = ["LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "de67fa59e33ad156a590055375a30b23c40299d3" +uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" +version = "0.5.5" + +[[deps.XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "58443b63fb7e465a8a7210828c91c08b92132dff" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.9.14+0" + +[[deps.XSLT_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] +git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" +uuid = "aed1982a-8fda-507f-9586-7b0439959a61" +version = "1.1.34+0" + +[[deps.Xorg_libX11_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] +git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" +uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" +version = "1.6.9+4" + +[[deps.Xorg_libXau_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" +uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" +version = "1.0.9+4" + +[[deps.Xorg_libXdmcp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" +uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" +version = "1.1.3+4" + +[[deps.Xorg_libXext_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" +uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" +version = "1.3.4+4" + +[[deps.Xorg_libXrender_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" +uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" +version = "0.9.10+4" + +[[deps.Xorg_libpthread_stubs_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" +uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" +version = "0.1.0+3" + +[[deps.Xorg_libxcb_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] +git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" +uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" +version = "1.13.0+3" + +[[deps.Xorg_xtrans_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" +uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" +version = "1.4.0+3" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.12+3" + +[[deps.Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.2+0" + +[[deps.isoband_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51b5eeb3f98367157a7a12a1fb0aa5328946c03c" +uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4" +version = "0.2.3+0" + +[[deps.libaom_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4" +uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" +version = "3.4.0+0" + +[[deps.libass_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" +uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" +version = "0.15.1+0" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.1.1+0" + +[[deps.libfdk_aac_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" +uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" +version = "2.0.2+0" + +[[deps.libpng_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" +uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" +version = "1.6.38+0" + +[[deps.libsixel_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "libpng_jll"] +git-tree-sha1 = "d4f63314c8aa1e48cd22aa0c17ed76cd1ae48c3c" +uuid = "075b6546-f08a-558a-be8f-8157d0f608a5" +version = "1.10.3+0" + +[[deps.libvorbis_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] +git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" +uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" +version = "1.3.7+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.48.0+0" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+0" + +[[deps.x264_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" +version = "2021.5.5+0" + +[[deps.x265_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" +version = "3.5.0+0" diff --git a/issues/641/Project.toml b/issues/641/Project.toml new file mode 100644 index 000000000..39e2ecdab --- /dev/null +++ b/issues/641/Project.toml @@ -0,0 +1,7 @@ +[deps] +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +MixedModels = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" +MixedModelsMakie = "b12ae82c-6730-437f-aff9-d2c38332a376" diff --git a/issues/641/main.jl b/issues/641/main.jl new file mode 100644 index 000000000..049f0c5a7 --- /dev/null +++ b/issues/641/main.jl @@ -0,0 +1,82 @@ +using CairoMakie +using CSV +using DataFrames +using Downloads +using MixedModels +using MixedModelsMakie + +const CSV_URL = "https://github.com/JuliaStats/MixedModels.jl/files/9659213/web_areas.csv" + +data = CSV.read(Downloads.download(CSV_URL), DataFrame) + +contrasts = Dict(:species => Grouping()) + +form = @formula(web_area ~ 1 + rain + placement + canopy + understory + size + (1|species)) + +fm1 = fit(MixedModel, form, data; contrasts) + +# does look like a bit of heteroskedacity +plot(fitted(fm1), residuals(fm1)) + +form_log = @formula(log(web_area) ~ 1 + rain + placement + canopy + understory + size + (1|species)) + +fm1_log = fit(MixedModel, form_log, data; contrasts) + +# looks much better +plot(fitted(fm1_log), residuals(fm1_log)) + +density(residuals(fm1_log)) + +# looks pretty good +let f = Figure() + ax = Axis(f[1,1]; aspect=1) + scatter!(ax, fitted(fm1_log), response(fm1_log)) + ablines!(ax, 0, 1; linestyle=:dash) + xlims!(ax, -1.4, 3.4) + ylims!(ax, -1.4, 3.4) + f +end + + +# what about sqrt? since we're dealing with areas + +form_sqrt = @formula(sqrt(web_area) ~ 1 + rain + placement + canopy + understory + size + (1 |species)) + +fm1_sqrt = fit(MixedModel, form_sqrt, data; contrasts) + +# not nearly as good as log +plot(fitted(fm1_sqrt), residuals(fm1_sqrt)) + +density(residuals(fm1_sqrt)) + +# doesn't look bad +let f = Figure() + ax = Axis(f[1,1]; aspect=1) + scatter!(ax, fitted(fm1_sqrt), response(fm1_sqrt)) + ablines!(ax, 0, 1; linestyle=:dash) + xlims!(ax, 0, 6) + ylims!(ax, 0, 6) + f +end + +# what about reciprocal/inverse? this often works quite nicely for things where log also works + +form_inv = @formula(1 / web_area ~ 1 + rain + placement + canopy + understory + size + (1|species)) + +fm1_inv = fit(MixedModel, form_inv, data; contrasts) + +# othis actually looks kinda bad +plot(fitted(fm1_inv), residuals(fm1_inv)) + +density(residuals(fm1_inv)) + +# this almost looks like there are other things we're not controlling for +let f = Figure() + ax = Axis(f[1,1]; aspect=1) + scatter!(ax, fitted(fm1_inv), response(fm1_inv)) + ablines!(ax, 0, 1; linestyle=:dash) + f +end + +# one key thing to note here is that there is hole in all the fitted vs. observed plots -- +# I suspect there is some type of jump, maybe between species? From 0ffbaa51e7ffcb4dffb8d64dade95b4bf6c777ab Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 14 Oct 2022 05:13:22 +0000 Subject: [PATCH 15/51] allow predicting from a single observation (#653) * allow predicting from a single observation * NEWS + patch bump * cut even more methods * update news and version for more extensive change * remove more cruft Co-authored-by: Dave Kleinschmidt --- NEWS.md | 5 +++++ Project.toml | 2 +- src/grouping.jl | 10 ++++++---- test/predict.jl | 7 +++++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index e87202392..2b7073d35 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.8.0 Release Notes +============================== +* Allow predicting from a single observation, as long as `Grouping()` is used for the grouping variables. The simplified implementation of `Grouping()` also removes several now unnecessary `StatsModels` methods that should not have been called directly by the user. [#653] + MixedModels v4.7.3 Release Notes ============================== * More informative error message for formulae lacking random effects [#651] @@ -375,3 +379,4 @@ Package dependencies [#637]: https://github.com/JuliaStats/MixedModels.jl/issues/637 [#648]: https://github.com/JuliaStats/MixedModels.jl/issues/648 [#651]: https://github.com/JuliaStats/MixedModels.jl/issues/651 +[#653]: https://github.com/JuliaStats/MixedModels.jl/issues/653 diff --git a/Project.toml b/Project.toml index 192d882aa..548f6f98c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.7.3" +version = "4.8.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/grouping.jl b/src/grouping.jl index 98bcd4367..2f0f49a45 100644 --- a/src/grouping.jl +++ b/src/grouping.jl @@ -21,10 +21,6 @@ julia> schema((; grp = string.(1:100_000)), Dict(:grp => Grouping())) """ struct Grouping <: StatsModels.AbstractContrasts end -# return an empty matrix -StatsModels.contrasts_matrix(::Grouping, baseind, n) = zeros(0, 0) -StatsModels.termnames(::Grouping, levels::AbstractVector, baseind::Integer) = levels - # this is needed until StatsModels stops assuming all contrasts have a .levels field Base.getproperty(g::Grouping, prop::Symbol) = prop == :levels ? nothing : getfield(g, prop) @@ -32,3 +28,9 @@ Base.getproperty(g::Grouping, prop::Symbol) = prop == :levels ? nothing : getfie function StatsModels.modelcols(::CategoricalTerm{Grouping}, d::NamedTuple) return error("can't create model columns directly from a Grouping term") end + +function StatsModels.ContrastsMatrix( + contrasts::Grouping, levels::AbstractVector +) + return StatsModels.ContrastsMatrix(zeros(0, 0), levels, levels, contrasts) +end diff --git a/test/predict.jl b/test/predict.jl index 466828dd2..fce35b982 100644 --- a/test/predict.jl +++ b/test/predict.jl @@ -47,6 +47,13 @@ include("modelcache.jl") end @testset "predict" begin + + @testset "single obs" begin + kb07 = DataFrame(dataset(:kb07)) + m = models(:kb07)[1] + only(predict(m, kb07[1:1, :])) ≈ first(fitted(m)) + end + slp = DataFrame(dataset(:sleepstudy)) slp2 = transform(slp, :subj => ByRow(x -> (x == "S308" ? "NEW" : x)) => :subj) slpm = allowmissing(slp, :reaction) From a9c774cb9054ad8089d9cd897dda219ce4de19d6 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 18 Oct 2022 18:04:54 +0000 Subject: [PATCH 16/51] Update CI concurrency to take advantage of "new" GHA features (#655) * update CI for GHA concurrency options * try something from GH docs --- .github/workflows/MKL.yml | 3 +++ .github/workflows/ci.yml | 8 +++----- .github/workflows/documenter.yml | 8 +++----- .github/workflows/lts.yml | 8 +++----- .github/workflows/nightly.yml | 8 +++----- .github/workflows/style.yml | 3 +++ 6 files changed, 18 insertions(+), 20 deletions(-) diff --git a/.github/workflows/MKL.yml b/.github/workflows/MKL.yml index b8f38b191..8652ad932 100644 --- a/.github/workflows/MKL.yml +++ b/.github/workflows/MKL.yml @@ -1,4 +1,7 @@ name: MKL +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true on: workflow_dispatch: jobs: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d1692974..a8106344c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,7 @@ name: current release +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true on: push: branches: @@ -21,11 +24,6 @@ jobs: julia-arch: [x64] os: [ubuntu-18.04] steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.9.1 - with: - all_but_latest: true - access_token: ${{ github.token }} - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 with: diff --git a/.github/workflows/documenter.yml b/.github/workflows/documenter.yml index 2256bf99c..03ec3b620 100644 --- a/.github/workflows/documenter.yml +++ b/.github/workflows/documenter.yml @@ -1,4 +1,7 @@ name: Documenter +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true on: push: branches: [main] @@ -18,11 +21,6 @@ jobs: name: Documentation runs-on: ubuntu-20.04 steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.9.1 - with: - all_but_latest: true - access_token: ${{ github.token }} - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 with: diff --git a/.github/workflows/lts.yml b/.github/workflows/lts.yml index 68aa62953..6d1cce8f2 100644 --- a/.github/workflows/lts.yml +++ b/.github/workflows/lts.yml @@ -1,4 +1,7 @@ name: LTS +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true on: push: branches: @@ -21,11 +24,6 @@ jobs: julia-arch: [x64] os: [ubuntu-18.04, macos-10.15, windows-2019] steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.9.1 - with: - all_but_latest: true - access_token: ${{ github.token }} - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 with: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index f05e1f3f0..b64189770 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -1,4 +1,7 @@ name: nightly +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true on: push: branches: @@ -21,11 +24,6 @@ jobs: julia-arch: [x64] os: [ubuntu-18.04] steps: - - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@0.9.1 - with: - all_but_latest: true - access_token: ${{ github.token }} - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 with: diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 3fe35d9ce..b671568fa 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -1,4 +1,7 @@ name: Style-Enforcer +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true on: push: branches: From 4abda3e9c4c132184951a9584e4284242511e9e9 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Thu, 20 Oct 2022 15:05:41 +0000 Subject: [PATCH 17/51] more tinkering on 638 (#654) * more tinkering on 638 * make it work like lme4 --- issues/638/Manifest.toml | 738 ++++++++++++++++++++++++++++++++++++++- issues/638/Project.toml | 2 + issues/638/main.jl | 62 ++++ src/linearmixedmodel.jl | 4 +- src/remat.jl | 12 +- 5 files changed, 807 insertions(+), 11 deletions(-) diff --git a/issues/638/Manifest.toml b/issues/638/Manifest.toml index 9fdcf5991..a6110c715 100644 --- a/issues/638/Manifest.toml +++ b/issues/638/Manifest.toml @@ -1,5 +1,28 @@ # This file is machine-generated - editing it directly is not advised +[[AbstractFFTs]] +deps = ["ChainRulesCore", "LinearAlgebra"] +git-tree-sha1 = "69f7020bd72f069c219b5e8c236c1fa90d2cb409" +uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" +version = "1.2.1" + +[[AbstractTrees]] +git-tree-sha1 = "5c0b629df8a5566a06f5fef5100b53ea56e465a0" +uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" +version = "0.4.2" + +[[Adapt]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "195c5505521008abea5aee4f96930717958eac6f" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "3.4.0" + +[[Animations]] +deps = ["Colors"] +git-tree-sha1 = "e81c509d2c8e49592413bfb0bb3b08150056c79d" +uuid = "27a7e980-b3e6-11e9-2bcd-0b925532e340" +version = "0.4.1" + [[ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" version = "1.1.1" @@ -19,6 +42,18 @@ version = "1.2.1" [[Artifacts]] uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" +[[Automa]] +deps = ["Printf", "ScanByte", "TranscodingStreams"] +git-tree-sha1 = "d50976f217489ce799e366d9561d56a98a30d7fe" +uuid = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b" +version = "0.8.2" + +[[AxisAlgorithms]] +deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] +git-tree-sha1 = "66771c8d21c8ff5e3a93379480a2307ac36863f7" +uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" +version = "1.0.1" + [[Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" @@ -51,6 +86,24 @@ git-tree-sha1 = "873fb188a4b9d76549b81465b1f75c82aaf59238" uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" version = "0.10.4" +[[Cairo]] +deps = ["Cairo_jll", "Colors", "Glib_jll", "Graphics", "Libdl", "Pango_jll"] +git-tree-sha1 = "d0b3f8b4ad16cb0a2988c6788646a5e6a17b6b1b" +uuid = "159f3aea-2a34-519c-b102-8c37f9878175" +version = "1.0.5" + +[[CairoMakie]] +deps = ["Base64", "Cairo", "Colors", "FFTW", "FileIO", "FreeType", "GeometryBasics", "LinearAlgebra", "Makie", "SHA", "SnoopPrecompile"] +git-tree-sha1 = "f53b586e9489163ece213144a5a6417742f0388e" +uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +version = "0.9.0" + +[[Cairo_jll]] +deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" +uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" +version = "1.16.1+1" + [[Calculus]] deps = ["LinearAlgebra"] git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" @@ -93,6 +146,36 @@ git-tree-sha1 = "849470b337d0fa8449c21061de922386f32949d9" uuid = "6b39b394-51ab-5f42-8807-6242bab2b4c2" version = "0.7.2" +[[ColorBrewer]] +deps = ["Colors", "JSON", "Test"] +git-tree-sha1 = "61c5334f33d91e570e1d0c3eb5465835242582c4" +uuid = "a2cac450-b92f-5266-8821-25eda20663c8" +version = "0.4.0" + +[[ColorSchemes]] +deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Random"] +git-tree-sha1 = "1fd869cc3875b57347f7027521f561cf46d1fcd8" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.19.0" + +[[ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.4" + +[[ColorVectorSpace]] +deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] +git-tree-sha1 = "d08c20eef1f2cbc6e60fd3612ac4340b89fea322" +uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" +version = "0.9.9" + +[[Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.8" + [[CommonSubexpressions]] deps = ["MacroTools", "Test"] git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" @@ -110,6 +193,11 @@ deps = ["Artifacts", "Libdl"] uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" version = "0.5.2+0" +[[Contour]] +git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781" +uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" +version = "0.6.2" + [[Crayons]] git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" @@ -186,11 +274,58 @@ git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" version = "0.6.8" +[[EarCut_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e3290f2d49e661fbd94046d7e3726ffcb2d41053" +uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" +version = "2.2.4+0" + +[[Expat_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bad72f730e9e91c08d9427d5e8db95478a3c323d" +uuid = "2e619515-83b5-522b-bb60-26c02a35a201" +version = "2.4.8+0" + [[ExprTools]] git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d" uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" version = "0.1.8" +[[Extents]] +git-tree-sha1 = "5e1e4c53fa39afe63a7d356e30452249365fba99" +uuid = "411431e0-e8b7-467b-b5e0-f676ba4f2910" +version = "0.1.1" + +[[FFMPEG]] +deps = ["FFMPEG_jll"] +git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" +version = "0.4.1" + +[[FFMPEG_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Pkg", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "74faea50c1d007c85837327f6775bea60b5492dd" +uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" +version = "4.4.2+2" + +[[FFTW]] +deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] +git-tree-sha1 = "90630efff0894f8142308e334473eba54c433549" +uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" +version = "1.5.0" + +[[FFTW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea" +uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" +version = "3.3.10+0" + +[[FileIO]] +deps = ["Pkg", "Requires", "UUIDs"] +git-tree-sha1 = "7be5f99f7d15578798f338f5433b6c432ea8037b" +uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +version = "1.16.0" + [[FilePathsBase]] deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"] git-tree-sha1 = "e27c4ebe80e8699540f2d6c805cc12203b614f12" @@ -206,6 +341,18 @@ git-tree-sha1 = "87519eb762f85534445f5cda35be12e32759ee14" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" version = "0.13.4" +[[FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[Fontconfig_jll]] +deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" +uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" +version = "2.13.93+0" + [[Formatting]] deps = ["Printf"] git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" @@ -218,6 +365,30 @@ git-tree-sha1 = "187198a4ed8ccd7b5d99c41b69c679269ea2b2d4" uuid = "f6369f11-7733-5829-9624-2563aa707210" version = "0.10.32" +[[FreeType]] +deps = ["CEnum", "FreeType2_jll"] +git-tree-sha1 = "cabd77ab6a6fdff49bfd24af2ebe76e6e018a2b4" +uuid = "b38be410-82b0-50bf-ab77-7b57e271db43" +version = "4.0.0" + +[[FreeType2_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" +uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" +version = "2.10.4+0" + +[[FreeTypeAbstraction]] +deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics"] +git-tree-sha1 = "38a92e40157100e796690421e34a11c107205c86" +uuid = "663a7486-cb36-511b-a19d-713bb74d65c9" +version = "0.10.0" + +[[FriBidi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" +uuid = "559328eb-81f9-559d-9380-de523a88c83c" +version = "1.0.10+0" + [[Future]] deps = ["Random"] uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" @@ -228,22 +399,121 @@ git-tree-sha1 = "039118892476c2bf045a43b88fcb75ed566000ff" uuid = "38e38edf-8417-5370-95a0-9cbb8c7f171a" version = "1.8.0" +[[GeoInterface]] +deps = ["Extents"] +git-tree-sha1 = "fb28b5dc239d0174d7297310ef7b84a11804dfab" +uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" +version = "1.0.1" + +[[GeometryBasics]] +deps = ["EarCut_jll", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] +git-tree-sha1 = "12a584db96f1d460421d5fb8860822971cdb8455" +uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +version = "0.4.4" + +[[Gettext_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" +uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" +version = "0.21.0+0" + +[[Glib_jll]] +deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "fb83fbe02fe57f2c068013aa94bcdf6760d3a7a7" +uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" +version = "2.74.0+1" + +[[Graphics]] +deps = ["Colors", "LinearAlgebra", "NaNMath"] +git-tree-sha1 = "d61890399bc535850c4bf08e4e0d3a7ad0f21cbd" +uuid = "a2bd30eb-e257-5431-a919-1863eab51364" +version = "1.1.2" + +[[Graphite2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" +uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" +version = "1.3.14+0" + +[[GridLayoutBase]] +deps = ["GeometryBasics", "InteractiveUtils", "Observables"] +git-tree-sha1 = "678d136003ed5bceaab05cf64519e3f956ffa4ba" +uuid = "3955a311-db13-416c-9275-1d80ed98e5e9" +version = "0.9.1" + +[[Grisu]] +git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" +uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" +version = "1.0.2" + +[[HarfBuzz_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] +git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" +uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" +version = "2.8.1+1" + [[HypergeometricFunctions]] deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions", "Test"] git-tree-sha1 = "709d864e3ed6e3545230601f94e11ebc65994641" uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" version = "0.3.11" +[[ImageCore]] +deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"] +git-tree-sha1 = "acf614720ef026d38400b3817614c45882d75500" +uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534" +version = "0.9.4" + +[[ImageIO]] +deps = ["FileIO", "IndirectArrays", "JpegTurbo", "LazyModules", "Netpbm", "OpenEXR", "PNGFiles", "QOI", "Sixel", "TiffImages", "UUIDs"] +git-tree-sha1 = "342f789fd041a55166764c351da1710db97ce0e0" +uuid = "82e4d734-157c-48bb-816b-45c225c6df19" +version = "0.6.6" + +[[Imath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "87f7662e03a649cffa2e05bf19c303e168732d3e" +uuid = "905a6f67-0a94-5f89-b386-d35d92009cd1" +version = "3.1.2+0" + +[[IndirectArrays]] +git-tree-sha1 = "012e604e1c7458645cb8b436f8fba789a51b257f" +uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959" +version = "1.0.0" + +[[Inflate]] +git-tree-sha1 = "5cd07aab533df5170988219191dfad0519391428" +uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" +version = "0.1.3" + [[InlineStrings]] deps = ["Parsers"] git-tree-sha1 = "d0ca109edbae6b4cc00e751a29dcb15a124053d6" uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" version = "1.2.0" +[[IntelOpenMP_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c" +uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" +version = "2018.0.3+2" + [[InteractiveUtils]] deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +[[Interpolations]] +deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] +git-tree-sha1 = "842dd89a6cb75e02e85fdd75c760cdc43f5d6863" +uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" +version = "0.14.6" + +[[IntervalSets]] +deps = ["Dates", "Random", "Statistics"] +git-tree-sha1 = "3f91cd3f56ea48d4d2a75c2a65455c5fc74fa347" +uuid = "8197267c-284f-5f27-9208-e0e47529a953" +version = "0.7.3" + [[InverseFunctions]] deps = ["Test"] git-tree-sha1 = "49510dfcb407e572524ba94aeae2fced1f3feb0f" @@ -260,6 +530,17 @@ git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" version = "0.1.1" +[[Isoband]] +deps = ["isoband_jll"] +git-tree-sha1 = "f9b6d97355599074dc867318950adaa6f9946137" +uuid = "f1662d9f-8043-43de-a69a-05efc1cc6ff4" +version = "0.1.1" + +[[IterTools]] +git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" +uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" +version = "1.4.0" + [[IteratorInterfaceExtensions]] git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" uuid = "82899510-4779-5014-852e-03e436cf321d" @@ -283,10 +564,50 @@ git-tree-sha1 = "f1572de22c866dc92aea032bc89c2b137cbddd6a" uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" version = "1.10.0" +[[JpegTurbo]] +deps = ["CEnum", "FileIO", "ImageCore", "JpegTurbo_jll", "TOML"] +git-tree-sha1 = "a77b273f1ddec645d1b7c4fd5fb98c8f90ad10a5" +uuid = "b835a17e-a41a-41e7-81f0-2f016b05efe0" +version = "0.1.1" + +[[JpegTurbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b53380851c6e6664204efb2e62cd24fa5c47e4ba" +uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" +version = "2.1.2+0" + +[[KernelDensity]] +deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] +git-tree-sha1 = "9816b296736292a80b9a3200eb7fbb57aaa3917a" +uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" +version = "0.6.5" + +[[LAME_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" +uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" +version = "3.100.1+0" + +[[LZO_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" +uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" +version = "2.10.1+0" + +[[LaTeXStrings]] +git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.0" + [[LazyArtifacts]] deps = ["Artifacts", "Pkg"] uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" +[[LazyModules]] +git-tree-sha1 = "a560dd966b386ac9ae60bdd3a3d3a326062d3c3e" +uuid = "8cdb02fc-e678-4876-92c5-9defec4f444e" +version = "0.3.1" + [[LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" @@ -309,6 +630,42 @@ version = "1.10.2+0" [[Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +[[Libffi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" +uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" +version = "3.2.2+1" + +[[Libgcrypt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] +git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" +uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" +version = "1.8.7+0" + +[[Libgpg_error_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" +uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" +version = "1.42.0+0" + +[[Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.16.1+1" + +[[Libmount_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" +uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" +version = "2.35.0+0" + +[[Libuuid_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" +uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" +version = "2.36.0+0" + [[LinearAlgebra]] deps = ["Libdl", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -328,16 +685,44 @@ git-tree-sha1 = "5d494bc6e85c4c9b626ee0cab05daa4085486ab1" uuid = "5ced341a-0733-55b8-9ab6-a4889d929147" version = "1.9.3+0" +[[MKL_jll]] +deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"] +git-tree-sha1 = "2ce8695e1e699b68702c03402672a69f54b8aca9" +uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" +version = "2022.2.0+0" + [[MacroTools]] deps = ["Markdown", "Random"] git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" version = "0.5.9" +[[Makie]] +deps = ["Animations", "Base64", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "Distributions", "DocStringExtensions", "FFMPEG", "FileIO", "FixedPointNumbers", "Formatting", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageIO", "InteractiveUtils", "IntervalSets", "Isoband", "KernelDensity", "LaTeXStrings", "LinearAlgebra", "MakieCore", "Markdown", "Match", "MathTeXEngine", "MiniQhull", "Observables", "OffsetArrays", "Packing", "PlotUtils", "PolygonOps", "Printf", "Random", "RelocatableFolders", "Serialization", "Showoff", "SignedDistanceFields", "SnoopPrecompile", "SparseArrays", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "TriplotBase", "UnicodeFun"] +git-tree-sha1 = "51e40869d076fbff25ab61d0aa3e198d80176c75" +uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" +version = "0.18.0" + +[[MakieCore]] +deps = ["Observables"] +git-tree-sha1 = "b87650f61f85fc2d4fb5923a479dbf05ba65ae4d" +uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b" +version = "0.5.0" + +[[MappedArrays]] +git-tree-sha1 = "e8b359ef06ec72e8c030463fe02efe5527ee5142" +uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900" +version = "0.4.1" + [[Markdown]] deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +[[Match]] +git-tree-sha1 = "1d9bc5c1a6e7ee24effb93f175c9342f9154d97f" +uuid = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf" +version = "1.2.0" + [[MathOptInterface]] deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "Printf", "SparseArrays", "SpecialFunctions", "Test", "Unicode"] git-tree-sha1 = "2284cb18c8670fd5c57ad010ce9bd4e2901692d2" @@ -350,11 +735,23 @@ git-tree-sha1 = "9abbe463a1e9fc507f12a69e7f29346c2cdc472c" uuid = "fdba3010-5040-5b88-9595-932c9decdf73" version = "0.7.8" +[[MathTeXEngine]] +deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "Test", "UnicodeFun"] +git-tree-sha1 = "7f837e1884f1ef84984c919fc7a00638cff1e6d1" +uuid = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" +version = "0.5.3" + [[MbedTLS_jll]] deps = ["Artifacts", "Libdl"] uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" version = "2.28.0+0" +[[MiniQhull]] +deps = ["QhullMiniWrapper_jll"] +git-tree-sha1 = "9dc837d180ee49eeb7c8b77bb1c860452634b0d1" +uuid = "978d7f02-9e05-4691-894f-ae31a51d76ca" +version = "0.4.0" + [[Missings]] deps = ["DataAPI"] git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" @@ -362,10 +759,16 @@ uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" version = "1.0.2" [[MixedModels]] -deps = ["Arrow", "DataAPI", "Distributions", "GLM", "JSON3", "LazyArtifacts", "LinearAlgebra", "Markdown", "NLopt", "PooledArrays", "ProgressMeter", "Random", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "StatsFuns", "StatsModels", "StructTypes", "Tables"] -git-tree-sha1 = "eb09b8b591d0c2e551ef68c30810fd3d1bb7c946" +deps = ["Arrow", "DataAPI", "Distributions", "GLM", "JSON3", "LazyArtifacts", "LinearAlgebra", "Markdown", "NLopt", "PooledArrays", "ProgressMeter", "Random", "SparseArrays", "StaticArrays", "Statistics", "StatsAPI", "StatsBase", "StatsFuns", "StatsModels", "StructTypes", "Tables"] +git-tree-sha1 = "31538466936a03a860d192d8db7bd1edb2179a91" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" -version = "4.7.1" +version = "4.8.0" + +[[MixedModelsMakie]] +deps = ["DataFrames", "Distributions", "KernelDensity", "LinearAlgebra", "Makie", "MixedModels", "Printf", "SpecialFunctions", "StatsBase"] +git-tree-sha1 = "adb722b6cc9f61731f7835b967ce683ea366b1f5" +uuid = "b12ae82c-6730-437f-aff9-d2c38332a376" +version = "0.3.17" [[Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" @@ -376,6 +779,12 @@ git-tree-sha1 = "748f6e1e4de814b101911e64cc12d83a6af66782" uuid = "78c3b35d-d492-501b-9361-3d52fe80e533" version = "0.7.2" +[[MosaicViews]] +deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"] +git-tree-sha1 = "b34e3bc3ca7c94914418637cb10cc4d1d80d877d" +uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389" +version = "0.3.3" + [[MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" version = "2022.2.1" @@ -404,48 +813,147 @@ git-tree-sha1 = "a7c3d1da1189a1c2fe843a3bfa04d18d20eb3211" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" version = "1.0.1" +[[Netpbm]] +deps = ["FileIO", "ImageCore"] +git-tree-sha1 = "18efc06f6ec36a8b801b23f076e3c6ac7c3bf153" +uuid = "f09324ee-3d7c-5217-9330-fc30815ba969" +version = "1.0.2" + [[NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" version = "1.2.0" +[[Observables]] +git-tree-sha1 = "5a9ea4b9430d511980c01e9f7173739595bbd335" +uuid = "510215fc-4207-5dde-b226-833fc4488ee2" +version = "0.5.2" + +[[OffsetArrays]] +deps = ["Adapt"] +git-tree-sha1 = "f71d8950b724e9ff6110fc948dff5a329f901d64" +uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" +version = "1.12.8" + +[[Ogg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" +version = "1.3.5+1" + [[OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" version = "0.3.20+0" +[[OpenEXR]] +deps = ["Colors", "FileIO", "OpenEXR_jll"] +git-tree-sha1 = "327f53360fdb54df7ecd01e96ef1983536d1e633" +uuid = "52e1d378-f018-4a11-a4be-720524705ac7" +version = "0.3.2" + +[[OpenEXR_jll]] +deps = ["Artifacts", "Imath_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "923319661e9a22712f24596ce81c54fc0366f304" +uuid = "18a262bb-aa17-5467-a713-aee519bc75cb" +version = "3.1.1+0" + [[OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" version = "0.8.1+0" +[[OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e60321e3f2616584ff98f0a4f18d98ae6f89bbb3" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "1.1.17+0" + [[OpenSpecFun_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" version = "0.5.5+0" +[[Opus_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +uuid = "91d4177d-7536-5919-b921-800302f37372" +version = "1.3.2+0" + [[OrderedCollections]] git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.4.1" +[[PCRE2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" +version = "10.40.0+0" + [[PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] git-tree-sha1 = "cf494dca75a69712a72b80bc48f59dcf3dea63ec" uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" version = "0.11.16" +[[PNGFiles]] +deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"] +git-tree-sha1 = "f809158b27eba0c18c269cf2a2be6ed751d3e81d" +uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883" +version = "0.3.17" + +[[Packing]] +deps = ["GeometryBasics"] +git-tree-sha1 = "1155f6f937fa2b94104162f01fa400e192e4272f" +uuid = "19eb6ba3-879d-56ad-ad62-d5c202156566" +version = "0.4.2" + +[[PaddedViews]] +deps = ["OffsetArrays"] +git-tree-sha1 = "03a7a85b76381a3d04c7a1656039197e70eda03d" +uuid = "5432bcbf-9aad-5242-b902-cca2824c8663" +version = "0.5.11" + +[[Pango_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "84a314e3926ba9ec66ac097e3635e270986b0f10" +uuid = "36c8627f-9965-5494-a995-c6b170f724f3" +version = "1.50.9+0" + [[Parsers]] deps = ["Dates"] git-tree-sha1 = "3d5bf43e3e8b412656404ed9466f1dcbf7c50269" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" version = "2.4.0" +[[Pixman_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" +uuid = "30392449-352a-5448-841d-b1acce4e97dc" +version = "0.40.1+0" + [[Pkg]] deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" version = "1.8.0" +[[PkgVersion]] +deps = ["Pkg"] +git-tree-sha1 = "f6cf8e7944e50901594838951729a1861e668cb8" +uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688" +version = "0.3.2" + +[[PlotUtils]] +deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "SnoopPrecompile", "Statistics"] +git-tree-sha1 = "21303256d239f6b484977314674aef4bb1fe4420" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "1.3.1" + +[[PolygonOps]] +git-tree-sha1 = "77b3d3605fc1cd0b42d95eba87dfcd2bf67d5ff6" +uuid = "647866c9-e3ac-4575-94e7-e3d426903924" +version = "0.1.2" + [[PooledArrays]] deps = ["DataAPI", "Future"] git-tree-sha1 = "a6062fe4063cdafe78f4a0a81cfffb89721b30e7" @@ -478,6 +986,24 @@ git-tree-sha1 = "d7a7aef8f8f2d537104f170139553b14dfe39fe9" uuid = "92933f4c-e287-5a05-a399-4b506db050ca" version = "1.7.2" +[[QOI]] +deps = ["ColorTypes", "FileIO", "FixedPointNumbers"] +git-tree-sha1 = "18e8f4d1426e965c7b532ddd260599e1510d26ce" +uuid = "4b34888f-f399-49d4-9bb3-47ed5cae4e65" +version = "1.0.0" + +[[QhullMiniWrapper_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Qhull_jll"] +git-tree-sha1 = "607cf73c03f8a9f83b36db0b86a3a9c14179621f" +uuid = "460c41e3-6112-5d7f-b78c-b6823adb3f2d" +version = "1.0.0+1" + +[[Qhull_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "695c3049ad94fa38b7f1e8243cdcee27ecad0867" +uuid = "784f63db-0788-585a-bace-daefebcd302b" +version = "8.0.1000+0" + [[QuadGK]] deps = ["DataStructures", "LinearAlgebra"] git-tree-sha1 = "3c009334f45dfd546a16a57960a821a1a023d241" @@ -492,6 +1018,12 @@ uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" deps = ["SHA", "Serialization"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +[[Ratios]] +deps = ["Requires"] +git-tree-sha1 = "dc84268fe0e3335a62e315a3a7cf2afa7178a734" +uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" +version = "0.4.3" + [[RecipesBase]] deps = ["SnoopPrecompile"] git-tree-sha1 = "612a4d76ad98e9722c8ba387614539155a59e30c" @@ -503,6 +1035,18 @@ git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" uuid = "189a3867-3050-52da-a836-e630ba90ab69" version = "1.2.2" +[[RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "90bc7a7c96410424509e4263e277e43250c05691" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "1.0.0" + +[[Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + [[Rmath]] deps = ["Random", "Rmath_jll"] git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f" @@ -519,6 +1063,17 @@ version = "0.3.0+0" uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" version = "0.7.0" +[[SIMD]] +git-tree-sha1 = "7dbc15af7ed5f751a82bf3ed37757adf76c32402" +uuid = "fdea26ae-647d-5447-a871-4b548cad5224" +version = "3.4.1" + +[[ScanByte]] +deps = ["Libdl", "SIMD"] +git-tree-sha1 = "2436b15f376005e8790e318329560dcc67188e84" +uuid = "7b38b023-a4d7-4c5e-8d43-3f3097f304eb" +version = "0.3.3" + [[Scratch]] deps = ["Dates"] git-tree-sha1 = "f94f779c94e58bf9ea243e77a37e16d9de9126bd" @@ -534,11 +1089,33 @@ version = "1.3.15" [[Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +[[SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + [[ShiftedArrays]] git-tree-sha1 = "503688b59397b3307443af35cd953a13e8005c16" uuid = "1277b4bf-5013-50f5-be3d-901d8477a67a" version = "2.0.0" +[[Showoff]] +deps = ["Dates", "Grisu"] +git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" +uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" +version = "1.0.3" + +[[SignedDistanceFields]] +deps = ["Random", "Statistics", "Test"] +git-tree-sha1 = "d263a08ec505853a5ff1c1ebde2070419e3f28e9" +uuid = "73760f76-fbc4-59ce-8f25-708e95d2df96" +version = "0.4.0" + +[[Sixel]] +deps = ["Dates", "FileIO", "ImageCore", "IndirectArrays", "OffsetArrays", "REPL", "libsixel_jll"] +git-tree-sha1 = "8fb59825be681d451c246a795117f317ecbcaa28" +uuid = "45858cf5-a6b0-47a3-bbea-62219f50df47" +version = "0.1.2" + [[SnoopPrecompile]] git-tree-sha1 = "f604441450a3c0569830946e5b33b78c928e1a85" uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" @@ -563,6 +1140,12 @@ git-tree-sha1 = "d75bda01f8c31ebb72df80a46c88b25d1c79c56d" uuid = "276daf66-3868-5448-9aa4-cd146d93841b" version = "2.1.7" +[[StackViews]] +deps = ["OffsetArrays"] +git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c" +uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15" +version = "0.1.1" + [[StaticArrays]] deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] git-tree-sha1 = "f86b3a049e5d05227b10e15dbb315c5b90f14988" @@ -607,6 +1190,12 @@ git-tree-sha1 = "46da2434b41f41ac3594ee9816ce5541c6096123" uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" version = "0.3.0" +[[StructArrays]] +deps = ["Adapt", "DataAPI", "StaticArraysCore", "Tables"] +git-tree-sha1 = "8c6ac65ec9ab781af05b08ff305ddc727c25f680" +uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +version = "0.6.12" + [[StructTypes]] deps = ["Dates", "UUIDs"] git-tree-sha1 = "ca4bccb03acf9faaf4137a9abc1881ed1841aa70" @@ -639,10 +1228,22 @@ deps = ["ArgTools", "SHA"] uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" version = "1.10.1" +[[TensorCore]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" +uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" +version = "0.1.1" + [[Test]] deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[[TiffImages]] +deps = ["ColorTypes", "DataStructures", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "Mmap", "OffsetArrays", "PkgVersion", "ProgressMeter", "UUIDs"] +git-tree-sha1 = "70e6d2da9210371c927176cb7a56d41ef1260db7" +uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69" +version = "0.6.1" + [[TimeZones]] deps = ["Dates", "Downloads", "InlineStrings", "LazyArtifacts", "Mocking", "Printf", "RecipesBase", "Scratch", "Unicode"] git-tree-sha1 = "d634a3641062c040fc8a7e2a3ea17661cc159688" @@ -655,6 +1256,11 @@ git-tree-sha1 = "8a75929dcd3c38611db2f8d08546decb514fcadf" uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" version = "0.9.9" +[[TriplotBase]] +git-tree-sha1 = "4d4ed7f294cda19382ff7de4c137d24d16adc89b" +uuid = "981d1d27-644d-49a2-9326-4793e63143c3" +version = "0.1.0" + [[UUIDs]] deps = ["Random", "SHA"] uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" @@ -662,12 +1268,84 @@ uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [[Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" +[[UnicodeFun]] +deps = ["REPL"] +git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" +uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" +version = "0.4.1" + [[WeakRefStrings]] deps = ["DataAPI", "InlineStrings", "Parsers"] git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" version = "1.4.2" +[[WoodburyMatrices]] +deps = ["LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "de67fa59e33ad156a590055375a30b23c40299d3" +uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" +version = "0.5.5" + +[[XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "58443b63fb7e465a8a7210828c91c08b92132dff" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.9.14+0" + +[[XSLT_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] +git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" +uuid = "aed1982a-8fda-507f-9586-7b0439959a61" +version = "1.1.34+0" + +[[Xorg_libX11_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] +git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" +uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" +version = "1.6.9+4" + +[[Xorg_libXau_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" +uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" +version = "1.0.9+4" + +[[Xorg_libXdmcp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" +uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" +version = "1.1.3+4" + +[[Xorg_libXext_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" +uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" +version = "1.3.4+4" + +[[Xorg_libXrender_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" +uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" +version = "0.9.10+4" + +[[Xorg_libpthread_stubs_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" +uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" +version = "0.1.0+3" + +[[Xorg_libxcb_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] +git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" +uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" +version = "1.13.0+3" + +[[Xorg_xtrans_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" +uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" +version = "1.4.0+3" + [[Zlib_jll]] deps = ["Libdl"] uuid = "83775a58-1f1d-513f-b197-d71354ab007a" @@ -679,11 +1357,53 @@ git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" version = "1.5.2+0" +[[isoband_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51b5eeb3f98367157a7a12a1fb0aa5328946c03c" +uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4" +version = "0.2.3+0" + +[[libaom_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4" +uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" +version = "3.4.0+0" + +[[libass_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" +uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" +version = "0.15.1+0" + [[libblastrampoline_jll]] deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" version = "5.1.1+0" +[[libfdk_aac_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" +uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" +version = "2.0.2+0" + +[[libpng_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" +uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" +version = "1.6.38+0" + +[[libsixel_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "libpng_jll"] +git-tree-sha1 = "d4f63314c8aa1e48cd22aa0c17ed76cd1ae48c3c" +uuid = "075b6546-f08a-558a-be8f-8157d0f608a5" +version = "1.10.3+0" + +[[libvorbis_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] +git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" +uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" +version = "1.3.7+1" + [[nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" @@ -693,3 +1413,15 @@ version = "1.48.0+0" deps = ["Artifacts", "Libdl"] uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" version = "17.4.0+0" + +[[x264_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" +version = "2021.5.5+0" + +[[x265_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" +version = "3.5.0+0" diff --git a/issues/638/Project.toml b/issues/638/Project.toml index f4bf0e09d..ba2a61482 100644 --- a/issues/638/Project.toml +++ b/issues/638/Project.toml @@ -1,9 +1,11 @@ [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a" MixedModels = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" +MixedModelsMakie = "b12ae82c-6730-437f-aff9-d2c38332a376" [compat] MixedModels = "4" diff --git a/issues/638/main.jl b/issues/638/main.jl index 08856d421..61ea6c682 100644 --- a/issues/638/main.jl +++ b/issues/638/main.jl @@ -129,3 +129,65 @@ slopes_form = @formula(y ~ 0 + v1 + v2 + v3 + v4 + v5 + ((0 + v5) | pl5)) fm2 = LinearMixedModel(slopes_form, data; wts, contrasts) + +# but this does work +# fails with zero corr but otherwise gives similar estimates to lme +m_zc_pl3 = let f = @formula(y ~ v1 + v2 + v3 + v4 + v5 + + zerocorr(1 + v1 | pl3) + + (1 + v2 + v3 + v4 + v5 | pl5)) + + fit(MixedModel, f, data; wts, contrasts) +end + +m_no_int_pl3 = let f = @formula(y ~ v1 + v2 + v3 + v4 + v5 + + (0 + v1 | pl3) + + (1 + v2 + v3 + v4 + v5 | pl5)) + + fit(MixedModel, f, data; wts, contrasts) +end + +# let f = @formula(y ~ v1 + v2 + v3 + v4 + v5 + +# zerocorr(1 + v1 | pl3) + +# zerocorr(1 + v2 + v3 + v4 + v5 | pl5)) +# fit(MixedModel, f, data; wts, contrasts) +# end + +using MixedModelsMakie +using CairoMakie +# ugh this covariance structure +splom!(Figure(), select(data, Not([:pl3, :pl5, :w, :y]))) + +select!(data, :, + :pl3 => :pl3a, + :pl3 => :pl3b, + :pl5 => :pl5a, + :pl5 => :pl5b, + :pl5 => :pl5c, + :pl5 => :pl5d, + :pl5 => :pl5e) + +contrasts = merge(contrasts, Dict(:pl3a => Grouping(), + :pl3b => Grouping(), + :pl5a => Grouping(), + :pl5b => Grouping(), + :pl5c => Grouping(), + :pl5d => Grouping(), + :pl5e => Grouping())) + + +using LinearAlgebra +MixedModels.rmulΛ!(A::Diagonal{T}, B::ReMat{T,1}) where {T} = rmul!(A, only(B.λ)) +function MixedModels.rankUpdate!(C::Hermitian{T, Diagonal{T, Vector{T}}}, A::Diagonal{T, Vector{T}}, α, β) where {T} + size(C) == size(A) || throw(DimensionMismatch("Diagonal matrices unequal size")) + C.data.diag .*= β + C.data.diag .+= α .* abs2.(A.diag) + return C +end + +m_form_split = let f = @formula(y ~ v1 + v2 + v3 + v4 + v5 + + (1 | pl3a) + ((0 + v1) | pl3b) + + (1 | pl5a) + ((0 + v2) | pl5b) + + ((0 + v3) | pl5c) + ((0 + v4) | pl5d) + + ((0 + v5) | pl5e)) + fit(MixedModel, f, data; wts, contrasts) +end diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index 99647bfa0..3da4d6782 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -160,7 +160,7 @@ function LinearMixedModel( sort!(reterms; by=nranef, rev=true) Xy = FeMat(feterm, vec(y)) - sqrtwts = sqrt.(convert(Vector{T}, wts)) + sqrtwts = map!(sqrt, Vector{T}(undef, length(wts)), wts) reweight!.(reterms, Ref(sqrtwts)) reweight!(Xy, sqrtwts) A, L = createAL(reterms, Xy) @@ -557,7 +557,7 @@ function fixef!(v::AbstractVector{Tv}, m::LinearMixedModel{T}) where {Tv,T} for j in 1:r v[j] = XyL[k, j] end - ldiv!(feL(m)', length(v) == r ? v : view(v, 1:r)) + ldiv!(L', length(v) == r ? v : view(v, 1:r)) return v end diff --git a/src/remat.jl b/src/remat.jl index 11103b966..d3added38 100644 --- a/src/remat.jl +++ b/src/remat.jl @@ -229,7 +229,7 @@ function lmulΛ!(adjA::Adjoint{T,<:ReMat{T,S}}, B::BlockedSparse{T}) where {T,S} end function lmulΛ!(adjA::Adjoint{T,ReMat{T,1}}, B::BlockedSparse{T,1,P}) where {T,P} - lmul!(only(adjA.parent.λ.data), nonzeros(B.cscmat)) + lmul!(only(adjA.parent.λ), nonzeros(B.cscmat)) return B end @@ -504,15 +504,15 @@ function reweight!(A::ReMat, sqrtwts::Vector) if A.z === A.wtz A.wtz = similar(A.z) end - rmul!(copyto!(A.wtz, A.z), Diagonal(sqrtwts)) + mul!(A.wtz, A.z, Diagonal(sqrtwts)) end return A end -rmulΛ!(A::Matrix{T}, B::ReMat{T,1}) where {T} = rmul!(A, only(B.λ.data)) +rmulΛ!(A::Matrix{T}, B::ReMat{T,1}) where {T} = rmul!(A, only(B.λ)) function rmulΛ!(A::SparseMatrixCSC{T}, B::ReMat{T,1}) where {T} - rmul!(nonzeros(A), only(B.λ.data)) + rmul!(nonzeros(A), only(B.λ)) return A end @@ -558,7 +558,7 @@ function copyscaleinflate! end function copyscaleinflate!(Ljj::Diagonal{T}, Ajj::Diagonal{T}, Λj::ReMat{T,1}) where {T} Ldiag, Adiag = Ljj.diag, Ajj.diag - broadcast!((x, λsqr) -> x * λsqr + one(T), Ldiag, Adiag, abs2(only(Λj.λ.data))) + broadcast!((x, λsqr) -> x * λsqr + one(T), Ldiag, Adiag, abs2(only(Λj.λ))) return Ljj end @@ -636,7 +636,7 @@ end function σρs(A::ReMat{T,1}, sc::T) where {T} return NamedTuple{(:σ, :ρ)}(( - NamedTuple{(Symbol(only(A.cnames)),)}((sc * abs(only(A.λ.data)),)), () + NamedTuple{(Symbol(only(A.cnames)),)}((sc * abs(only(A.λ)),)), () )) end From 2c041e5aaaab8a3d468c72277f8d0d29245d4fdc Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 21 Oct 2022 22:38:08 +0000 Subject: [PATCH 18/51] Update Mac CI (#656) https://github.com/actions/runner-images/issues/5583 --- .github/workflows/lts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lts.yml b/.github/workflows/lts.yml index 6d1cce8f2..99b462ac1 100644 --- a/.github/workflows/lts.yml +++ b/.github/workflows/lts.yml @@ -22,7 +22,7 @@ jobs: matrix: julia-version: [1.6] julia-arch: [x64] - os: [ubuntu-18.04, macos-10.15, windows-2019] + os: [ubuntu-18.04, macos-11, windows-2019] steps: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 From 9b645fec59f80b0d758dd7b9a0811b5ede2ead2e Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 26 Oct 2022 19:43:29 +0000 Subject: [PATCH 19/51] don't fit a GLM when fixed effects are empty (#657) * don't fit a GLM when fixed effects are empty * NEW entry * format * JuliaFormatter --- NEWS.md | 6 ++++++ docs/make.jl | 4 +++- src/generalizedlinearmixedmodel.jl | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 2b7073d35..a1377f2e6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ + + +* Don't fit a GLM internally during construction of GLMM when the fixed effects are empty (better compatibility with + `dropcollinear` kwarg in newer GLM.jl) [#657] + MixedModels v4.8.0 Release Notes ============================== * Allow predicting from a single observation, as long as `Grouping()` is used for the grouping variables. The simplified implementation of `Grouping()` also removes several now unnecessary `StatsModels` methods that should not have been called directly by the user. [#653] @@ -380,3 +385,4 @@ Package dependencies [#648]: https://github.com/JuliaStats/MixedModels.jl/issues/648 [#651]: https://github.com/JuliaStats/MixedModels.jl/issues/651 [#653]: https://github.com/JuliaStats/MixedModels.jl/issues/653 +[#657]: https://github.com/JuliaStats/MixedModels.jl/issues/657 diff --git a/docs/make.jl b/docs/make.jl index c9cb034ab..fb4f8e36f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -19,4 +19,6 @@ makedocs(; ], ) -deploydocs(;repo = "github.com/JuliaStats/MixedModels.jl.git", push_preview = true, devbranch = "main") +deploydocs(; + repo="github.com/JuliaStats/MixedModels.jl.git", push_preview=true, devbranch="main" +) diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index fce0ffc5b..67fb6aaa1 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -403,8 +403,18 @@ function GeneralizedLinearMixedModel( constresponse || updateL!(LMM) # fit a glm to the fixed-effects only T = eltype(LMM.Xymat) - gl = glm(LMM.X, y, d, l; wts=convert(Vector{T}, wts), offset=convert(Vector{T}, offset)) - β = coef(gl) + # newer versions of GLM (>1.8.0) have a kwarg dropcollinear=true + # which creates problems for the empty fixed-effects case during fitting + # so just don't allow fitting + # XXX unfortunately, this means we have double-rank defiency detection + # TODO: construct GLM by hand so that we skip collinearity checks + # TODO: extend this so that we never fit a GLM when initializing from LMM + dofit = size(LMM.X, 2) != 0 # GLM.jl kwarg + gl = glm(LMM.X, y, d, l; + wts=convert(Vector{T}, wts), + dofit, + offset=convert(Vector{T}, offset)) + β = dofit ? coef(gl) : T[] u = [fill(zero(eltype(y)), vsize(t), nlevs(t)) for t in LMM.reterms] # vv is a template vector used to initialize fields for AGQ # it is empty unless there is a single random-effects term From f8774eb203cdd06a0e5aa7287285b16f9037b5da Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 21 Dec 2022 01:45:02 +0000 Subject: [PATCH 20/51] patch bump (#660) * patch bump * add 4.8.1 --- NEWS.md | 3 ++- Project.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index a1377f2e6..68423d346 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ - +MixedModels v4.8.1 Release Notes +============================== * Don't fit a GLM internally during construction of GLMM when the fixed effects are empty (better compatibility with `dropcollinear` kwarg in newer GLM.jl) [#657] diff --git a/Project.toml b/Project.toml index 548f6f98c..42e595555 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.8.0" +version = "4.8.1" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" From 2b7fa095f7e7ed7f64f9108776d243027ab7fad9 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 10 Jan 2023 22:12:58 +0000 Subject: [PATCH 21/51] use Aqua for static analysis (#659) * use Aqua for static analysis * disable unbound args test --- src/likelihoodratiotest.jl | 2 ++ test/Project.toml | 2 ++ test/runtests.jl | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/src/likelihoodratiotest.jl b/src/likelihoodratiotest.jl index ce4c1a181..335cbaa3f 100644 --- a/src/likelihoodratiotest.jl +++ b/src/likelihoodratiotest.jl @@ -230,6 +230,8 @@ function _iscomparable(m::LinearMixedModel...) return true end +# XXX we need the where clause to distinguish from the general method +# but static analysis complains if we don't use the type parameter function _samefamily( ::GeneralizedLinearMixedModel{<:AbstractFloat,S}... ) where {S<:Distribution} diff --git a/test/Project.toml b/test/Project.toml index 46a3d7075..2d54cb614 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,4 +1,5 @@ [deps] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a" @@ -14,4 +15,5 @@ Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] +Aqua = "0.5" StableRNGs = "0.1, 1" diff --git a/test/runtests.jl b/test/runtests.jl index 1e40d26d7..5b6fc47e5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,7 @@ +using Aqua using MixedModels +using Test + import InteractiveUtils: versioninfo import LinearAlgebra: BLAS @@ -13,6 +16,12 @@ else end end +@testset "Aqua" begin + # we can't check for unbound type parameters + # because we actually need one at one point for _same_family() + Aqua.test_all(MixedModels; ambiguities=false, unbound_args=false) +end + include("utilities.jl") include("misc.jl") include("pivot.jl") From 5bf6b646334c303376ce6bd2b3bb8a09bb95c2e8 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 11 Jan 2023 22:50:50 +0000 Subject: [PATCH 22/51] use SnoopPrecompile instead of precompile file (#663) * use SnoopPrecompile instead of precompile file * news/patch bump * JuliaFormatter Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- NEWS.md | 4 ++ Project.toml | 4 +- src/MixedModels.jl | 25 +++++++++++- src/precompile_MixedModels.jl | 73 ----------------------------------- 4 files changed, 30 insertions(+), 76 deletions(-) delete mode 100644 src/precompile_MixedModels.jl diff --git a/NEWS.md b/NEWS.md index 68423d346..a2f5a56d5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,6 @@ +MixedModels v4.8.2 Release Notes +============================== +* Use `SnoopPrecompile` for better precompilation performance. This can dramatically increase TTFX, especially on Julia 1.9. [#663] MixedModels v4.8.1 Release Notes ============================== @@ -387,3 +390,4 @@ Package dependencies [#651]: https://github.com/JuliaStats/MixedModels.jl/issues/651 [#653]: https://github.com/JuliaStats/MixedModels.jl/issues/653 [#657]: https://github.com/JuliaStats/MixedModels.jl/issues/657 +[#663]: https://github.com/JuliaStats/MixedModels.jl/issues/663 diff --git a/Project.toml b/Project.toml index 42e595555..d0cf86134 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.8.1" +version = "4.8.2" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" @@ -16,6 +16,7 @@ NLopt = "76087f3c-5699-56af-9a33-bf431cd00edd" PooledArrays = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SnoopPrecompile = "66db9d55-30c0-4569-8b51-7e840670fc0c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" @@ -36,6 +37,7 @@ LazyArtifacts = "1" NLopt = "0.5, 0.6" PooledArrays = "0.5, 1" ProgressMeter = "1.7" +SnoopPrecompile = "1" StaticArrays = "0.11, 0.12, 1" StatsAPI = "1.5" StatsBase = "0.31, 0.32, 0.33" diff --git a/src/MixedModels.jl b/src/MixedModels.jl index 11fc01e78..28437e721 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -178,6 +178,27 @@ include("grouping.jl") include("mimeshow.jl") include("serialization.jl") -include("precompile_MixedModels.jl") -_precompile_() +using SnoopPrecompile + +@precompile_setup begin + # Putting some things in `setup` can reduce the size of the + # precompile file and potentially make loading faster. + sleepstudy = MixedModels.dataset(:sleepstudy) + contra = MixedModels.dataset(:contra) + @precompile_all_calls begin + # all calls in this block will be precompiled, regardless of whether + # they belong to your package or not (on Julia 1.8 and higher) + + # these are relatively small models and so shouldn't increase precompile times all that much + # while still massively boosting load and TTFX times + fit(MixedModel, + @formula(reaction ~ 1 + days + (1 + days | subj)), + sleepstudy) + fit(MixedModel, + @formula(use ~ 1 + age + abs2(age) + urban + livch + (1 | urban & dist)), + contra, + Bernoulli()) + end +end + end # module diff --git a/src/precompile_MixedModels.jl b/src/precompile_MixedModels.jl deleted file mode 100644 index 2ff92d965..000000000 --- a/src/precompile_MixedModels.jl +++ /dev/null @@ -1,73 +0,0 @@ -#! format: off -# this file is automatically generated by SnoopCompile - -function _precompile_() - ccall(:jl_generating_output, Cint, ()) == 1 || return nothing - let fbody = try Base.bodyfunction(which(fit!, (LinearMixedModel,))) catch missing end - if !ismissing(fbody) - precompile(fbody, (Bool,Bool,Nothing,Int64,typeof(fit!),LinearMixedModel,)) - end -end # time: 6.582904 - Base.precompile(Tuple{typeof(fit!),GeneralizedLinearMixedModel}) # time: 6.0995073 - Base.precompile(Tuple{Type{LinearMixedModel},AbstractArray,Tuple,FormulaTerm,Vector{Any},Nothing}) # time: 2.2513552 - let fbody = try Base.bodyfunction(which(fit!, (LinearMixedModel{Float64},))) catch missing end - if !ismissing(fbody) - precompile(fbody, (Bool,Bool,Nothing,Int64,typeof(fit!),LinearMixedModel{Float64},)) - end -end # time: 2.1690955 - isdefined(MixedModels, Symbol("#22#23")) && Base.precompile(Tuple{getfield(MixedModels, Symbol("#22#23"))}) # time: 0.70335937 - Base.precompile(Tuple{Type{LinearMixedModel},Vector{Float64},Tuple{Matrix{Float64}, ReMat{Float64, 2}},FormulaTerm{ContinuousTerm{Float64}, Tuple{MatrixTerm{Tuple{InterceptTerm{true}, ContinuousTerm{Float64}}}, RandomEffectsTerm}},Vector{Any},Nothing}) # time: 0.6737979 - Base.precompile(Tuple{typeof(deviance!),GeneralizedLinearMixedModel,Int64}) # time: 0.6433022 - Base.precompile(Tuple{Type{LinearMixedModel},Vector{Float64},FeTerm{Float64, Matrix{Float64}},Vector{AbstractReMat{Float64}},FormulaTerm{ContinuousTerm{Float64}, Tuple{MatrixTerm{Tuple{InterceptTerm{true}, ContinuousTerm{Float64}}}, RandomEffectsTerm}},Vector{Any},Nothing}) # time: 0.42538697 - Base.precompile(Tuple{typeof(deviance!),GeneralizedLinearMixedModel{Float64, Bernoulli{Float64}},Int64}) # time: 0.3716886 - Base.precompile(Tuple{typeof(fit!),GeneralizedLinearMixedModel{Float64, Bernoulli{Float64}}}) # time: 0.1559177 - Base.precompile(Tuple{typeof(adjA),Vector{Int32},Matrix{Float64}}) # time: 0.11642844 - Base.precompile(Tuple{typeof(apply_schema),Term,MultiSchema{FullRank},UnionAll}) # time: 0.0992202 - Base.precompile(Tuple{typeof(fit),Type{GeneralizedLinearMixedModel},FormulaTerm,NamedTuple,Bernoulli,LogitLink}) # time: 0.09839547 - Base.precompile(Tuple{typeof(copyscaleinflate!),UniformBlockDiagonal{Float64},UniformBlockDiagonal{Float64},ReMat{Float64, 2}}) # time: 0.07856259 - Base.precompile(Tuple{typeof(*),Adjoint{Float64, ReMat{Float64, 2}},ReMat{Float64, 2}}) # time: 0.064247385 - let fbody = try Base.bodyfunction(which(fit, (Type{LinearMixedModel},FormulaTerm,NamedTuple,))) catch missing end - if !ismissing(fbody) - precompile(fbody, (Any,Any,Bool,Bool,Any,Any,typeof(fit),Type{LinearMixedModel},FormulaTerm,NamedTuple,)) - end -end # time: 0.0641711 - Base.precompile(Tuple{typeof(apply_schema),Tuple{RandomEffectsTerm, RandomEffectsTerm},MultiSchema{FullRank},Type{LinearMixedModel}}) # time: 0.062291622 - Base.precompile(Tuple{typeof(apply_schema),RandomEffectsTerm,MultiSchema{FullRank},Type{<:MixedModel}}) # time: 0.05415768 - Base.precompile(Tuple{typeof(rmulΛ!),Matrix{Float64},ReMat{Float64, 2}}) # time: 0.03744466 - Base.precompile(Tuple{typeof(rdiv!),Matrix{Float64},UpperTriangular{Float64, Adjoint{Float64, UniformBlockDiagonal{Float64}}}}) # time: 0.037409946 - Base.precompile(Tuple{typeof(LD),UniformBlockDiagonal{Float64}}) # time: 0.029826526 - Base.precompile(Tuple{typeof(*),Adjoint{Float64, ReMat{Float64, 1}},ReMat{Float64, 1}}) # time: 0.02977296 - Base.precompile(Tuple{typeof(GLM.wrkresp!),SubArray{Float64, 1, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true},GLM.GlmResp{Vector{Float64}, Bernoulli{Float64}, LogitLink}}) # time: 0.022571307 - Base.precompile(Tuple{typeof(copyscaleinflate!),Diagonal{Float64, Vector{Float64}},Diagonal{Float64, Vector{Float64}},ReMat{Float64, 1}}) # time: 0.014116756 - Base.precompile(Tuple{typeof(cholUnblocked!),UniformBlockDiagonal{Float64},Type{Val{:L}}}) # time: 0.011265205 - Base.precompile(Tuple{Core.Type{MixedModels.GeneralizedLinearMixedModel{Float64, Distributions.Bernoulli}},LinearMixedModel,Any,Any,Vector,Any,Any,Any,Any,Any,Any,Any,Any,Any,Any}) # time: 0.010291444 - Base.precompile(Tuple{typeof(apply_schema),RandomEffectsTerm,MultiSchema{FullRank},Type{LinearMixedModel}}) # time: 0.009160354 - Base.precompile(Tuple{Type{FeTerm},Matrix{Float64},Any}) # time: 0.008526229 - Base.precompile(Tuple{typeof(apply_schema),Term,MultiSchema{FullRank},Type}) # time: 0.008067499 - Base.precompile(Tuple{typeof(apply_schema),Tuple{RandomEffectsTerm, RandomEffectsTerm},MultiSchema,Type}) # time: 0.006452216 - Base.precompile(Tuple{typeof(*),Adjoint{Float64, FeMat{Float64, Matrix{Float64}}},ReMat{Float64, 2}}) # time: 0.005299216 - Base.precompile(Tuple{typeof(reweight!),ReMat{Float64, 1},Vector{Float64}}) # time: 0.00500359 - Base.precompile(Tuple{typeof(reweight!),ReMat{Float64, 2},Vector{Float64}}) # time: 0.004945764 - Base.precompile(Tuple{typeof(_pushALblock!),Vector{AbstractMatrix{Float64}},Vector{AbstractMatrix{Float64}},Diagonal{Float64, Vector{Float64}}}) # time: 0.004846841 - Base.precompile(Tuple{typeof(apply_schema),Tuple{RandomEffectsTerm, RandomEffectsTerm},MultiSchema{FullRank},Type{<:MixedModel}}) # time: 0.004639013 - Base.precompile(Tuple{typeof(_pushALblock!),Vector{AbstractMatrix{Float64}},Vector{AbstractMatrix{Float64}},UniformBlockDiagonal{Float64}}) # time: 0.004212355 - isdefined(MixedModels, Symbol("#obj#92")) && Base.precompile(Tuple{getfield(MixedModels, Symbol("#obj#92")),Vector{Float64},Vector{Float64}}) # time: 0.00415707 - Base.precompile(Tuple{typeof(reweight!),LinearMixedModel{Float64},Vector{Float64}}) # time: 0.003799728 - Base.precompile(Tuple{typeof(copyto!),UniformBlockDiagonal{Float64},UniformBlockDiagonal{Float64}}) # time: 0.003437127 - Base.precompile(Tuple{typeof(cholUnblocked!),Matrix{Float64},Type{Val{:L}}}) # time: 0.002697967 - isdefined(MixedModels, Symbol("#97#99")) && Base.precompile(Tuple{getfield(MixedModels, Symbol("#97#99")),ReMat{Float64, 1}}) # time: 0.002630397 - Base.precompile(Tuple{typeof(apply_schema),ConstantTerm{Int64},MultiSchema{FullRank},UnionAll}) # time: 0.002451962 - Base.precompile(Tuple{typeof(apply_schema),ConstantTerm{Int64},MultiSchema{FullRank},Type}) # time: 0.002029733 - Base.precompile(Tuple{typeof(rmulΛ!),Matrix{Float64},ReMat{Float64, 1}}) # time: 0.00186467 - Base.precompile(Tuple{typeof(getproperty),LinearMixedModel,Symbol}) # time: 0.001859925 - isdefined(MixedModels, Symbol("#59#61")) && Base.precompile(Tuple{getfield(MixedModels, Symbol("#59#61")),ReMat{Float64, 1}}) # time: 0.00181014 - isdefined(MixedModels, Symbol("#58#60")) && Base.precompile(Tuple{getfield(MixedModels, Symbol("#58#60")),ReMat{Float64, 2}}) # time: 0.001746027 - Base.precompile(Tuple{typeof(mul!),Vector{Float64},ReMat{Float64, 1},Vector{Float64},Float64,Float64}) # time: 0.001642233 - Base.precompile(Tuple{typeof(cholUnblocked!),Diagonal{Float64, Vector{Float64}},Type{Val{:L}}}) # time: 0.001591365 - isdefined(MixedModels, Symbol("#59#61")) && Base.precompile(Tuple{getfield(MixedModels, Symbol("#59#61")),ReMat{Float64, 2}}) # time: 0.001566984 - Base.precompile(Tuple{Type{RandomEffectsTerm},Any,Any}) # time: 0.001504504 - isdefined(MixedModels, Symbol("#58#60")) && Base.precompile(Tuple{getfield(MixedModels, Symbol("#58#60")),ReMat{Float64, 1}}) # time: 0.001407624 - Base.precompile(Tuple{typeof(*),Adjoint{Float64, FeMat{Float64, Matrix{Float64}}},ReMat{Float64, 1}}) # time: 0.001186352 - Base.precompile(Tuple{Type{MultiSchema},FullRank}) # time: 0.001066192 - Base.precompile(Tuple{Type{ReMat{Float64, 2}},CategoricalTerm{DummyCoding, String, 17},Vector{Int32},Vector{String},Vector{String},Matrix{Float64},Matrix{Float64},LowerTriangular{Float64, Matrix{Float64}},Vector{Int64},SparseMatrixCSC{Float64, Int32},Matrix{Float64}}) # time: 0.001038076 -end From cdf13e98d0579b9655e004beb0ae92c3e769c45a Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 7 Feb 2023 17:12:02 +0000 Subject: [PATCH 23/51] set Julia minimum compat to 1.8 (#665) * set Julia minimum compat to 1.8 * NEWS link * link in README * bump Ubuntu LTS test version --- .github/workflows/MKL.yml | 2 +- .github/workflows/{ci.yml => current.yml} | 2 +- .github/workflows/{lts.yml => minimum.yml} | 6 +++--- .github/workflows/nightly.yml | 2 +- NEWS.md | 5 +++++ Project.toml | 2 +- README.md | 18 +++++++++--------- 7 files changed, 21 insertions(+), 16 deletions(-) rename .github/workflows/{ci.yml => current.yml} (96%) rename .github/workflows/{lts.yml => minimum.yml} (88%) diff --git a/.github/workflows/MKL.yml b/.github/workflows/MKL.yml index 8652ad932..c7395dbe6 100644 --- a/.github/workflows/MKL.yml +++ b/.github/workflows/MKL.yml @@ -12,7 +12,7 @@ jobs: matrix: julia-version: [nightly] julia-arch: [x64] - os: [ubuntu-18.04] + os: [ubuntu-20.04] steps: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 diff --git a/.github/workflows/ci.yml b/.github/workflows/current.yml similarity index 96% rename from .github/workflows/ci.yml rename to .github/workflows/current.yml index a8106344c..8745e0e93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/current.yml @@ -22,7 +22,7 @@ jobs: matrix: julia-version: [1] julia-arch: [x64] - os: [ubuntu-18.04] + os: [ubuntu-20.04] steps: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 diff --git a/.github/workflows/lts.yml b/.github/workflows/minimum.yml similarity index 88% rename from .github/workflows/lts.yml rename to .github/workflows/minimum.yml index 99b462ac1..176fdefcd 100644 --- a/.github/workflows/lts.yml +++ b/.github/workflows/minimum.yml @@ -1,4 +1,4 @@ -name: LTS +name: "minimum compat" concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true @@ -20,9 +20,9 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - julia-version: [1.6] + julia-version: [1.8] julia-arch: [x64] - os: [ubuntu-18.04, macos-11, windows-2019] + os: [ubuntu-20.04, macos-11, windows-2019] steps: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index b64189770..d56eff075 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -22,7 +22,7 @@ jobs: matrix: julia-version: [nightly] julia-arch: [x64] - os: [ubuntu-18.04] + os: [ubuntu-20.04] steps: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 diff --git a/NEWS.md b/NEWS.md index a2f5a56d5..26c3f33ad 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.9.0 Release Notes +============================== +* Julia minimum compat version raised to 1.8 because of BSplineKit [#665] + MixedModels v4.8.2 Release Notes ============================== * Use `SnoopPrecompile` for better precompilation performance. This can dramatically increase TTFX, especially on Julia 1.9. [#663] @@ -391,3 +395,4 @@ Package dependencies [#653]: https://github.com/JuliaStats/MixedModels.jl/issues/653 [#657]: https://github.com/JuliaStats/MixedModels.jl/issues/657 [#663]: https://github.com/JuliaStats/MixedModels.jl/issues/663 +[#665]: https://github.com/JuliaStats/MixedModels.jl/issues/665 diff --git a/Project.toml b/Project.toml index d0cf86134..60d4a4482 100644 --- a/Project.toml +++ b/Project.toml @@ -45,7 +45,7 @@ StatsFuns = "0.8, 0.9, 1" StatsModels = "0.6.23" StructTypes = "1" Tables = "1" -julia = "1.6" +julia = "1.8" [extras] DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" diff --git a/README.md b/README.md index e922f7e6d..5b4b41553 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,14 @@ [codecov-img]: https://codecov.io/github/JuliaStats/MixedModels.jl/badge.svg?branch=main [codecov-url]: https://codecov.io/github/JuliaStats/MixedModels.jl?branch=main -[current-img]: https://github.com/JuliaStats/MixedModels.jl/actions/workflows/ci.yml/badge.svg -[current-url]: https://github.com/JuliaStats/MixedModels.jl/actions?workflow=ci +[current-img]: https://github.com/JuliaStats/MixedModels.jl/actions/workflows/current.yml/badge.svg +[current-url]: https://github.com/JuliaStats/MixedModels.jl/actions?workflow=current [nightly-img]: https://github.com/JuliaStats/MixedModels.jl/actions/workflows/nightly.yml/badge.svg [nightly-url]: https://github.com/JuliaStats/MixedModels.jl/actions?workflow=nightly -[lts-img]: https://github.com/JuliaStats/MixedModels.jl/actions/workflows/lts.yml/badge.svg -[lts-url]: https://github.com/JuliaStats/MixedModels.jl/actions?workflow=lts +[minimum-img]: https://github.com/JuliaStats/MixedModels.jl/actions/workflows/minimum.yml/badge.svg +[minimum-url]: https://github.com/JuliaStats/MixedModels.jl/actions?workflow=minimum [pkgeval-img]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/M/MixedModels.svg [pkgeval-url]: https://juliaci.github.io/NanosoldierReports/pkgeval_badges/report.html @@ -52,11 +52,11 @@ Typical distribution forms are _Bernoulli_ for binary data or _Poisson_ for coun |OS | OS Version |Arch |Julia | |:------:|:-------------:|:---:|:--------------:| -|Linux | Ubuntu 18.04 | x64 |v1.6 (LTS) | -|Linux | Ubuntu 18.04 | x64 |current release | -|Linux | Ubuntu 18.04 | x64 |nightly | -|macOS | Catalina 10.15| x64 |v1.6 (LTS) | -|Windows | Server 2019 | x64 |v1.6 (LTS) | +|Linux | Ubuntu 20.04 | x64 |v1.8 | +|Linux | Ubuntu 20.04 | x64 |current release | +|Linux | Ubuntu 20.04 | x64 |nightly | +|macOS | Catalina 10.15| x64 |v1.8 | +|Windows | Server 2019 | x64 |v1.8 | Note that previous releases still support older Julia versions. From cb6bb41c562b56ef7b7aaf8a1f6f72cc6e8fc732 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Wed, 22 Feb 2023 09:05:54 -0600 Subject: [PATCH 24/51] Update benchmarks, single global contrasts Dict (#667) * Update benchmarks, single global contrasts Dict * Add NEWS.md entry * Update NEWS.md Co-authored-by: Phillip Alday --------- Co-authored-by: Phillip Alday --- NEWS.md | 2 + benchmark/benchmarks.jl | 136 +++++++++++++++++++++++----------------- 2 files changed, 82 insertions(+), 56 deletions(-) diff --git a/NEWS.md b/NEWS.md index 26c3f33ad..8047ba68b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ MixedModels v4.9.0 Release Notes ============================== +* Revise code in benchmarks to work with recent Julia and PkgBenchmark.jl [#667] * Julia minimum compat version raised to 1.8 because of BSplineKit [#665] MixedModels v4.8.2 Release Notes @@ -396,3 +397,4 @@ Package dependencies [#657]: https://github.com/JuliaStats/MixedModels.jl/issues/657 [#663]: https://github.com/JuliaStats/MixedModels.jl/issues/663 [#665]: https://github.com/JuliaStats/MixedModels.jl/issues/665 +[#667]: https://github.com/JuliaStats/MixedModels.jl/issues/667 diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index ecd73dcf3..ed8a7872e 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -3,88 +3,112 @@ using MixedModels: dataset const SUITE = BenchmarkGroup() -const global contrasts = Dict( - :mrk17_exp1 => merge(Dict(n => HelmertCoding() for n in (:F, :P, :Q, :lQ, :lT)), Dict(n => Grouping() for n in (:item, :subj))), - :kb07 => merge(Dict(n => HelmertCoding() for n in (:spkr, :prec, :load)), Dict(n => Grouping() for n in (:item, :subj))), - :insteval => Dict(n => Grouping() for n in (:s, :d)), +const global contrasts = Dict{Symbol,Any}( + :batch => Grouping(), # dyestuff, dyestuff2, pastes + :cask => Grouping(), # pastes + :d => Grouping(), # insteval + # :dept => Grouping(), # insteval - not set b/c also used in fixed effects + :g => Grouping(), # d3, ml1m + :h => Grouping(), # d3, ml1m + :i => Grouping(), # d3 + :item => Grouping(), # kb07, mrk17_exp1, + :Machine => Grouping(), # machines + :plate => Grouping(), # penicillin + :s => Grouping(), # insteval + :sample => Grouping(), # penicillin + :subj => Grouping(), # kb07, mrk17_exp1, sleepstudy + :Worker => Grouping(), # machines + :F => HelmertCoding(), # mrk17_exp1 + :P => HelmertCoding(), # mrk17_exp1 + :Q => HelmertCoding(), # mrk17_exp1 + :lQ => HelmertCoding(), # mrk17_exp1 + :lT => HelmertCoding(), # mrk17_exp1 + :load => HelmertCoding(), # kb07 + :prec => HelmertCoding(), # kb07 + :service => HelmertCoding(), # insteval + :spkr => HelmertCoding(), # kb07 ) + const global fms = Dict( :dyestuff => [ - @formula(yield ~ 1 + (1|batch)), - ], + @formula(yield ~ 1 + (1 | batch)) + ], :dyestuff2 => [ - @formula(yield ~ 1 + (1|batch)), - ], + @formula(yield ~ 1 + (1 | batch)) + ], :d3 => [ - @formula(y ~ 1 + u + (1+u|g) + (1+u|h) + (1+u|i)), - ], + @formula(y ~ 1 + u + (1 + u | g) + (1 + u | h) + (1 + u | i)) + ], :insteval => [ - @formula(y ~ 1 + service + (1|s) + (1|d) + (1|dept)), - @formula(y ~ 1 + service*dept + (1|s) + (1|d)), - ], + @formula(y ~ 1 + service + (1 | s) + (1 | d) + (1 | dept)), + @formula(y ~ 1 + service * dept + (1 | s) + (1 | d)), + ], :kb07 => [ - @formula(rt_trunc ~ 1+spkr+prec+load+(1|subj)+(1|item)), - @formula(rt_trunc ~ 1+spkr*prec*load+(1|subj)+(1+prec|item)), - @formula(rt_trunc ~ 1+spkr*prec*load+(1+spkr+prec+load|subj)+(1+spkr+prec+load|item)), - ], + @formula(rt_trunc ~ 1 + spkr + prec + load + (1 | subj) + (1 | item)), + @formula(rt_trunc ~ 1 + spkr * prec * load + (1 | subj) + (1 + prec | item)), + @formula( + rt_trunc ~ + 1 + spkr * prec * load + (1 + spkr + prec + load | subj) + + (1 + spkr + prec + load | item) + ), + ], :machines => [ - @formula(score ~ 1 + (1|Worker) + (1|Machine)), - ], + @formula(score ~ 1 + (1 | Worker) + (1 | Machine)) + ], :ml1m => [ - @formula(y ~ 1 + (1|g) + (1|h)), - ], + @formula(y ~ 1 + (1 | g) + (1 | h)) + ], :mrk17_exp1 => [ - @formula(1000/rt ~ 1+F*P*Q*lQ*lT + (1|item) + (1|subj)), - @formula(1000/rt ~ 1+F*P*Q*lQ*lT + (1+P+Q+lQ+lT|item) + (1+F+P+Q+lQ+lT|subj)), - ], + @formula(1000 / rt ~ 1 + F * P * Q * lQ * lT + (1 | item) + (1 | subj)), + @formula( + 1000 / rt ~ + 1 + F * P * Q * lQ * lT + (1 + P + Q + lQ + lT | item) + + (1 + F + P + Q + lQ + lT | subj) + ), + ], :pastes => [ - @formula(strength ~ 1 + (1|batch&cask)), - @formula(strength ~ 1 + (1|batch/cask)), - ], + @formula(strength ~ 1 + (1 | batch & cask)), + @formula(strength ~ 1 + (1 | batch / cask)), + ], :penicillin => [ - @formula(diameter ~ 1 + (1|plate) + (1|sample)), - ], + @formula(diameter ~ 1 + (1 | plate) + (1 | sample)) + ], :sleepstudy => [ - @formula(reaction ~ 1 + days + (1|subj)), - @formula(reaction ~ 1 + days + zerocorr(1+days|subj)), - @formula(reaction ~ 1 + days + (1|subj) + (0+days|subj)), - @formula(reaction ~ 1 + days + (1+days|subj)), - ], + @formula(reaction ~ 1 + days + (1 | subj)), + @formula(reaction ~ 1 + days + zerocorr(1 + days | subj)), + @formula(reaction ~ 1 + days + (1 | subj) + (0 + days | subj)), + @formula(reaction ~ 1 + days + (1 + days | subj)), + ], ) -function fitbobyqa(dsname::Symbol, index::Integer) - fit( - MixedModel, - fms[dsname][index], - dataset(dsname), - contrasts=get!(contrasts, dsname, Dict{Symbol,StatsModels.AbstractContrasts}()), - ) +function fitbobyqa(dsnm::Symbol, i::Integer) + return fit(MixedModel, fms[dsnm][i], dataset(dsnm); contrasts, progress=false) end SUITE["simplescalar"] = BenchmarkGroup(["single", "simple", "scalar"]) -for (ds, i) in [ - (:dyestuff, 1,), - (:dyestuff2, 1,), +for (ds, i) in [ + (:dyestuff, 1), + (:dyestuff2, 1), (:pastes, 1), - (:sleepstudy, 1,), + (:sleepstudy, 1), ] - SUITE["simplescalar"][string(ds, ':', i)] = @benchmarkable fitbobyqa($(QuoteNode(ds)), $(QuoteNode(i))) + SUITE["simplescalar"][string(ds, ':', i)] = @benchmarkable fitbobyqa($ds, $i) end SUITE["singlevector"] = BenchmarkGroup(["single", "vector"]) -for (ds, i) in [ - (:sleepstudy, 2,), - (:sleepstudy, 3,), - (:sleepstudy, 4,), +for (ds, i) in [ + (:sleepstudy, 2), + (:sleepstudy, 3), + (:sleepstudy, 4), ] - SUITE["singlevector"][string(ds, ':', i)] = @benchmarkable fitbobyqa($(QuoteNode(ds)), $(QuoteNode(i))) + SUITE["singlevector"][string(ds, ':', i)] = @benchmarkable fitbobyqa($ds, $i) end SUITE["nested"] = BenchmarkGroup(["multiple", "nested", "scalar"]) -for (ds, i) in [ - (:pastes, 2,), +for (ds, i) in [ +(:pastes, 2) ] - SUITE["nested"][string(ds, ':', i)] = @benchmarkable fitbobyqa($(QuoteNode(ds)), $(QuoteNode(i))) + SUITE["nested"][string(ds, ':', i)] = @benchmarkable fitbobyqa($ds, $i) end SUITE["crossed"] = BenchmarkGroup(["multiple", "crossed", "scalar"]) @@ -97,7 +121,7 @@ for (ds, i) in [ (:mrk17_exp1, 1), (:penicillin, 1), ] - SUITE["crossed"][string(ds, ':', i)] = @benchmarkable fitbobyqa($(QuoteNode(ds)), $(QuoteNode(i))) + SUITE["crossed"][string(ds, ':', i)] = @benchmarkable fitbobyqa($ds, $i) end SUITE["crossedvector"] = BenchmarkGroup(["multiple", "crossed", "vector"]) @@ -107,5 +131,5 @@ for (ds, i) in [ (:kb07, 3), (:mrk17_exp1, 2), ] - SUITE["crossedvector"][string(ds, ':', i)] = @benchmarkable fitbobyqa($(QuoteNode(ds)), $(QuoteNode(i))) + SUITE["crossedvector"][string(ds, ':', i)] = @benchmarkable fitbobyqa($ds, $i) end From 8afa1e4b06ce1679b5e2de3c155d867015dbe3f8 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 24 Feb 2023 22:26:01 +0000 Subject: [PATCH 25/51] fix some typos (#669) --- NEWS.md | 2 +- docs/src/optimization.md | 2 +- src/bootstrap.jl | 2 +- src/generalizedlinearmixedmodel.jl | 2 +- src/linearmixedmodel.jl | 2 +- src/predict.jl | 6 +++--- src/randomeffectsterm.jl | 2 +- src/simulate.jl | 4 ++-- test/bootstrap.jl | 4 ++-- test/pls.jl | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8047ba68b..ff90225f5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -294,7 +294,7 @@ Principal components * An `AbstractReMat` type has now been introduced to support [#380] work on constrained random-effects structures and random-effects structures appropriate for applications - in GLM-based decovolution as used in fMRI and EEG (see e.g. [unfold.jl](https://github.com/unfoldtoolbox/unfold.jl).) + in GLM-based deconvolution as used in fMRI and EEG (see e.g. [unfold.jl](https://github.com/unfoldtoolbox/unfold.jl).) * Similarly, a constructor for `FeMat{::SparseMatrixCSC,S}` has been introduced [#309]. Currently, this constructor assumes a full-rank matrix, but the work on rank deficiency may be extended to this constructor as well. diff --git a/docs/src/optimization.md b/docs/src/optimization.md index d6ae7bb77..100b18914 100644 --- a/docs/src/optimization.md +++ b/docs/src/optimization.md @@ -278,7 +278,7 @@ issingular(fm2) In a [*generalized linear model*](https://en.wikipedia.org/wiki/Generalized_linear_model) the responses are modelled as coming from a particular distribution, such as `Bernoulli` for binary responses or `Poisson` for responses that represent counts. The scalar distributions of individual responses differ only in their means, which are determined by a *linear predictor* expression $\eta=\bf X\beta$, where, as before, $\bf X$ is a model matrix derived from the values of covariates and $\beta$ is a vector of coefficients. -The unconstrained components of $\eta$ are mapped to the, possiby constrained, components of the mean response, $\mu$, via a scalar function, $g^{-1}$, applied to each component of $\eta$. +The unconstrained components of $\eta$ are mapped to the, possibly constrained, components of the mean response, $\mu$, via a scalar function, $g^{-1}$, applied to each component of $\eta$. For historical reasons, the inverse of this function, taking components of $\mu$ to the corresponding component of $\eta$ is called the *link function* and the more frequently used map from $\eta$ to $\mu$ is the *inverse link*. A *generalized linear mixed-effects model* (GLMM) is defined, for the purposes of this package, by diff --git a/src/bootstrap.jl b/src/bootstrap.jl index e5c10051c..296a61517 100644 --- a/src/bootstrap.jl +++ b/src/bootstrap.jl @@ -58,7 +58,7 @@ bar is automatically disabled for non-interactive (i.e. logging) contexts. !!! note Note that `use_threads=true` may not offer a performance boost and may even - decrease peformance if multithreaded linear algebra (BLAS) routines are available. + decrease performance if multithreaded linear algebra (BLAS) routines are available. In this case, threads at the level of the linear algebra may already occupy all processors/processor cores. There are plans to provide better support in coordinating Julia- and BLAS-level threads in the future. diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index 67fb6aaa1..d1612b2ad 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -406,7 +406,7 @@ function GeneralizedLinearMixedModel( # newer versions of GLM (>1.8.0) have a kwarg dropcollinear=true # which creates problems for the empty fixed-effects case during fitting # so just don't allow fitting - # XXX unfortunately, this means we have double-rank defiency detection + # XXX unfortunately, this means we have double-rank deficiency detection # TODO: construct GLM by hand so that we skip collinearity checks # TODO: extend this so that we never fit a GLM when initializing from LMM dofit = size(LMM.X, 2) != 0 # GLM.jl kwarg diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index 3da4d6782..e69998f65 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -1121,7 +1121,7 @@ Return the denominator for penalized sums-of-squares. For MLE, this value is the number of observations. For REML, this value is the number of observations minus the rank of the fixed-effects matrix. -The difference is analagous to the use of n or n-1 in the denominator when +The difference is analogous to the use of n or n-1 in the denominator when calculating the variance. """ function ssqdenom(m::LinearMixedModel)::Int diff --git a/src/predict.jl b/src/predict.jl index 9440d3158..d3c0be5c5 100644 --- a/src/predict.jl +++ b/src/predict.jl @@ -99,7 +99,7 @@ function _predict(m::MixedModel{T}, newdata, β; new_re_levels) where {T} # (at least for the response) # add a response column - # we get type stability via constant propogation on `new_re_levels` + # we get type stability via constant propagation on `new_re_levels` y, mnew = let ytemp = ones(T, length(first(newdata))) f, contr = _abstractify_grouping(m.formula) respvars = StatsModels.termvars(f.lhs) @@ -136,7 +136,7 @@ function _predict(m::MixedModel{T}, newdata, β; new_re_levels) where {T} for (grp, known_levels, data_levels) in zip(grps, levels.(m.reterms), levels.(mnew.reterms)) if sort!(known_levels) != sort!(data_levels) - throw(ArgumentError("New level enountered in $grp")) + throw(ArgumentError("New level encountered in $grp")) end end @@ -172,7 +172,7 @@ function _predict(m::MixedModel{T}, newdata, β; new_re_levels) where {T} for (lidx, ll) in enumerate(levels(newre[idx])) oldloc = findfirst(isequal(ll), oldlevels) if oldloc === nothing - # missing is poisonous so propogates + # missing is poisonous so propagates B[:, lidx] .= missing else B[:, lidx] .= @view blupsold[idx][:, oldloc] diff --git a/src/randomeffectsterm.jl b/src/randomeffectsterm.jl index 455186263..fbc1fbc51 100644 --- a/src/randomeffectsterm.jl +++ b/src/randomeffectsterm.jl @@ -129,7 +129,7 @@ function _ranef_refs( return refs, uniques end -# TODO: split this off into a RegressionFormula packge? +# TODO: split this off into a RegressionFormula package? Base.:/(a::AbstractTerm, b::AbstractTerm) = a + a & b function StatsModels.apply_schema( t::FunctionTerm{typeof(/)}, sch::StatsModels.FullRank, Mod::Type{<:MixedModel} diff --git a/src/simulate.jl b/src/simulate.jl index 6c4606b8a..1906ab943 100644 --- a/src/simulate.jl +++ b/src/simulate.jl @@ -42,7 +42,7 @@ end function simulate!( rng::AbstractRNG, m::GeneralizedLinearMixedModel{T}; β=coef(m), σ=m.σ, θ=T[] ) where {T} - # note that these m.resp.y and m.LMM.y will later be sychronized in (re)fit!() + # note that these m.resp.y and m.LMM.y will later be synchronized in (re)fit!() # but for now we use them as distinct scratch buffers to avoid allocations # the noise term is actually in the GLM and not the LMM part so no noise @@ -59,7 +59,7 @@ end """ _rand(rng::AbstractRNG, d::Distribution, location, scale=missing, n=1) -A convenience function taking a draw from a distrbution. +A convenience function taking a draw from a distribution. Note that `d` is specified as an existing distribution, such as from the `GlmResp.d` field. This isn't vectorized nicely because diff --git a/test/bootstrap.jl b/test/bootstrap.jl index c532c69b9..e581d6882 100644 --- a/test/bootstrap.jl +++ b/test/bootstrap.jl @@ -98,7 +98,7 @@ end use_threads=true, hide_progress=true) # even though it's bad practice with floating point, exact equality should # be a valid test here -- if everything is working right, then it's the exact - # same operations occuring within each bootstrap sample, which IEEE 754 + # same operations occurring within each bootstrap sample, which IEEE 754 # guarantees will yield the same result @test sort(bsamp_threaded.σ) == sort(bsamp.σ) @test sort(bsamp_threaded.θ) == sort(bsamp.θ) @@ -124,7 +124,7 @@ end hide_progress=true) end - @testset "Bernoulli simulate! and GLMM boostrap" begin + @testset "Bernoulli simulate! and GLMM bootstrap" begin contra = dataset(:contra) # need a model with fast=false to test that we only # copy the optimizer constraints for θ and not β diff --git a/test/pls.jl b/test/pls.jl index b0f7746d5..739449463 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -469,7 +469,7 @@ end fmzc = models(:sleepstudy)[2] λ = first(fmzc.reterms).λ @test λ isa Diagonal{Float64, Vector{Float64}} - # implicit zerocorr via almagation + # implicit zerocorr via amalgamation fmnc = models(:sleepstudy)[3] λ = first(fmnc.reterms).λ @test λ isa Diagonal{Float64, Vector{Float64}} From ac4c44f6bc277339e28b8ce6527f0da49821be3f Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Sat, 25 Feb 2023 08:14:13 +0000 Subject: [PATCH 26/51] fix badge in README (#670) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b4b41553..148959a1c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ |**Documentation**|**Citation**|**Build Status**|**Code Coverage**| **Style Guide** | |:---------------:|:----------:|:--------------:|:---------------:|:----------------| -|[![Stable Docs][docs-stable-img]][docs-stable-url] [![Dev Docs][docs-dev-img]][docs-dev-url] | [![DOI][doi-img]][doi-url] | [![Julia Current][current-img]][current-url] [![Julia 1.6 (LTS)][lts-img]][lts-url] [![Julia Nightly][nightly-img]][nightly-url] [![PkgEval][pkgeval-img]][pkgeval-url] | [![CodeCov][codecov-img]][codecov-url] | [![Code Style: Blue](https://img.shields.io/badge/code%20style-Blue-4495d1.svg)](https://github.com/invenia/BlueStyle) | +|[![Stable Docs][docs-stable-img]][docs-stable-url] [![Dev Docs][docs-dev-img]][docs-dev-url] | [![DOI][doi-img]][doi-url] | [![Julia Current][current-img]][current-url] [![Julia Minimum Supported Version][minimum-img]][minimum-url] [![Julia Nightly][nightly-img]][nightly-url] [![PkgEval][pkgeval-img]][pkgeval-url] | [![CodeCov][codecov-img]][codecov-url] | [![Code Style: Blue](https://img.shields.io/badge/code%20style-Blue-4495d1.svg)](https://github.com/invenia/BlueStyle) | [doi-img]: https://zenodo.org/badge/9106942.svg [doi-url]: https://zenodo.org/badge/latestdoi/9106942 From 658aea1c0e0ecc0fcfca952a0fcbaa38f64bdb2c Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 7 Mar 2023 22:29:54 +0000 Subject: [PATCH 27/51] hide fit progress during precompilation (#671) --- src/MixedModels.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/MixedModels.jl b/src/MixedModels.jl index 28437e721..846def1b4 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -185,6 +185,7 @@ using SnoopPrecompile # precompile file and potentially make loading faster. sleepstudy = MixedModels.dataset(:sleepstudy) contra = MixedModels.dataset(:contra) + progress = false @precompile_all_calls begin # all calls in this block will be precompiled, regardless of whether # they belong to your package or not (on Julia 1.8 and higher) @@ -193,11 +194,11 @@ using SnoopPrecompile # while still massively boosting load and TTFX times fit(MixedModel, @formula(reaction ~ 1 + days + (1 + days | subj)), - sleepstudy) + sleepstudy; progress) fit(MixedModel, @formula(use ~ 1 + age + abs2(age) + urban + livch + (1 | urban & dist)), contra, - Bernoulli()) + Bernoulli(); progress) end end From c68bb4bc7265d8ea59e2f956d66fd8757fca48b0 Mon Sep 17 00:00:00 2001 From: Dave Kleinschmidt Date: Mon, 10 Apr 2023 13:30:12 -0400 Subject: [PATCH 28/51] integrate changes from StatsModels 0.7 (upcoming release) (#664) * statsmodels 0.7 upgrade * sort out ranef implicit intercept * compat requirement for GLM * fix sorting order for zerocorr * format * show methods for zerocorr * add in test from docs * Minor version bump, NEWS * bump julia version in docs ci --------- Co-authored-by: Phillip Alday --- .github/workflows/documenter.yml | 2 +- NEWS.md | 2 ++ Project.toml | 6 +++--- src/randomeffectsterm.jl | 32 ++++++++++++++++++++++++++------ test/FactorReTerm.jl | 6 ++++++ 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/.github/workflows/documenter.yml b/.github/workflows/documenter.yml index 03ec3b620..4379603de 100644 --- a/.github/workflows/documenter.yml +++ b/.github/workflows/documenter.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@v1 with: - version: 1.6 + version: 1.8 - uses: julia-actions/julia-buildpkg@latest - uses: julia-actions/julia-docdeploy@latest env: diff --git a/NEWS.md b/NEWS.md index ff90225f5..040e4bb2e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ MixedModels v4.9.0 Release Notes ============================== +* Support `StatsModels` 0.7, drop support for `StatsModels` 0.6. [#664] * Revise code in benchmarks to work with recent Julia and PkgBenchmark.jl [#667] * Julia minimum compat version raised to 1.8 because of BSplineKit [#665] @@ -396,5 +397,6 @@ Package dependencies [#653]: https://github.com/JuliaStats/MixedModels.jl/issues/653 [#657]: https://github.com/JuliaStats/MixedModels.jl/issues/657 [#663]: https://github.com/JuliaStats/MixedModels.jl/issues/663 +[#664]: https://github.com/JuliaStats/MixedModels.jl/issues/664 [#665]: https://github.com/JuliaStats/MixedModels.jl/issues/665 [#667]: https://github.com/JuliaStats/MixedModels.jl/issues/667 diff --git a/Project.toml b/Project.toml index 60d4a4482..ed6f483ef 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.8.2" +version = "4.9.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" @@ -31,7 +31,7 @@ Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Arrow = "1, 2" DataAPI = "1" Distributions = "0.21, 0.22, 0.23, 0.24, 0.25" -GLM = "1.5.1" +GLM = "1.8.2" JSON3 = "1" LazyArtifacts = "1" NLopt = "0.5, 0.6" @@ -42,7 +42,7 @@ StaticArrays = "0.11, 0.12, 1" StatsAPI = "1.5" StatsBase = "0.31, 0.32, 0.33" StatsFuns = "0.8, 0.9, 1" -StatsModels = "0.6.23" +StatsModels = "0.7" StructTypes = "1" Tables = "1" julia = "1.8" diff --git a/src/randomeffectsterm.jl b/src/randomeffectsterm.jl index fbc1fbc51..a5876d8f3 100644 --- a/src/randomeffectsterm.jl +++ b/src/randomeffectsterm.jl @@ -37,7 +37,7 @@ function StatsModels.apply_schema( schema::MultiSchema{StatsModels.FullRank}, Mod::Type{<:MixedModel}, ) - lhs, rhs = t.args_parsed + lhs, rhs = t.args isempty(intersect(StatsModels.termvars(lhs), StatsModels.termvars(rhs))) || throw(ArgumentError("Same variable appears on both sides of |")) @@ -53,11 +53,21 @@ check_re_group_type(term::GROUPING_TYPE) = true check_re_group_type(terms::Tuple{Vararg{<:GROUPING_TYPE}}) = true check_re_group_type(x) = false +_unprotect(x) = x +for op in StatsModels.SPECIALS + @eval _unprotect(t::FunctionTerm{typeof($op)}) = t.f(_unprotect.(t.args)...) +end + # make a potentially untyped RandomEffectsTerm concrete function StatsModels.apply_schema( t::RandomEffectsTerm, schema::MultiSchema{StatsModels.FullRank}, Mod::Type{<:MixedModel} ) - lhs, rhs = t.lhs, t.rhs + # we need to do this here because the implicit intercept dance has to happen + # _before_ we apply_schema, which is where :+ et al. are normally + # unprotected. I tried to finagle a way around this (using yet another + # schema wrapper type) but it ends up creating way too many potential/actual + # method ambiguities to be a good idea. + lhs, rhs = _unprotect(t.lhs), t.rhs # get a schema that's specific for the grouping (RHS), creating one if needed schema = get!(schema.subs, rhs, StatsModels.FullRank(schema.base.schema)) @@ -134,11 +144,11 @@ Base.:/(a::AbstractTerm, b::AbstractTerm) = a + a & b function StatsModels.apply_schema( t::FunctionTerm{typeof(/)}, sch::StatsModels.FullRank, Mod::Type{<:MixedModel} ) - if length(t.args_parsed) ≠ 2 + if length(t.args) ≠ 2 throw(ArgumentError("malformed nesting term: $t (Exactly two arguments required")) end - first, second = apply_schema.(t.args_parsed, Ref(sch), Mod) + first, second = apply_schema.(t.args, Ref(sch), Mod) if !(typeof(first) <: CategoricalTerm) throw( @@ -188,7 +198,7 @@ end function StatsModels.apply_schema( t::FunctionTerm{typeof(fulldummy)}, sch::StatsModels.FullRank, Mod::Type{<:MixedModel} ) - return fulldummy(apply_schema.(t.args_parsed, Ref(sch), Mod)...) + return fulldummy(apply_schema.(t.args, Ref(sch), Mod)...) end # specify zero correlation @@ -207,11 +217,21 @@ zerocorr(x) = ZeroCorr(x) # for schema extraction (from runtime-created zerocorr) StatsModels.terms(t::ZeroCorr) = StatsModels.terms(t.term) StatsModels.termvars(t::ZeroCorr) = StatsModels.termvars(t.term) +StatsModels.degree(t::ZeroCorr) = StatsModels.degree(t.term) +# dirty rotten no good ugly hack: make sure zerocorr ranef terms sort appropriately +# cf https://github.com/JuliaStats/StatsModels.jl/blob/41b025409af03c0e019591ac6e817b22efbb4e17/src/terms.jl#L421-L422 +StatsModels.degree(t::FunctionTerm{typeof(zerocorr)}) = StatsModels.degree(only(t.args)) + +Base.show(io::IO, t::ZeroCorr) = Base.show(io, MIME"text/plain"(), t) +function Base.show(io::IO, ::MIME"text/plain", t::ZeroCorr) + # ranefterms already show with parens + return print(io, "zerocorr", t.term) +end function StatsModels.apply_schema( t::FunctionTerm{typeof(zerocorr)}, sch::MultiSchema, Mod::Type{<:MixedModel} ) - return ZeroCorr(apply_schema(t.args_parsed..., sch, Mod)) + return ZeroCorr(apply_schema(only(t.args), sch, Mod)) end function StatsModels.apply_schema(t::ZeroCorr, sch::MultiSchema, Mod::Type{<:MixedModel}) diff --git a/test/FactorReTerm.jl b/test/FactorReTerm.jl index e40c76339..32d266c27 100644 --- a/test/FactorReTerm.jl +++ b/test/FactorReTerm.jl @@ -157,6 +157,12 @@ end @test zc.rhs.sym == :subj end + @testset "Amalgamation of ZeroCorr with other terms" begin + f = @formula(reaction ~ 1 + days + (1|subj) + zerocorr(days|subj)) + m = LMM(f, dataset(:sleepstudy), contrasts = Dict(:days => DummyCoding())) + re = only(m.reterms) + @test length(re.cnames) == length(unique(re.cnames)) == 10 + end end @testset "Categorical Blocking Variable" begin From e5d8a6a01fd102910640b53fe54ab1569147a5ab Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 11 Apr 2023 21:17:49 +0000 Subject: [PATCH 29/51] Deprecate mulithreading in bootstrap (#674) * make use_threads a noop in bootstrap * test deprecation warning instead of results * NEWS * version bump * drop references in docs * remove threading from replicate as well --- NEWS.md | 5 ++++ Project.toml | 2 +- docs/src/bootstrap.md | 2 +- src/bootstrap.jl | 54 +++++++++++-------------------------------- src/utilities.jl | 27 ++++++++-------------- test/bootstrap.jl | 12 ++-------- test/utilities.jl | 12 +--------- 7 files changed, 32 insertions(+), 82 deletions(-) diff --git a/NEWS.md b/NEWS.md index 040e4bb2e..e91a057ac 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.10.0 Release Notes +============================== +* Multithreading in `parametricbootstrap` with `use_threads` is now deprecated and a noop. With improvements in BLAS threading, multithreading at the Julia level did not help performance and sometimes hurt it. [#674] + MixedModels v4.9.0 Release Notes ============================== * Support `StatsModels` 0.7, drop support for `StatsModels` 0.6. [#664] @@ -400,3 +404,4 @@ Package dependencies [#664]: https://github.com/JuliaStats/MixedModels.jl/issues/664 [#665]: https://github.com/JuliaStats/MixedModels.jl/issues/665 [#667]: https://github.com/JuliaStats/MixedModels.jl/issues/667 +[#674]: https://github.com/JuliaStats/MixedModels.jl/issues/674 diff --git a/Project.toml b/Project.toml index ed6f483ef..3ad6caed7 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.9.0" +version = "4.10.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/docs/src/bootstrap.md b/docs/src/bootstrap.md index e6d1e66fb..549c80413 100644 --- a/docs/src/bootstrap.md +++ b/docs/src/bootstrap.md @@ -118,7 +118,7 @@ m2 = fit( DisplayAs.Text(ans) # hide ``` ```@example Main -samp2 = parametricbootstrap(rng, 10_000, m2, use_threads=true); +samp2 = parametricbootstrap(rng, 10_000, m2); df2 = DataFrame(samp2.allpars); first(df2, 10) ``` diff --git a/src/bootstrap.jl b/src/bootstrap.jl index 296a61517..e786ce8ea 100644 --- a/src/bootstrap.jl +++ b/src/bootstrap.jl @@ -36,7 +36,7 @@ end """ parametricbootstrap([rng::AbstractRNG], nsamp::Integer, m::MixedModel{T}, ftype=T; - β = coef(m), σ = m.σ, θ = m.θ, use_threads=false, hide_progress=false) + β = coef(m), σ = m.σ, θ = m.θ, hide_progress=false) Perform `nsamp` parametric bootstrap replication fits of `m`, returning a `MixedModelBootstrap`. @@ -52,20 +52,8 @@ performance benefits. - `β`, `σ`, and `θ` are the values of `m`'s parameters for simulating the responses. - `σ` is only valid for `LinearMixedModel` and `GeneralizedLinearMixedModel` for families with a dispersion parameter. -- `use_threads` determines whether or not to use thread-based parallelism. - `hide_progress` can be used to disable the progress bar. Note that the progress bar is automatically disabled for non-interactive (i.e. logging) contexts. - -!!! note - Note that `use_threads=true` may not offer a performance boost and may even - decrease performance if multithreaded linear algebra (BLAS) routines are available. - In this case, threads at the level of the linear algebra may already occupy all - processors/processor cores. There are plans to provide better support in coordinating - Julia- and BLAS-level threads in the future. - -!!! warning - The PRNG shared between threads is locked using `Threads.SpinLock`, which - should not be used recursively. Do not wrap `parametricbootstrap` in an outer `SpinLock`. """ function parametricbootstrap( rng::AbstractRNG, @@ -88,35 +76,19 @@ function parametricbootstrap( β_names = (Symbol.(fixefnames(morig))...,) - # we need arrays of these for in-place operations to work across threads - m_threads = [m] - βsc_threads = [βsc] - θsc_threads = [θsc] - - if use_threads - Threads.resize_nthreads!(m_threads) - Threads.resize_nthreads!(βsc_threads) - Threads.resize_nthreads!(θsc_threads) - end - # we use locks to guarantee thread-safety, but there might be better ways to do this for some RNGs - # see https://docs.julialang.org/en/v1.3/manual/parallel-computing/#Side-effects-and-mutable-function-arguments-1 - # see https://docs.julialang.org/en/v1/stdlib/Future/index.html - rnglock = Threads.SpinLock() - samp = replicate(n; use_threads=use_threads, hide_progress=hide_progress) do - tidx = use_threads ? Threads.threadid() : 1 - mod = m_threads[tidx] - local βsc = βsc_threads[tidx] - local θsc = θsc_threads[tidx] - lock(rnglock) - mod = simulate!(rng, mod; β=β, σ=σ, θ=θ) - unlock(rnglock) - refit!(mod; progress=false) + use_threads && Base.depwarn( + "use_threads is deprecated and will be removed in a future release", + :parametricbootstrap, + ) + samp = replicate(n; hide_progress=hide_progress) do + simulate!(rng, m; β, σ, θ) + refit!(m; progress=false) ( - objective=ftype.(mod.objective), - σ=ismissing(mod.σ) ? missing : ftype(mod.σ), - β=NamedTuple{β_names}(fixef!(βsc, mod)), - se=SVector{p,ftype}(stderror!(βsc, mod)), - θ=SVector{k,ftype}(getθ!(θsc, mod)), + objective=ftype.(m.objective), + σ=ismissing(m.σ) ? missing : ftype(m.σ), + β=NamedTuple{β_names}(fixef!(βsc, m)), + se=SVector{p,ftype}(stderror!(βsc, m)), + θ=SVector{k,ftype}(getθ!(θsc, m)), ) end return MixedModelBootstrap{ftype}( diff --git a/src/utilities.jl b/src/utilities.jl index bbe6fffd7..71d3b982f 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -124,21 +124,18 @@ end _is_logging(io) = isa(io, Base.TTY) == false || (get(ENV, "CI", nothing) == "true") """ - replicate(f::Function, n::Integer; use_threads=false) + replicate(f::Function, n::Integer; hide_progress=false) Return a vector of the values of `n` calls to `f()` - used in simulations where the value of `f` is stochastic. `hide_progress` can be used to disable the progress bar. Note that the progress bar is automatically disabled for non-interactive (i.e. logging) contexts. - -!!! warning - If `f()` is not thread-safe or depends on a non thread-safe RNG, - then you must set `use_threads=false`. Also note that ordering of replications - is not guaranteed when `use_threads=true`, although the replications are not - otherwise affected for thread-safe `f()`. """ function replicate(f::Function, n::Integer; use_threads=false, hide_progress=false) - # no macro version yet: https://github.com/timholy/ProgressMeter.jl/issues/143 + use_threads && Base.depwarn( + "use_threads is deprecated and will be removed in a future release", + :replicate, + ) # and we want some advanced options p = Progress(n; output=Base.stderr, enabled=!hide_progress && !_is_logging(stderr)) # get the type @@ -146,17 +143,11 @@ function replicate(f::Function, n::Integer; use_threads=false, hide_progress=fal next!(p) # pre-allocate results = [rr for _ in Base.OneTo(n)] - if use_threads - Threads.@threads for idx in 2:n - results[idx] = f() - next!(p) - end - else - for idx in 2:n - results[idx] = f() - next!(p) - end + for idx in 2:n + results[idx] = f() + next!(p) end + finish!(p) return results end diff --git a/test/bootstrap.jl b/test/bootstrap.jl index e581d6882..2899a292a 100644 --- a/test/bootstrap.jl +++ b/test/bootstrap.jl @@ -94,16 +94,8 @@ end @test propertynames(coefp) == [:iter, :coefname, :β, :se, :z, :p] @testset "threaded bootstrap" begin - bsamp_threaded = parametricbootstrap(MersenneTwister(1234321), 100, fm; - use_threads=true, hide_progress=true) - # even though it's bad practice with floating point, exact equality should - # be a valid test here -- if everything is working right, then it's the exact - # same operations occurring within each bootstrap sample, which IEEE 754 - # guarantees will yield the same result - @test sort(bsamp_threaded.σ) == sort(bsamp.σ) - @test sort(bsamp_threaded.θ) == sort(bsamp.θ) - @test sort(columntable(bsamp_threaded.β).β) == sort(columntable(bsamp.β).β) - @test sum(issingular(bsamp)) == sum(issingular(bsamp_threaded)) + @test_logs (:warn, r"use_threads is deprecated") parametricbootstrap(MersenneTwister(1234321), 1, fm; + use_threads=true, hide_progress=true) end @testset "zerocorr + Base.length + ftype" begin diff --git a/test/utilities.jl b/test/utilities.jl index 8ccab24da..71d2d26dc 100644 --- a/test/utilities.jl +++ b/test/utilities.jl @@ -40,17 +40,7 @@ end end @testset "threaded_replicate" begin - rng = StableRNG(42); - single_thread = replicate(10;use_threads=false) do; only(randn(rng, 1)) ; end - rng = StableRNG(42); - multi_thread = replicate(10;use_threads=true) do - if Threads.threadid() % 2 == 0 - sleep(0.001) - end - r = only(randn(rng, 1)); - end - - @test all(sort!(single_thread) .≈ sort!(multi_thread)) + @test_logs (:warn, r"use_threads is deprecated") replicate(string, 1; use_threads=true) end @testset "datasets" begin From 251ef8a4ce43b0be0d05dcc649b4874ad3b6e209 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 12 Apr 2023 16:39:21 +0000 Subject: [PATCH 30/51] support rank deficiency in prediction (#676) * support rank deficiency in prediction * add NEWS * oops * Update NEWS.md --- NEWS.md | 2 ++ src/predict.jl | 23 +++++++++++++------- test/predict.jl | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index e91a057ac..803f85fb8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ MixedModels v4.10.0 Release Notes ============================== +* Rank deficiency in prediction is now supported, both when the original model was fit to rank-deficient data and when the new data are rank deficient. The behavior is consistent but may be surprising when both old and new data are rank deficient. See the `predict` docstring for an example. [#676] * Multithreading in `parametricbootstrap` with `use_threads` is now deprecated and a noop. With improvements in BLAS threading, multithreading at the Julia level did not help performance and sometimes hurt it. [#674] MixedModels v4.9.0 Release Notes @@ -405,3 +406,4 @@ Package dependencies [#665]: https://github.com/JuliaStats/MixedModels.jl/issues/665 [#667]: https://github.com/JuliaStats/MixedModels.jl/issues/667 [#674]: https://github.com/JuliaStats/MixedModels.jl/issues/674 +[#676]: https://github.com/JuliaStats/MixedModels.jl/issues/676 diff --git a/src/predict.jl b/src/predict.jl index d3c0be5c5..d540af353 100644 --- a/src/predict.jl +++ b/src/predict.jl @@ -18,13 +18,20 @@ Predict response for new data. `missing` is not valid because `missing` data are dropped before constructing the model matrices. -!!! warning - Models are assumed to be full rank. - !!! warning These methods construct an entire MixedModel behind the scenes and as such may use a large amount of memory when `newdata` is large. +!!! warning + Rank-deficiency can lead to surprising but consistent behavior. + For example, if there are two perfectly collinear predictors `A` + and `B` (e.g. constant multiples of each other), then it is possible + that `A` will be pivoted out in the fitted model and thus the + associated coefficient is set to zero. If predictions are then + generated on new data where `B` has been set to zero but `A` has + not, then there will no contribution from neither `A` nor `B` + in the resulting predictions. + The keyword argument `new_re_levels` specifies how previously unobserved values of the grouping variable are handled. Possible values are: @@ -63,7 +70,7 @@ Similarly, offsets are also not supported for `GeneralizedLinearMixedModel`. function StatsAPI.predict( m::LinearMixedModel, newdata::Tables.ColumnTable; new_re_levels=:missing ) - return _predict(m, newdata, m.β; new_re_levels) + return _predict(m, newdata, coef(m)[m.feterm.piv]; new_re_levels) end function StatsAPI.predict( @@ -73,13 +80,14 @@ function StatsAPI.predict( type=:response, ) type in (:linpred, :response) || throw(ArgumentError("Invalid value for type: $(type)")) - - y = _predict(m.LMM, newdata, m.β; new_re_levels) + # want pivoted but not truncated + y = _predict(m.LMM, newdata, coef(m)[m.feterm.piv]; new_re_levels) return type == :linpred ? y : broadcast!(Base.Fix1(linkinv, Link(m)), y, y) end # β is separated out here because m.β != m.LMM.β depending on how β is estimated for GLMM +# also β should already be pivoted but NOT truncated in the rank deficient case function _predict(m::MixedModel{T}, newdata, β; new_re_levels) where {T} new_re_levels in (:population, :missing, :error) || throw(ArgumentError("Invalid value for new_re_levels: $(new_re_levels)")) @@ -118,8 +126,9 @@ function _predict(m::MixedModel{T}, newdata, β; new_re_levels) where {T} ytemp, lmm end + pivotmatch = mnew.feterm.piv[m.feterm.piv] grps = fnames(m) - mul!(y, mnew.X, β) + mul!(y, view(mnew.X, :, pivotmatch), β) # mnew.reterms for the correct Z matrices # ranef(m) for the BLUPs from the original fit diff --git a/test/predict.jl b/test/predict.jl index fce35b982..55f2639a0 100644 --- a/test/predict.jl +++ b/test/predict.jl @@ -81,6 +81,61 @@ end @test_throws ArgumentError predict(m, slpm) fill!(slpm.reaction, missing) @test_throws ArgumentError predict(m, slpm) + + end + + @testset "rank deficiency" begin + @testset "in original fit" begin + refvals = predict(first(models(:sleepstudy)), slp) + + slprd = transform(slp, :days => ByRow(x -> 2x) => :days2) + m = fit(MixedModel, @formula(reaction ~ 1 + days + days2 + (1|subj)), slprd; progress=false) + # predict assumes that X is the correct length and stored pivoted + # so these first two tests will fail if we change that storage detail + @test size(m.X) == (180, 3) + @test all(2 .* view(m.X, :, m.feterm.piv[2]) .== view(m.X, :, m.feterm.piv[3])) + @test predict(m, slprd) == refvals + + slprd0 = transform(slp, :days => zero => :days0) + m = fit(MixedModel, @formula(reaction ~ 1 + days0 + days + (1|subj)), slprd0; progress=false) + @test predict(m, slprd0) == refvals + # change the formula order slightly so that the original ordering and hence the + # permutation vector for pivoting isn't identical + m = fit(MixedModel, @formula(reaction ~ 1 + days + days0 + (1|subj)), slprd0; progress=false) + @test predict(m, slprd0) == refvals + end + + @testset "in newdata" begin + mref = first(models(:sleepstudy)) + # remove days + refvals = fitted(mref) .- view(mref.X, :, 2) * mref.β[2] + slp0 = transform(slp, :days => zero => :days) + vals = predict(mref, slp0) + @test all(refvals .≈ vals) + end + + @testset "in both" begin + # now what happens when old and new are rank deficient + mref = first(models(:sleepstudy)) + # remove days + refvals = fitted(mref) .- view(mref.X, :, 2) * mref.β[2] + # days gets pivoted out + slprd = transform(slp, :days => ByRow(x -> 2x) => :days2) + m = fit(MixedModel, @formula(reaction ~ 1 + days + days2 + (1|subj)), slprd; progress=false) + # days2 gets pivoted out + slp0 = transform(slp, :days => zero => :days2) + vals = predict(m, slp0) + # but in the original fit, days gets pivoted out, so its coef is zero + # and now we have a column of zeros for days2 + # leaving us with only the intercept + # this is consistent behavior + @test all(refvals .≈ vals) + + slp1 = transform(slp, :days => ByRow(one) => :days2) + vals = predict(m, slp1) + refvals = fitted(mref) .- view(mref.X, :, 2) * mref.β[2] .+ last(fixef(m)) + @test all(refvals .≈ vals) + end end @testset "transformed response" begin @@ -124,4 +179,5 @@ end @test predict(gm0, contra; type=:response) ≈ gm0.resp.mu rtol=0.01 end end + end From 8ae74f724acb514a1bb844cd6ee96d9c9b9504f3 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Wed, 12 Apr 2023 12:48:43 -0500 Subject: [PATCH 31/51] raneftables returning NamedTuple of DictTables (#634) * raneftables returning NamedTuple of DictTables * Add news item * Bump version to 4.11.0 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Phillip Alday --- NEWS.md | 5 +++++ Project.toml | 4 +++- src/MixedModels.jl | 1 + src/mixedmodel.jl | 13 ++++++++----- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index 803f85fb8..d50244b12 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.11.0 Release Notes +============================== +* `raneftables` returns a `NamedTuple` where the names are the grouping factor names and the values are some `Tables.jl`-compatible type. Currently this type is a `DictTable` from `TypedTables.jl`. [#634] + MixedModels v4.10.0 Release Notes ============================== * Rank deficiency in prediction is now supported, both when the original model was fit to rank-deficient data and when the new data are rank deficient. The behavior is consistent but may be surprising when both old and new data are rank deficient. See the `predict` docstring for an example. [#676] @@ -396,6 +400,7 @@ Package dependencies [#614]: https://github.com/JuliaStats/MixedModels.jl/issues/614 [#615]: https://github.com/JuliaStats/MixedModels.jl/issues/615 [#628]: https://github.com/JuliaStats/MixedModels.jl/issues/628 +[#634]: https://github.com/JuliaStats/MixedModels.jl/issues/634 [#637]: https://github.com/JuliaStats/MixedModels.jl/issues/637 [#648]: https://github.com/JuliaStats/MixedModels.jl/issues/648 [#651]: https://github.com/JuliaStats/MixedModels.jl/issues/651 diff --git a/Project.toml b/Project.toml index 3ad6caed7..2f20f75d6 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.10.0" +version = "4.11.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" @@ -26,6 +26,7 @@ StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d" StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" [compat] Arrow = "1, 2" @@ -45,6 +46,7 @@ StatsFuns = "0.8, 0.9, 1" StatsModels = "0.7" StructTypes = "1" Tables = "1" +TypedTables = "1" julia = "1.8" [extras] diff --git a/src/MixedModels.jl b/src/MixedModels.jl index 846def1b4..bbebf4773 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -20,6 +20,7 @@ using StatsBase using StatsModels using StructTypes using Tables +using TypedTables using LinearAlgebra: BlasFloat, BlasReal, HermOrSym, PosDefException, copytri! using Base: Ryu, require_one_based_indexing diff --git a/src/mixedmodel.jl b/src/mixedmodel.jl index 45812ad3f..7106ffe9d 100644 --- a/src/mixedmodel.jl +++ b/src/mixedmodel.jl @@ -91,16 +91,19 @@ StatsAPI.nobs(m::MixedModel) = length(m.y) StatsAPI.predict(m::MixedModel) = fitted(m) function retbl(mat, trm) - return merge( - NamedTuple{(fname(trm),)}((trm.levels,)), - columntable(Tables.table(transpose(mat); header=Symbol.(trm.cnames))), - ) + nms = (fname(trm), Symbol.(trm.cnames)...) + return DictTable( + [NamedTuple{nms}((l, view(mat, :, i)...),) for (i, l) in enumerate(trm.levels)] +) end """ raneftables(m::MixedModel; uscale = false) -Return the conditional means of the random effects as a `NamedTuple` of columntables +Return the conditional means of the random effects as a `NamedTuple` of Tables.jl-compliant tables. + +!!! note + The API guarantee is only that the NamedTuple contains Tables.jl tables and not on the particular concrete type of each table. """ function raneftables(m::MixedModel{T}; uscale=false) where {T} return NamedTuple{fnames(m)}((map(retbl, ranef(m; uscale=uscale), m.reterms)...,)) From 564ce23f6e176faafb492c3f0b1f6a5bbad644bc Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 14 Apr 2023 17:22:14 +0000 Subject: [PATCH 32/51] better compatibility with RegressionFormulae.jl (#677) * better compatibility with RegressionFormulae.jl * NEWS --- NEWS.md | 5 +++++ Project.toml | 2 +- src/randomeffectsterm.jl | 6 ++++-- test/FactorReTerm.jl | 27 +++------------------------ 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/NEWS.md b/NEWS.md index d50244b12..5f69adfa1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.12.0 Release Notes +============================== +* The pirated method `Base.:/(a::AbstractTerm, b::AbstractTerm)` is no longer defined. This does not impact the use of `/` as a nesting term in `@formula` within MixedModels, only the programmatic runtime construction of formula, e.g. `term(:a) / term(:b)`. If you require `Base.:/`, then [`RegressionFormulae.jl`](https://github.com/kleinschmidt/RegressionFormulae.jl) provides this method. (Avoiding method redefinition when using `RegressionFormulae.jl` is the motivating reason for this change.) [#677] + MixedModels v4.11.0 Release Notes ============================== * `raneftables` returns a `NamedTuple` where the names are the grouping factor names and the values are some `Tables.jl`-compatible type. Currently this type is a `DictTable` from `TypedTables.jl`. [#634] @@ -412,3 +416,4 @@ Package dependencies [#667]: https://github.com/JuliaStats/MixedModels.jl/issues/667 [#674]: https://github.com/JuliaStats/MixedModels.jl/issues/674 [#676]: https://github.com/JuliaStats/MixedModels.jl/issues/676 +[#677]: https://github.com/JuliaStats/MixedModels.jl/issues/677 diff --git a/Project.toml b/Project.toml index 2f20f75d6..51a325b35 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.11.0" +version = "4.12.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/randomeffectsterm.jl b/src/randomeffectsterm.jl index a5876d8f3..a17b34f53 100644 --- a/src/randomeffectsterm.jl +++ b/src/randomeffectsterm.jl @@ -139,8 +139,10 @@ function _ranef_refs( return refs, uniques end -# TODO: split this off into a RegressionFormula package? -Base.:/(a::AbstractTerm, b::AbstractTerm) = a + a & b +# TODO: remove all of this and either +# - require users to use RegressionFormulae.jl +# - add a dependency on RegressionFormulae.jl + function StatsModels.apply_schema( t::FunctionTerm{typeof(/)}, sch::StatsModels.FullRank, Mod::Type{<:MixedModel} ) diff --git a/test/FactorReTerm.jl b/test/FactorReTerm.jl index 32d266c27..24a584c02 100644 --- a/test/FactorReTerm.jl +++ b/test/FactorReTerm.jl @@ -245,31 +245,11 @@ end @test modelcols(f2.rhs, d2) == [ones(20) d2.b .== :Y (d2.b .== :X).*d2.a (d2.b .== :Y).*d2.a] @test coefnames(f2.rhs) == ["(Intercept)", "b: Y", "b: X & a", "b: Y & a"] - # runtime - fr2 = term(1) + term(:b) / term(:a) - @test length(fr2) == 3 - @test fr2[1] isa ConstantTerm - @test fr2[2] isa Term - @test fr2[3] isa InteractionTerm - frf2 = apply_schema(term(0) ~ fr2, schema(d2), MixedModel) - @test modelcols(frf2.rhs, d2) == [ones(20) d2.b .== :Y (d2.b .== :X).*d2.a (d2.b .== :Y).*d2.a] - @test coefnames(frf2.rhs) == ["(Intercept)", "b: Y", "b: X & a", "b: Y & a"] - # check promotion f3 = apply_schema(@formula(0 ~ 0 + b/a), schema(d2), MixedModel) @test modelcols(f3.rhs, d2) == [d2.b .== :X d2.b .== :Y (d2.b .== :X).*d2.a (d2.b .== :Y).*d2.a] @test coefnames(f3.rhs) == ["b: X", "b: Y", "b: X & a", "b: Y & a"] - # runtime: - fr3 = term(0) + term(:b) / term(:a) - @test length(fr3) == 3 - @test fr3[1] isa ConstantTerm - @test fr3[2] isa Term - @test fr3[3] isa InteractionTerm - ffr3 = apply_schema(term(0) ~ fr3, schema(d2), MixedModel) - @test modelcols(ffr3.rhs, d2) == [d2.b .== :X d2.b .== :Y (d2.b .== :X).*d2.a (d2.b .== :Y).*d2.a] - @test coefnames(ffr3.rhs) == ["b: X", "b: Y", "b: X & a", "b: Y & a"] - # errors for continuous grouping @test_throws ArgumentError apply_schema(@formula(0 ~ 1 + a/b), schema(d2), MixedModel) @@ -280,12 +260,11 @@ end psts = dataset("pastes") m = fit(MixedModel, @formula(strength ~ 1 + (1|batch/cask)), psts; progress=false) m2 = fit(MixedModel, @formula(strength ~ 1 + (1|batch) + (1|batch&cask)), psts; progress=false) - mr = fit(MixedModel, term(:strength) ~ term(1) + (term(1)|term(:batch)/term(:cask)), psts; progress=false) m2r = fit(MixedModel, term(:strength) ~ term(1) + (term(1)|term(:batch)) + (term(1)|term(:batch)&term(:cask)), psts; progress=false) - @test fnames(m) == fnames(m2) == fnames(mr) == fnames(m2r) == (Symbol("batch & cask"), :batch) - @test m.λ == m2.λ == mr.λ == m2r.λ - @test deviance(m) == deviance(m2) == deviance(mr) == deviance(m2r) + @test fnames(m) == fnames(m2) == fnames(m2r) == (Symbol("batch & cask"), :batch) + @test m.λ == m2.λ == m2r.λ + @test deviance(m) == deviance(m2) == deviance(m2r) end @testset "multiple terms with same grouping" begin From 41bfe224c0560430e350d97f1baf4e6e5f04005c Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Tue, 25 Apr 2023 07:23:11 -0500 Subject: [PATCH 33/51] Migrate from SnoopPrecompile to PrecompileTools (#681) * Migrate from SnoopPrecompile to PrecompileTools * alphabetical ordering --- Project.toml | 4 ++-- src/MixedModels.jl | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index 51a325b35..038dd3f65 100644 --- a/Project.toml +++ b/Project.toml @@ -14,9 +14,9 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" NLopt = "76087f3c-5699-56af-9a33-bf431cd00edd" PooledArrays = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" +PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SnoopPrecompile = "66db9d55-30c0-4569-8b51-7e840670fc0c" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" @@ -37,8 +37,8 @@ JSON3 = "1" LazyArtifacts = "1" NLopt = "0.5, 0.6" PooledArrays = "0.5, 1" +PrecompileTools = "1" ProgressMeter = "1.7" -SnoopPrecompile = "1" StaticArrays = "0.11, 0.12, 1" StatsAPI = "1.5" StatsBase = "0.31, 0.32, 0.33" diff --git a/src/MixedModels.jl b/src/MixedModels.jl index bbebf4773..b2041f9b5 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -179,15 +179,15 @@ include("grouping.jl") include("mimeshow.jl") include("serialization.jl") -using SnoopPrecompile +using PrecompileTools -@precompile_setup begin +@setup_workload begin # Putting some things in `setup` can reduce the size of the # precompile file and potentially make loading faster. sleepstudy = MixedModels.dataset(:sleepstudy) contra = MixedModels.dataset(:contra) progress = false - @precompile_all_calls begin + @compile_workload begin # all calls in this block will be precompiled, regardless of whether # they belong to your package or not (on Julia 1.8 and higher) From 52accc37269e3c8e28b882f6e6a0943d41ff1931 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 25 Apr 2023 14:02:30 +0000 Subject: [PATCH 34/51] remove explicit Vararg (#680) * remove explicit Vararg * NEWS and patch bump * add news for precompile backend * ignore LocalPreferences.toml --- .gitignore | 2 ++ NEWS.md | 7 +++++++ Project.toml | 2 +- src/randomeffectsterm.jl | 2 +- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ed4438abb..1e9f9910a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ tune.json Manifest.toml settings.json docs/jmd +LocalPreferences.toml + diff --git a/NEWS.md b/NEWS.md index 5f69adfa1..d477beb17 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +MixedModels v4.12.1 Release Notes +============================== +* Precompilation is now handled with `PrecompileTools` instead of `SnoopPrecompile`. [#681] +* An unnecessary explicit `Vararg` in an internal method has been removed. This removal eliminates a compiler warning about the deprecated `Vararg` pattern. [#680] + MixedModels v4.12.0 Release Notes ============================== * The pirated method `Base.:/(a::AbstractTerm, b::AbstractTerm)` is no longer defined. This does not impact the use of `/` as a nesting term in `@formula` within MixedModels, only the programmatic runtime construction of formula, e.g. `term(:a) / term(:b)`. If you require `Base.:/`, then [`RegressionFormulae.jl`](https://github.com/kleinschmidt/RegressionFormulae.jl) provides this method. (Avoiding method redefinition when using `RegressionFormulae.jl` is the motivating reason for this change.) [#677] @@ -417,3 +422,5 @@ Package dependencies [#674]: https://github.com/JuliaStats/MixedModels.jl/issues/674 [#676]: https://github.com/JuliaStats/MixedModels.jl/issues/676 [#677]: https://github.com/JuliaStats/MixedModels.jl/issues/677 +[#680]: https://github.com/JuliaStats/MixedModels.jl/issues/680 +[#681]: https://github.com/JuliaStats/MixedModels.jl/issues/681 diff --git a/Project.toml b/Project.toml index 038dd3f65..4335f633e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.12.0" +version = "4.12.1" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/randomeffectsterm.jl b/src/randomeffectsterm.jl index a17b34f53..a742b7baa 100644 --- a/src/randomeffectsterm.jl +++ b/src/randomeffectsterm.jl @@ -50,7 +50,7 @@ const GROUPING_TYPE = Union{ <:CategoricalTerm,<:InteractionTerm{<:NTuple{N,CategoricalTerm} where {N}} } check_re_group_type(term::GROUPING_TYPE) = true -check_re_group_type(terms::Tuple{Vararg{<:GROUPING_TYPE}}) = true +check_re_group_type(term::Tuple) = all(check_re_group_type, term) check_re_group_type(x) = false _unprotect(x) = x From 421fe2138c5c4484ca5783c2fa747384fc8ed5db Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Tue, 25 Apr 2023 10:59:50 -0500 Subject: [PATCH 35/51] undo #634, return Table not DictTable (#682) * undo #634 return Table not DictTable Co-authored-by: Phillip Alday --- NEWS.md | 5 +++++ src/mixedmodel.jl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index d477beb17..3029f1db0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.13.0 Release Notes +============================== +* `raneftables` returns a `NamedTuple` where the names are the grouping factor names and the values are some `Tables.jl`-compatible type. This type has been changed to a `Table` from `TypedTables.jl`. [#682] + MixedModels v4.12.1 Release Notes ============================== * Precompilation is now handled with `PrecompileTools` instead of `SnoopPrecompile`. [#681] @@ -424,3 +428,4 @@ Package dependencies [#677]: https://github.com/JuliaStats/MixedModels.jl/issues/677 [#680]: https://github.com/JuliaStats/MixedModels.jl/issues/680 [#681]: https://github.com/JuliaStats/MixedModels.jl/issues/681 +[#682]: https://github.com/JuliaStats/MixedModels.jl/issues/682 diff --git a/src/mixedmodel.jl b/src/mixedmodel.jl index 7106ffe9d..475a39252 100644 --- a/src/mixedmodel.jl +++ b/src/mixedmodel.jl @@ -92,7 +92,7 @@ StatsAPI.predict(m::MixedModel) = fitted(m) function retbl(mat, trm) nms = (fname(trm), Symbol.(trm.cnames)...) - return DictTable( + return Table( [NamedTuple{nms}((l, view(mat, :, i)...),) for (i, l) in enumerate(trm.levels)] ) end From 1bfad8a6ed7fd57e2c25f48289a314a3dcab5138 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Tue, 25 Apr 2023 11:29:00 -0500 Subject: [PATCH 36/51] Bump version number (#685) --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4335f633e..0afa08b15 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.12.1" +version = "4.13.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" From d946f6f26fb9f097f1be330e0b3e09244549257c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 3 May 2023 03:46:35 +0000 Subject: [PATCH 37/51] CompatHelper: bump compat for StatsBase to 0.34, (keep existing compat) (#687) * CompatHelper: bump compat for StatsBase to 0.34, (keep existing compat) * Update Project.toml --------- Co-authored-by: CompatHelper Julia Co-authored-by: Phillip Alday --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 0afa08b15..5319ab3b6 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.13.0" +version = "4.13.1" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" @@ -41,7 +41,7 @@ PrecompileTools = "1" ProgressMeter = "1.7" StaticArrays = "0.11, 0.12, 1" StatsAPI = "1.5" -StatsBase = "0.31, 0.32, 0.33" +StatsBase = "0.31, 0.32, 0.33, 0.34" StatsFuns = "0.8, 0.9, 1" StatsModels = "0.7" StructTypes = "1" From 25ed4e87b74c5244450ecf0a47a610ab6e127df6 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Thu, 4 May 2023 13:40:45 -0500 Subject: [PATCH 38/51] Profile the objective (#639) * add `profile` method and `MixedModelProfile` type * using BSplineKit, add confint for model and prof * Add BSplineKit and TypedTables to Project.toml Co-authored-by: Phillip Alday --- NEWS.md | 6 ++ Project.toml | 4 +- src/MixedModels.jl | 9 ++ src/bootstrap.jl | 80 ++++++++++++++++++ src/linearmixedmodel.jl | 77 ++++++++++++++++- src/profile/fixefpr.jl | 107 +++++++++++++++++++++++ src/profile/profile.jl | 82 ++++++++++++++++++ src/profile/sigmapr.jl | 75 +++++++++++++++++ src/profile/thetapr.jl | 103 +++++++++++++++++++++++ src/profile/utilities.jl | 177 +++++++++++++++++++++++++++++++++++++++ src/profile/vcpr.jl | 92 ++++++++++++++++++++ src/remat.jl | 67 ++++++++++++--- src/utilities.jl | 2 +- test/Project.toml | 3 +- test/bootstrap.jl | 12 +++ test/pls.jl | 47 ++++++++++- 16 files changed, 923 insertions(+), 20 deletions(-) create mode 100644 src/profile/fixefpr.jl create mode 100644 src/profile/profile.jl create mode 100644 src/profile/sigmapr.jl create mode 100644 src/profile/thetapr.jl create mode 100644 src/profile/utilities.jl create mode 100644 src/profile/vcpr.jl diff --git a/NEWS.md b/NEWS.md index 3029f1db0..ed5d9e1dd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +MixedModels v4.14.0 Release Notes +============================== +* New function `profile` for computing likelihood profiles for `LinearMixedModel`. The resultant `MixedModelProfile` can be then be used for computing confidence intervals with `confint`. Note that this API is still somewhat experimental and as such the internal storage details of `MixedModelProfile` may change in a future release without being considered breaking. [#639] +* A `confint(::LinearMixedModel)` method has been defined that returns Wald confidence intervals based on the z-statistic, i.e. treating the denominator degrees of freedom as infinite. [#639] + MixedModels v4.13.0 Release Notes ============================== * `raneftables` returns a `NamedTuple` where the names are the grouping factor names and the values are some `Tables.jl`-compatible type. This type has been changed to a `Table` from `TypedTables.jl`. [#682] @@ -415,6 +420,7 @@ Package dependencies [#628]: https://github.com/JuliaStats/MixedModels.jl/issues/628 [#634]: https://github.com/JuliaStats/MixedModels.jl/issues/634 [#637]: https://github.com/JuliaStats/MixedModels.jl/issues/637 +[#639]: https://github.com/JuliaStats/MixedModels.jl/issues/639 [#648]: https://github.com/JuliaStats/MixedModels.jl/issues/648 [#651]: https://github.com/JuliaStats/MixedModels.jl/issues/651 [#653]: https://github.com/JuliaStats/MixedModels.jl/issues/653 diff --git a/Project.toml b/Project.toml index 5319ab3b6..faa92debb 100644 --- a/Project.toml +++ b/Project.toml @@ -1,10 +1,11 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.13.1" +version = "4.14.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" +BSplineKit = "093aae92-e908-43d7-9660-e50ee39d5a0a" DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a" @@ -30,6 +31,7 @@ TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" [compat] Arrow = "1, 2" +BSplineKit = "0.14,0.15" DataAPI = "1" Distributions = "0.21, 0.22, 0.23, 0.24, 0.25" GLM = "1.8.2" diff --git a/src/MixedModels.jl b/src/MixedModels.jl index b2041f9b5..38c37dc04 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -1,6 +1,7 @@ module MixedModels using Arrow +using BSplineKit using DataAPI using Distributions using GLM @@ -51,6 +52,7 @@ export @formula, LogLink, MixedModel, MixedModelBootstrap, + MixedModelProfile, Normal, OptSummary, Poisson, @@ -60,6 +62,7 @@ export @formula, ReMat, SeqDiffCoding, SqrtLink, + Table, UniformBlockDiagonal, VarCorr, aic, @@ -73,6 +76,7 @@ export @formula, cond, condVar, condVartables, + confint, deviance, dispersion, dispersion_parameter, @@ -101,9 +105,13 @@ export @formula, model_response, nobs, objective, + objective!, parametricbootstrap, pirls!, predict, + profile, + profileσ, + profilevc, pwrss, ranef, raneftables, @@ -178,6 +186,7 @@ include("blockdescription.jl") include("grouping.jl") include("mimeshow.jl") include("serialization.jl") +include("profile/profile.jl") using PrecompileTools diff --git a/src/bootstrap.jl b/src/bootstrap.jl index e786ce8ea..c76257961 100644 --- a/src/bootstrap.jl +++ b/src/bootstrap.jl @@ -165,6 +165,45 @@ function allpars(bsamp::MixedModelFitCollection{T}) where {T} ) end +""" + confint(pr::MixedModelBootstrap; level::Real=0.95) + +Compute bootstrap confidence intervals for coefficients and variance components, with confidence level level (by default 95%). + +!!! note + The API guarantee is for a Tables.jl compatible table. The exact return type is an + implementation detail and may change in a future minor release without being considered + breaking. + +!!! note + The "row names" indicating the associated parameter name are guaranteed to be unambiguous, + but their precise naming scheme is not yet stable and may change in a future release + without being considered breaking. + +See also [`shortestcovint`](@ref). +""" +function StatsBase.confint(bsamp::MixedModelBootstrap{T}; level::Real=0.95) where {T} + cutoff = sqrt(quantile(Chisq(1), level)) + # Creating the table is somewhat wasteful because columns are created then immediately skipped. + tbl = Table(bsamp.tbl) + lower = T[] + upper = T[] + v = similar(tbl.σ) + par = sort!( + collect( + filter( + k -> !(startswith(string(k), 'θ') || string(k) == "obj"), propertynames(tbl) + ), + ), + ) + for p in par + l, u = shortestcovint(sort!(copyto!(v, getproperty(tbl, p))), level) + push!(lower, l) + push!(upper, u) + end + return DictTable(; par, lower, upper) +end + function Base.getproperty(bsamp::MixedModelFitCollection, s::Symbol) if s ∈ [:objective, :σ, :θ, :se] getproperty.(getfield(bsamp, :fits), s) @@ -176,6 +215,8 @@ function Base.getproperty(bsamp::MixedModelFitCollection, s::Symbol) tidyσs(bsamp) elseif s == :allpars allpars(bsamp) + elseif s == :tbl + pbstrtbl(bsamp) else getfield(bsamp, s) end @@ -209,6 +250,7 @@ function Base.propertynames(bsamp::MixedModelFitCollection) :lowerbd, :fits, :fcnames, + :tbl, ] end @@ -364,3 +406,41 @@ function tidyσs(bsamp::MixedModelFitCollection{T}) where {T} end return result end + +function pbstrtbl(bsamp::MixedModelFitCollection{T}) where {T} + (; fits, λ, inds) = bsamp + row1 = first(fits) + cnms = [:obj, :σ] + pos = Dict{Symbol,UnitRange{Int}}(:obj => 1:1, :σ => 2:2) + βsz = length(row1.β) + append!(cnms, _generatesyms('β', βsz)) + lastpos = 2 + βsz + pos[:β] = 3:lastpos + σsz = sum(m -> size(m, 1), bsamp.λ) + append!(cnms, _generatesyms('σ', σsz)) + pos[:σs] = (lastpos + 1):(lastpos + σsz) + lastpos += σsz + θsz = length(row1.θ) + append!(cnms, _generatesyms('θ', θsz)) + pos[:θ] = (lastpos + 1):(lastpos + θsz) + tblrowtyp = NamedTuple{(cnms...,),NTuple{length(cnms),T}} + val = sizehint!(tblrowtyp[], length(bsamp.fits)) + v = Vector{T}(undef, length(cnms)) + for (i, r) in enumerate(bsamp.fits) + v[1] = r.objective + v[2] = coalesce(r.σ, one(T)) + copyto!(view(v, pos[:β]), r.β) + fill!(view(v, pos[:σs]), zero(T)) + copyto!(view(v, pos[:θ]), r.θ) + setθ!(bsamp, i) + vpos = first(pos[:σs]) + for l in λ + for λr in eachrow(l) + v[vpos] = r.σ * norm(λr) + vpos += 1 + end + end + push!(val, tblrowtyp(v)) + end + return val +end diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index e69998f65..c06f607fc 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -30,7 +30,7 @@ Linear mixed-effects model representation """ struct LinearMixedModel{T<:AbstractFloat} <: MixedModel{T} formula::FormulaTerm - reterms::Vector{AbstractReMat{T}} + reterms::Vector{<:AbstractReMat{T}} Xymat::FeMat{T} feterm::FeTerm{T} sqrtwts::Vector{T} @@ -359,12 +359,33 @@ function condVartables(m::MixedModel{T}) where {T} return NamedTuple{fnames(m)}((map(_cvtbl, condVar(m), m.reterms)...,)) end +""" + confint(pr::MixedModelProfile; level::Real=0.95) + +Compute profile confidence intervals for (fixed effects) coefficients, with confidence level `level` (by default 95%). + +!!! note + The API guarantee is for a Tables.jl compatible table. The exact return type is an + implementation detail and may change in a future minor release without being considered + breaking. + +""" +function StatsBase.confint(m::MixedModel{T}; level=0.95) where {T} + cutoff = sqrt.(quantile(Chisq(1), level)) + β, std = m.β, m.stderror + return DictTable(; + coef=coefnames(m), + lower=β .- cutoff .* std, + upper=β .+ cutoff .* std + ) +end + function _pushALblock!(A, L, blk) push!(L, blk) return push!(A, deepcopy(isa(blk, BlockedSparse) ? blk.cscmat : blk)) end -function createAL(reterms::Vector{AbstractReMat{T}}, Xy::FeMat{T}) where {T} +function createAL(reterms::Vector{<:AbstractReMat{T}}, Xy::FeMat{T}) where {T} k = length(reterms) vlen = kchoose2(k + 1) A = sizehint!(AbstractMatrix{T}[], vlen) @@ -548,7 +569,6 @@ the length of `v` can be the rank of `X` or the number of columns of `X`. In th case the calculated coefficients are padded with -0.0 out to the number of columns. """ function fixef!(v::AbstractVector{Tv}, m::LinearMixedModel{T}) where {Tv,T} - Xtrm = m.feterm fill!(v, -zero(Tv)) XyL = m.L[end] L = feL(m) @@ -765,7 +785,7 @@ end lowerbd(m::LinearMixedModel) = m.optsum.lowerbd -function mkparmap(reterms::Vector{AbstractReMat{T}}) where {T} +function mkparmap(reterms::Vector{<:AbstractReMat{T}}) where {T} parmap = NTuple{3,Int}[] for (k, trm) in enumerate(reterms) n = LinearAlgebra.checksquare(trm.λ) @@ -796,6 +816,37 @@ function objective(m::LinearMixedModel{T}) where {T} return isempty(wts) ? val : val - T(2.0) * sum(log, wts) end +""" + objective!(m::LinearMixedModel, θ) + objective!(m::LinearMixedModel) + +Equivalent to `objective(updateL!(setθ!(m, θ)))`. + +When `m` has a single, scalar random-effects term, `θ` can be a scalar. + +The one-argument method curries and returns a single-argument function of `θ`. + +Note that these methods modify `m`. +The calling function is responsible for restoring the optimal `θ`. +""" +function objective! end + +function objective!(m::LinearMixedModel) + return Base.Fix1(objective!, m) +end + +function objective!(m::LinearMixedModel{T}, θ) where {T} + return objective(updateL!(setθ!(m, θ))) +end + +function objective!(m::LinearMixedModel{T}, x::Number) where {T} + retrm = only(m.reterms) + isa(retrm, ReMat{T,1}) || + throw(DimensionMismatch("length(m.θ) = $(length(m.θ)), should be 1")) + copyto!(retrm.λ.data, x) + return objective(updateL!(m)) +end + function Base.propertynames(m::LinearMixedModel, private::Bool=false) return ( fieldnames(LinearMixedModel)..., @@ -996,6 +1047,24 @@ function setθ!(m::LinearMixedModel{T}, θ::AbstractVector) where {T} return m end +# This method is nearly identical to the previous one but determining a common signature +# to collapse these to a single definition would be tricky, so we repeat ourselves. +function setθ!(m::LinearMixedModel{T}, θ::NTuple{N,T}) where {T,N} + parmap, reterms = m.parmap, m.reterms + N == length(parmap) || throw(DimensionMismatch()) + reind = 1 + λ = first(reterms).λ + for (tv, tr) in zip(θ, parmap) + tr1 = first(tr) + if reind ≠ tr1 + reind = tr1 + λ = reterms[tr1].λ + end + λ[tr[2], tr[3]] = tv + end + return m +end + function Base.setproperty!(m::LinearMixedModel, s::Symbol, y) return s == :θ ? setθ!(m, y) : setfield!(m, s, y) end diff --git a/src/profile/fixefpr.jl b/src/profile/fixefpr.jl new file mode 100644 index 000000000..98ab98166 --- /dev/null +++ b/src/profile/fixefpr.jl @@ -0,0 +1,107 @@ +struct FeProfile{T<:AbstractFloat} # derived model with the j'th fixed-effects coefficient held constant + m::LinearMixedModel{T} # copy of original model after removing the j'th column from X + tc::TableColumns{T} + y₀::Vector{T} # original response vector + xⱼ::Vector{T} # the column that was removed from X + j::Integer +end + +""" + Base.copy(ReMat{T,S}) + +Return a shallow copy of ReMat. + +A shallow copy shares as much internal storage as possible with the original ReMat. +Only the vector `λ` and the `scratch` matrix are copied. +""" +function Base.copy(ret::ReMat{T,S}) where {T,S} + return ReMat{T,S}(ret.trm, + ret.refs, + ret.levels, + ret.cnames, + ret.z, + ret.wtz, + copy(ret.λ), + ret.inds, + ret.adjA, + copy(ret.scratch)) +end + +## FIXME: also create a shallow copy of a LinearMixedModel object that performs a shallow copy of the reterms and the optsum. +## Probably don't bother to copy the components of L as we will always assume that an updateL! call precedes a call to +## objective. + +function FeProfile(m::LinearMixedModel, tc::TableColumns, j::Integer) + Xy = m.Xymat.xy + xcols = collect(axes(Xy, 2)) + ycol = pop!(xcols) + notj = deleteat!(xcols, j) # indirectly check that j ∈ xcols + y₀ = Xy[:, ycol] + xⱼ = Xy[:, j] + feterm = FeTerm(Xy[:, notj], m.feterm.cnames[notj]) + reterms = [copy(ret) for ret in m.reterms] + mnew = fit!( + LinearMixedModel(y₀ - xⱼ * m.β[j], feterm, reterms, m.formula); progress=false + ) + # not sure this next call makes sense - should the second argument be m.optsum.final? + _copy_away_from_lowerbd!( + mnew.optsum.initial, mnew.optsum.final, mnew.lowerbd; incr=0.05 + ) + return FeProfile(mnew, tc, y₀, xⱼ, j) +end + +function betaprofile!( + pr::FeProfile{T}, tc::TableColumns{T}, βⱼ::T, j::Integer, obj::T, neg::Bool +) where {T} + prm = pr.m + refit!(prm, mul!(copyto!(prm.y, pr.y₀), pr.xⱼ, βⱼ, -1, 1); progress=false) + (; positions, v) = tc + v[1] = (-1)^neg * sqrt(prm.objective - obj) + getθ!(view(v, positions[:θ]), prm) + v[first(positions[:σ])] = prm.σ + σvals!(view(v, positions[:σs]), prm) + β = prm.β + bpos = 0 + for (i, p) in enumerate(positions[:β]) + v[p] = (i == j) ? βⱼ : β[(bpos += 1)] + end + return first(v) +end + +function profileβj!( + val::NamedTuple, tc::TableColumns{T,N}, sym::Symbol; threshold=4 +) where {T,N} + m = val.m + (; β, θ, σ, stderror, objective) = m + (; cnames, v) = tc + pnm = (; p=sym) + j = parsej(sym) + prj = FeProfile(m, tc, j) + st = stderror[j] * 0.5 + bb = β[j] - st + tbl = [merge(pnm, mkrow!(tc, m, zero(T)))] + while true + ζ = betaprofile!(prj, tc, bb, j, objective, true) + push!(tbl, merge(pnm, NamedTuple{cnames,NTuple{N,T}}((v...,)))) + if abs(ζ) > threshold + break + end + bb -= st + end + reverse!(tbl) + bb = β[j] + st + while true + ζ = betaprofile!(prj, tc, bb, j, objective, false) + push!(tbl, merge(pnm, NamedTuple{cnames,NTuple{N,T}}((v...,)))) + if abs(ζ) > threshold + break + end + bb += st + end + append!(val.tbl, tbl) + ζv = getproperty.(tbl, :ζ) + βv = getproperty.(tbl, sym) + val.fwd[sym] = interpolate(βv, ζv, BSplineOrder(4), Natural()) + val.rev[sym] = interpolate(ζv, βv, BSplineOrder(4), Natural()) + return val +end diff --git a/src/profile/profile.jl b/src/profile/profile.jl new file mode 100644 index 000000000..6c825da28 --- /dev/null +++ b/src/profile/profile.jl @@ -0,0 +1,82 @@ +""" + MixedModelProfile{T<:AbstractFloat} + +Type representing a likelihood profile of a [`LinearMixedModel`](@ref), including associated interpolation splines. + +The function [`profile`](@ref) is used for computing profiles, while [`confint`](@ref) provides a useful method for constructing confidence intervals from a `MixedModelProfile`. + +!!! note + The exact fields and their representation are considered implementation details and are + **not** part of the public API. +""" +struct MixedModelProfile{T<:AbstractFloat} + m::LinearMixedModel{T} # Model that has been profiled + tbl::Table # Table containing ζ, σ, β, and θ from each conditional fit + fwd::Dict{Symbol} # Interpolation splines for ζ as a function of a parameter + rev::Dict{Symbol} # Interpolation splines for a parameter as a function of ζ +end + +include("utilities.jl") +include("fixefpr.jl") +include("sigmapr.jl") +include("thetapr.jl") +include("vcpr.jl") + +""" + profile(m::LinearMixedModel; threshold = 4) + +Return a `MixedModelProfile` for the objective of `m` with respect to the fixed-effects coefficients. + +`m` is `refit!` if `!isfitted(m)`. + +Profiling starts at the parameter estimate and continues until reaching a parameter bound or the absolute +value of ζ exceeds `threshold`. +""" +function profile(m::LinearMixedModel; threshold=4) + isfitted(m) || refit!(m) + final = copy(m.optsum.final) + tc = TableColumns(m) + val = profileσ(m, tc; threshold) # FIXME: defer creating the splines until the whole table is constructed + objective!(m, final) # restore the parameter estimates + for s in filter(s -> startswith(string(s), 'β'), keys(first(val.tbl))) + profileβj!(val, tc, s; threshold) + end + copyto!(m.optsum.final, final) + m.optsum.fmin = objective!(m, final) + for s in filter(s -> startswith(string(s), 'θ'), keys(first(val.tbl))) + profileθj!(val, s, tc; threshold) + end + profileσs!(val, tc) + objective!(m, final) # restore the parameter estimates + copyto!(m.optsum.final, final) + m.optsum.fmin = objective(m) + m.optsum.sigma = nothing + return MixedModelProfile(m, Table(val.tbl), val.fwd, val.rev) +end + +""" + confint(pr::MixedModelProfile; level::Real=0.95) + +Compute profile confidence intervals for coefficients and variance components, with confidence level level (by default 95%). + +!!! note + The API guarantee is for a Tables.jl compatible table. The exact return type is an + implementation detail and may change in a future minor release without being considered + breaking. + +!!! note + The "row names" indicating the associated parameter name are guaranteed to be unambiguous, + but their precise naming scheme is not yet stable and may change in a future release + without being considered breaking. +""" +function StatsAPI.confint(pr::MixedModelProfile; level::Real=0.95) + cutoff = sqrt(quantile(Chisq(1), level)) + rev = pr.rev + syms = sort!(collect(filter(k -> !startswith(string(k), 'θ'), keys(rev)))) + return DictTable(; + par=syms, + estimate=[rev[s](false) for s in syms], + lower=[rev[s](-cutoff) for s in syms], + upper=[rev[s](cutoff) for s in syms], + ) +end diff --git a/src/profile/sigmapr.jl b/src/profile/sigmapr.jl new file mode 100644 index 000000000..2fbf9cf22 --- /dev/null +++ b/src/profile/sigmapr.jl @@ -0,0 +1,75 @@ +""" + refitσ!(m::LinearMixedModel{T}, σ::T, tc::TableColumns{T}, obj::T, neg::Bool) + +Refit the model `m` with the given value of `σ` and return a NamedTuple of information about the fit. + +`obj` and `neg` allow for conversion of the objective to the `ζ` scale and `tc` is used to return a NamedTuple + +!!! note + This method is internal and may change or disappear in a future release + without being considered breaking. +""" +function refitσ!( + m::LinearMixedModel{T}, σ, tc::TableColumns{T}, obj::T, neg::Bool +) where {T} + m.optsum.sigma = σ + refit!(m; progress=false) + return mkrow!(tc, m, (neg ? -one(T) : one(T)) * sqrt(m.objective - obj)) +end + +""" + _facsz(m, σ, objective) + +Return a factor such that refitting `m` with `σ` at its current value times this factor gives `ζ ≈ 0.5` +""" +function _facsz(m::LinearMixedModel{T}, σ::T, obj::T) where {T} + i64 = T(inv(64)) + expi64 = exp(i64) # help the compiler infer it is a constant + m.optsum.sigma = σ * expi64 + return exp(i64 / (2 * sqrt(refit!(m; progress=false).objective - obj))) +end + +""" + profileσ(m::LinearMixedModel, tc::TableColumns; threshold=4) + +Return a Table of the profile of `σ` for model `m`. The profile extends to where the magnitude of ζ exceeds `threshold`. +!!! note + This method is called by `profile` and currently considered internal. + As such, it may change or disappear in a future release without being considered breaking. +""" +function profileσ(m::LinearMixedModel{T}, tc::TableColumns{T}; threshold=4) where {T} + (; σ, optsum) = m + isnothing(optsum.sigma) || + throw(ArgumentError("Can't profile σ, which is fixed at $(optsum.sigma)")) + θ = copy(optsum.final) + θinitial = copy(optsum.initial) + _copy_away_from_lowerbd!(optsum.initial, optsum.final, optsum.lowerbd) + obj = optsum.fmin + σ = m.σ + pnm = (p=:σ,) + tbl = [merge(pnm, mkrow!(tc, m, zero(T)))] + facsz = _facsz(m, σ, obj) + σv = σ / facsz + while true + newrow = merge(pnm, refitσ!(m, σv, tc, obj, true)) + push!(tbl, newrow) + newrow.ζ > -threshold || break + σv /= facsz + end + reverse!(tbl) + σv = σ * facsz + while true + newrow = merge(pnm, refitσ!(m, σv, tc, obj, false)) + push!(tbl, newrow) + newrow.ζ < threshold || break + σv *= facsz + end + optsum.sigma = nothing + optsum.initial = θinitial + updateL!(setθ!(m, θ)) + σv = [r.σ for r in tbl] + ζv = [r.ζ for r in tbl] + fwd = Dict(:σ => interpolate(σv, ζv, BSplineOrder(4), Natural())) + rev = Dict(:σ => interpolate(ζv, σv, BSplineOrder(4), Natural())) + return (; m, tbl, fwd, rev) +end diff --git a/src/profile/thetapr.jl b/src/profile/thetapr.jl new file mode 100644 index 000000000..62f9473b2 --- /dev/null +++ b/src/profile/thetapr.jl @@ -0,0 +1,103 @@ + +""" + optsumj(os::OptSummary, j::Integer) + +Return an `OptSummary` with the `j`'th component of the parameter omitted. + +`os.final` with its j'th component omitted is used as the initial parameter. +""" +function optsumj(os::OptSummary, j::Integer) + return OptSummary( + deleteat!(copy(os.final), j), + deleteat!(copy(os.lowerbd), j), + os.optimizer + ) +end + +function profileobj!( + m::LinearMixedModel{T}, θ::AbstractVector{T}, opt::Opt, osj::OptSummary +) where {T} + isone(length(θ)) && return objective!(m, θ) + fmin, xmin, ret = NLopt.optimize(opt, copyto!(osj.final, osj.initial)) + _check_nlopt_return(ret) + return fmin +end + +function profileθj!( + val::NamedTuple, sym::Symbol, tc::TableColumns{T}; threshold=4 +) where {T} + (; m, fwd, rev) = val + optsum = m.optsum + (; final, fmin, lowerbd) = optsum + j = parsej(sym) + θ = copy(final) + lbj = lowerbd[j] + osj = optsum + opt = Opt(osj) + if length(θ) > 1 # set up the conditional optimization problem + notj = deleteat!(collect(axes(final, 1)), j) + osj = optsumj(optsum, j) + opt = Opt(osj) # create an NLopt optimizer object for the reduced problem + function obj(x, g) + isempty(g) || + throw(ArgumentError("gradients are not evaluated by this objective")) + for i in eachindex(notj, x) + @inbounds θ[notj[i]] = x[i] + end + return objective!(m, θ) + end + NLopt.min_objective!(opt, obj) + end + pnm = (; p=sym) + ζold = zero(T) + tbl = [merge(pnm, mkrow!(tc, m, ζold))] # start with the row for ζ = 0 + δj = inv(T(64)) + θj = final[j] + θ[j] = θj - δj + while (abs(ζold) < threshold) && θ[j] ≥ lbj && length(tbl) < 100 # decreasing values of θ[j] + ζ = sign(θ[j] - θj) * sqrt(profileobj!(m, θ, opt, osj) - fmin) + push!(tbl, merge(pnm, mkrow!(tc, m, ζ))) + θ[j] == lbj && break + δj /= (4 * abs(ζ - ζold)) # take smaller steps when evaluating negative zeta + ζold = ζ + θ[j] = max(lbj, (θ[j] -= δj)) + end + reverse!(tbl) # reorder the new part of the table by increasing ζ + sv = getproperty(sym).(tbl) + δj = if length(sv) > 3 # need to handle the case of convergence on the boundary + slope = ( + Derivative(1) * + interpolate(sv, getproperty(:ζ).(tbl), BSplineOrder(4), Natural()) + )( + last(sv) + ) + δj = inv(T(2) * slope) # approximate step for increase of 0.5 + else + inv(T(32)) + end + ζold = zero(T) + copyto!(θ, final) + θ[j] += δj + while (ζold < threshold) && (length(tbl) < 120) + fval = profileobj!(m, θ, opt, osj) + if fval < fmin + @warn "Negative difference ", fval - fmin, " for ", sym, " at ", θ[j] + ζ = zero(T) + else + ζ = sqrt(profileobj!(m, θ, opt, osj) - fmin) + end + push!(tbl, merge(pnm, mkrow!(tc, m, ζ))) + δj /= (2 * abs(ζ - ζold)) + ζold = ζ + θ[j] += δj + end + append!(val.tbl, tbl) + updateL!(setθ!(m, final)) + sv = getproperty(sym).(tbl) + ζv = getproperty(:ζ).(tbl) + fwd[sym] = interpolate(sv, ζv, BSplineOrder(4), Natural()) + isnondecreasing(fwd[sym]) || @warn "Forward spline for $sym is not monotone." + rev[sym] = interpolate(ζv, sv, BSplineOrder(4), Natural()) + isnondecreasing(rev[sym]) || @warn "Reverse spline for $sym is not monotone." + return val +end diff --git a/src/profile/utilities.jl b/src/profile/utilities.jl new file mode 100644 index 000000000..27f63c4a0 --- /dev/null +++ b/src/profile/utilities.jl @@ -0,0 +1,177 @@ +""" + TableColumns + +A structure containing the column names for the numeric part of the profile table. + +The struct also contains a Dict giving the column ranges for Symbols like `:σ` and `:β`. +Finally it contains a scratch vector used to accumulate to values in a row of the profile table. + +!!! note + This is an internal structure used in [`MixedModelProfile`](@ref). + As such, it may change or disappear in a future release without being considered breaking. +""" +struct TableColumns{T<:AbstractFloat,N} + cnames::NTuple{N,Symbol} + positions::Dict{Symbol,UnitRange{Int}} + v::Vector{T} + corrpos::Vector{NTuple{3,Int}} +end + +""" + _generatesyms(tag::Char, len::Integer) + +Utility to generate a vector of Symbols of the form : from a tag and a length. + +The indices are left-padded with zeros to allow lexicographic sorting. +""" +function _generatesyms(tag::Char, len::Integer) + return Symbol.(string.(tag, lpad.(Base.OneTo(len), ndigits(len), '0'))) +end + +function TableColumns(m::LinearMixedModel{T}) where {T} + nmvec = [:ζ] + positions = Dict(:ζ => 1:1) + lastpos = 1 + sz = m.feterm.rank + append!(nmvec, _generatesyms('β', sz)) + positions[:β] = (lastpos + 1):(lastpos + sz) + lastpos += sz + push!(nmvec, :σ) + lastpos += 1 + positions[:σ] = lastpos:lastpos + sz = sum(t -> size(t.λ, 1), m.reterms) + append!(nmvec, _generatesyms('σ', sz)) + positions[:σs] = (lastpos + 1):(lastpos + sz) + lastpos += sz + corrpos = NTuple{3,Int}[] + for (i, re) in enumerate(m.reterms) + (isa(re.λ, Diagonal) || isa(re, ReMat{T,1})) && continue + indm = indmat(re) + for j in axes(indm, 1) + rowj = view(indm, j, :) + for k in (j + 1):size(indm, 1) + if !iszero(dot(rowj, view(indm, k, :))) + push!(corrpos, (i, j, k)) + end + end + end + end + sz = length(corrpos) + if sz > 0 + append!(nmvec, _generatesyms('ρ', sz)) + positions[:ρs] = (lastpos + 1):(lastpos + sz) + lastpos += sz + end + sz = length(m.θ) + append!(nmvec, _generatesyms('θ', sz)) + positions[:θ] = (lastpos + 1):(lastpos + sz) + return TableColumns((nmvec...,), positions, zeros(T, length(nmvec)), corrpos) +end + +function mkrow!(tc::TableColumns{T,N}, m::LinearMixedModel{T}, ζ::T) where {T,N} + (; cnames, positions, v, corrpos) = tc + v[1] = ζ + fixef!(view(v, positions[:β]), m) + v[first(positions[:σ])] = m.σ + σvals!(view(v, positions[:σs]), m) + getθ!(view(v, positions[:θ]), m) # must do this first to preserve a copy + if length(corrpos) > 0 + ρvals!(view(v, positions[:ρs]), corrpos, m) + setθ!(m, view(v, positions[:θ])) + end + return NamedTuple{cnames,NTuple{N,T}}((v...,)) +end + +""" + parsej(sym::Symbol) + +Return the index from symbol names like `:θ1`, `:θ01`, etc. + +!!! note + This method is internal. +""" +function parsej(sym::Symbol) + symstr = string(sym) # convert Symbol to a String + return parse(Int, SubString(symstr, nextind(symstr, 1))) # drop first Unicode character and parse as Int +end + +#= # It appears that this method is not used +""" + σvals(m::LinearMixedModel) + +Return a Tuple of the standard deviation estimates of the random effects +""" +function σvals(m::LinearMixedModel{T}) where {T} + (; σ, reterms) = m + isone(length(reterms)) && return σvals(only(reterms), σ) + return (collect(Iterators.flatten(σvals.(reterms, σ)))...,) +end +=# + +function σvals!(v::AbstractVector{T}, m::LinearMixedModel{T}) where {T} + (; σ, reterms) = m + isone(length(reterms)) && return σvals!(v, only(reterms), σ) + ind = firstindex(v) + for t in m.reterms + S = size(t.λ, 1) + σvals!(view(v, ind:(ind + S - 1)), t, σ) + ind += S + end + return v +end + +function ρvals!( + v::AbstractVector{T}, corrpos::Vector{NTuple{3,Int}}, m::LinearMixedModel{T} +) where {T} + reterms = m.reterms + lasti = 1 + λ = first(reterms).λ + for r in eachrow(λ) + normalize!(r) + end + for (ii, pos) in enumerate(corrpos) + i, j, k = pos + if lasti ≠ i + λ = reterms[i].λ + for r in eachrow(λ) + normalize!(r) + end + lasti = i + end + v[ii] = dot(view(λ, j, :), view(λ, k, :)) + end + return v +end + +""" + _copy_away_from_lowerbd!(sink, source, bd; incr=0.01) + +Replace `sink[i]` by `max(source[i], bd[i] + incr)`. When `bd[i] == -Inf` this simply copies `source[i]`. +""" +function _copy_away_from_lowerbd!(sink, source, bd; incr=0.01) + for i in eachindex(sink, source, bd) + @inbounds sink[i] = max(source[i], bd[i] + incr) + end + return sink +end + +#= # It appears that this method is not used +""" + stepsize(tbl::Vector{NamedTuple}, resp::Symbol, pred::Symbol; rev::Bool=false) + +Return the stepsize from the last value of `tbl.pred` to increase `resp` by approximately 0.5 +""" +function stepsize(tbl::Vector{<:NamedTuple}, resp::Symbol, pred::Symbol) + ntbl = length(tbl) + lm1tbl = tbl[ntbl - 1] + x1 = getproperty(lm1tbl, pred) + y1 = getproperty(lm1tbl, resp) + x2 = getproperty(last(tbl), pred) + y2 = getproperty(last(tbl), resp) + return (x2 - x1) / (2 * (y2 - y1)) +end +=# + +function isnondecreasing(spl::SplineInterpolation) + return all(≥(0), (Derivative(1) * spl).(spl.x)) +end diff --git a/src/profile/vcpr.jl b/src/profile/vcpr.jl new file mode 100644 index 000000000..6457c2fcc --- /dev/null +++ b/src/profile/vcpr.jl @@ -0,0 +1,92 @@ + +""" + profilevc(m::LinearMixedModel{T}, val::T, rowj::AbstractVector{T}) where {T} + +Profile an element of the variance components. + +!!! note + This method is called by `profile` and currently considered internal. + As such, it may change or disappear in a future release without being considered breaking. +""" +function profilevc(m::LinearMixedModel{T}, val::T, rowj::AbstractVector{T}) where {T} + optsum = m.optsum + function obj(x, g) + isempty(g) || throw(ArgumentError("g must be empty")) + updateL!(setθ!(m, x)) + optsum.sigma = val / norm(rowj) + objctv = objective(m) + return objctv + end + opt = Opt(optsum) + NLopt.min_objective!(opt, obj) + fmin, xmin, ret = NLopt.optimize!(opt, copyto!(optsum.final, optsum.initial)) + _check_nlopt_return(ret) + return fmin, xmin +end + +""" + profileσs!(val::NamedTuple, tc::TableColumns{T}; nzlb=1.0e-8) where {T} + +Profile the variance components. + +!!! note + This method is called by `profile` and currently considered internal. + As such, it may change or disappear in a future release without being considered breaking. +""" +function profileσs!(val::NamedTuple, tc::TableColumns{T}; nzlb=1.0e-8) where {T} + m = val.m + (; λ, σ, β, optsum, parmap, reterms) = m + isnothing(optsum.sigma) || throw(ArgumentError("Can't profile vc's when σ is fixed")) + (; initial, final, fmin, lowerbd) = optsum + lowerbd .+= T(nzlb) # lower bounds must be > 0 b/c θ's occur in denominators + saveinitial = copy(initial) + copyto!(initial, max.(final, lowerbd)) + zetazero = mkrow!(tc, m, zero(T)) # parameter estimates + vcnms = filter(keys(first(val.tbl))) do sym + str = string(sym) + return startswith(str, 'σ') && (length(str) > 1) + end + ind = 0 + for t in reterms + for r in eachrow(t.λ) + optsum.sigma = nothing # re-initialize the model + objective!(m, final) + ind += 1 + sym = vcnms[ind] + gpsym = getproperty(sym) # extractor function + estimate = gpsym(zetazero) + pnm = (; p=sym) + tbl = [merge(pnm, zetazero)] + xtrms = extrema(gpsym, val.tbl) + lub = log(last(xtrms)) + llb = log(max(first(xtrms), T(0.01) * lub)) + for lx in LinRange(lub, llb, 15) # start at the upper bound where things are more stable + x = exp(lx) + obj, xmin = profilevc(m, x, r) + copyto!(initial, xmin) + zeta = sign(x - estimate) * sqrt(max(zero(T), obj - fmin)) + push!(tbl, merge(pnm, mkrow!(tc, m, zeta))) + end + if iszero(first(xtrms)) && !iszero(estimate) # handle the case of lower bound of zero + zrows = filter(iszero ∘ gpsym, val.tbl) + isone(length(zrows)) || + filter!(r -> iszero(getproperty(r, first(r))), zrows) + rr = only(zrows) # will error if zeros in sym column occur in unexpected places + push!(tbl, merge(pnm, rr[(collect(keys(rr))[2:end]...,)])) + end + sort!(tbl; by=gpsym) + append!(val.tbl, tbl) + ζcol = getproperty(:ζ).(tbl) + symcol = gpsym.(tbl) + val.fwd[sym] = interpolate(symcol, ζcol, BSplineOrder(4), Natural()) + issorted(ζcol) && + (val.rev[sym] = interpolate(ζcol, symcol, BSplineOrder(4), Natural())) + end + end + copyto!(final, initial) + copyto!(initial, saveinitial) + lowerbd .-= T(nzlb) + optsum.sigma = nothing + updateL!(setθ!(m, final)) + return val +end diff --git a/src/remat.jl b/src/remat.jl index d3added38..a86ed6262 100644 --- a/src/remat.jl +++ b/src/remat.jl @@ -12,7 +12,7 @@ A section of a model matrix generated by a random-effects term. - `cnames`: the names of the columns of the model matrix generated by the left-hand side of the term - `z`: transpose of the model matrix generated by the left-hand side of the term - `wtz`: a weighted copy of `z` (`z` and `wtz` are the same object for unweighted cases) -- `λ`: a `LowerTriangular` matrix of size `S×S` +- `λ`: a `LowerTriangular` or `Diagonal` matrix of size `S×S` - `inds`: a `Vector{Int}` of linear indices of the potential nonzeros in `λ` - `adjA`: the adjoint of the matrix as a `SparseMatrixCSC{T}` - `scratch`: a `Matrix{T}` @@ -35,7 +35,7 @@ end Combine multiple ReMat with the same grouping variable into a single object. """ -amalgamate(reterms::Vector{AbstractReMat{T}}) where {T} = _amalgamate(reterms, T) +amalgamate(reterms::Vector{<:AbstractReMat{T}}) where {T} = _amalgamate(reterms, T) function _amalgamate(reterms::Vector, T::Type) factordict = Dict{Symbol,Vector{Int}}() @@ -617,22 +617,64 @@ function setθ!(A::ReMat{T}, v::AbstractVector{T}) where {T} return A end -function σs(A::ReMat{T,1}, sc::T) where {T} - return NamedTuple{(Symbol(only(A.cnames)),)}(sc * abs(only(A.λ.data))) +σvals(A::ReMat{T,1}, sc::Number) where {T} = (sc * abs(only(A.λ.data)),) + +""" + σvals!(v::AbstractVector, A::ReMat, sc::Number) + +Overwrite v with the standard deviations of the random effects associated with `A` +""" +σvals!(v::AbstractVector, A::ReMat, sc::Number) = σvals!(v, A.λ, sc) + +function σvals!(v::AbstractVector{T}, A::ReMat{T,1}, sc::Number) where {T} + isone(length(v)) || throw(DimensionMismatch("length(v) = $(length(v)), should be 1")) + @inbounds v[1] = sc * abs(only(A.λ.data)) + return v end -function _σs(λ::LowerTriangular{T}, sc::T, cnames) where {T} - λ = λ.data - return NamedTuple{(Symbol.(cnames)...,)}( - ntuple(i -> sc * norm(view(λ, i, 1:i)), size(λ, 1)) - ) +function σvals!(v::AbstractVector{T}, λ::LowerTriangular{T}, sc::Number) where {T} + fill!(v, zero(T)) + for j in axes(λ, 2) + for i in j:size(λ, 1) + @inbounds v[i] += abs2(λ[i, j]) + end + end + for i in axes(λ, 1) + @inbounds v[i] = sqrt(v[i]) * sc + end + return v end -function _σs(λ::Diagonal{T}, sc::T, cnames) where {T} - return NamedTuple{(Symbol.(cnames)...,)}(((sc .* λ.diag)...,)) +function σvals!(v::AbstractVector{T}, λ::Diagonal{T}, sc::Number) where {T} + return rmul!(copyto!(v, λ.diag), sc) end -σs(A::ReMat{T}, sc::T) where {T} = _σs(A.λ, sc, A.cnames) +function σs(A::ReMat{T,1}, sc::Number) where {T} + return NamedTuple{(Symbol(only(A.cnames)),)}(σvals(A, sc)) +end + +function σvals(λ::LowerTriangular{T}, sc::Number) where {T} + return ntuple(size(λ, 1)) do i + s = zero(T) + for j in Base.OneTo(i) + @inbounds s += abs2(λ[i, j]) + end + sc * sqrt(s) + end +end + +function σvals(λ::Diagonal, sc::Number) + v = λ.diag + return ntuple(length(v)) do i + @inbounds sc * v[i] + end +end + +σvals(A::ReMat, sc::Number) = σvals(A.λ, sc) + +function σs(A::ReMat{T}, sc::Number) where {T} + return NamedTuple{(Symbol.(A.cnames)...,)}(σvals(A.λ, sc)) +end function σρs(A::ReMat{T,1}, sc::T) where {T} return NamedTuple{(:σ, :ρ)}(( @@ -671,6 +713,7 @@ end function σρs(A::ReMat{T}, sc::T) where {T} return _σρs(A.λ, sc, indmat(A), Symbol.(A.cnames)) end + """ corrmat(A::ReMat) diff --git a/src/utilities.jl b/src/utilities.jl index 71d3b982f..ad5a01ea4 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -134,7 +134,7 @@ bar is automatically disabled for non-interactive (i.e. logging) contexts. function replicate(f::Function, n::Integer; use_threads=false, hide_progress=false) use_threads && Base.depwarn( "use_threads is deprecated and will be removed in a future release", - :replicate, + :replicate ) # and we want some advanced options p = Progress(n; output=Base.stderr, enabled=!hide_progress && !_is_logging(stderr)) diff --git a/test/Project.toml b/test/Project.toml index 2d54cb614..e68e9b2be 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -13,7 +13,8 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" [compat] -Aqua = "0.5" +Aqua = "0.5, 0.6" StableRNGs = "0.1, 1" diff --git a/test/bootstrap.jl b/test/bootstrap.jl index 2899a292a..4943ccbc6 100644 --- a/test/bootstrap.jl +++ b/test/bootstrap.jl @@ -146,3 +146,15 @@ end @test sum(issingular(bs)) == 0 end end + +@testset "CI method comparison" begin + fmzc = models(:sleepstudy)[2] + level = 0.68 + pb = parametricbootstrap(MersenneTwister(42), 500, fmzc; hide_progress=true) + pr = profile(fmzc) + ci_boot = confint(pb; level) + ci_wald = confint(fmzc; level) + ci_prof = confint(pr; level) + @test first(ci_boot.lower, 2) ≈ first(ci_prof.lower, 2) atol=0.5 + @test first(ci_prof.lower, 2) ≈ first(ci_wald.lower, 2) atol=0.1 +end diff --git a/test/pls.jl b/test/pls.jl index 739449463..d07ba3e4d 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -7,6 +7,7 @@ using Statistics using StatsModels using Tables using Test +using TypedTables using MixedModels: likelihoodratiotest @@ -160,10 +161,16 @@ end @test length(fitlog) == (div(fm1.optsum.feval, thin) + 1) # for the initial value @test first(fitlog) == (fm1.optsum.initial, fm1.optsum.finitial) end + @testset "profile" begin + dspr01 = profile(only(models(:dyestuff))) + sigma0row = only(filter(r -> r.p == :σ && iszero(r.ζ), dspr01.tbl)) + @test sigma0row.σ ≈ dspr01.m.σ + @test sigma0row.β1 ≈ only(dspr01.m.β) + @test sigma0row.θ1 ≈ only(dspr01.m.θ) + end end @testset "Dyestuff2" begin - ds2 = MixedModels.dataset(:dyestuff2) fm = only(models(:dyestuff2)) @test lowerbd(fm) == zeros(1) show(IOBuffer(), fm) @@ -179,6 +186,13 @@ end refit!(fm, float(MixedModels.dataset(:dyestuff)[:yield]); progress=false) @test objective(fm) ≈ 327.3270598811428 atol=0.001 refit!(fm, float(MixedModels.dataset(:dyestuff2)[:yield]); progress=false) # restore the model in the cache + @testset "profile" begin # tests a branch in profileσs! for σ estimate of zero + dspr02 = profile(only(models(:dyestuff2))) + sigma10row = only(filter(r -> r.p == :σ1 && iszero(r.ζ), dspr02.tbl)) + @test iszero(sigma10row.σ1) + sigma1tbl = Table(filter(r -> r.p == :σ1, dspr02.tbl)) + @test all(≥(0), sigma1tbl.σ1) + end end @testset "penicillin" begin @@ -501,6 +515,29 @@ end @test bic(fm) ≈ bic(m) @test coef(fm) ≈ coef(m) end + @testset "profile" begin + pr = profile(last(models(:sleepstudy))) + tbl = pr.tbl + @test length(tbl) >= 122 + ci = confint(pr) + @test Tables.istable(ci) + @test propertynames(ci) == (:par, :estimate, :lower, :upper) + @test collect(ci.par) == [:β1, :β2, :σ, :σ1, :σ2] + @test isapprox( + ci.lower.values, + [237.681, 7.359, 22.898, 14.381, 0.0]; + atol=1.e-3) + @test isapprox( + ci.upper.values, + [265.130, 13.576, 28.858, 37.718, 8.753]; + atol=1.e-3) + @test first(only(filter(r -> r.p == :σ && iszero(r.ζ), pr.tbl)).σ) == last(models(:sleepstudy)).σ + end + @testset "confint" begin + ci = confint(last(models(:sleepstudy))) + @test Tables.istable(ci) + @test isapprox(ci.lower.values, [238.4061184564825, 7.52295850741417]; atol=1.e-3) + end end @testset "d3" begin @@ -525,6 +562,14 @@ end tokens = Set(split(String(take!(io)), r"\s+")) @test "Corr." in tokens @test "-0.89" in tokens + @testset "profile" begin + contrasts = Dict(:item => Grouping(), :subj => Grouping(), :prec => EffectsCoding(; base="maintain"), + :spkr => EffectsCoding(), :load => EffectsCoding()) + kbf03 = @formula rt_trunc ~ 1+prec+spkr+load+(1+prec|item)+(1|subj) + kbpr03 = profile(fit(MixedModel, kbf03, MixedModels.dataset(:kb07); contrasts, thin=1, progress=false)) + @test length(Tables.columnnames(kbpr03.tbl)) == 15 + @test length(Tables.rows(kbpr03.tbl)) > 200 + end end @testset "oxide" begin From b8b9b2edafe744d550dcc82a3e6a7644a6964733 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 5 May 2023 18:26:39 +0000 Subject: [PATCH 39/51] use Suppressor.jl to hide log messages in tests (#684) --- test/Project.toml | 2 ++ test/fit.jl | 8 +++++--- test/likelihoodratiotest.jl | 4 ++-- test/mime.jl | 4 ++++ test/pls.jl | 3 ++- test/predict.jl | 21 +++++++++++---------- 6 files changed, 26 insertions(+), 16 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index e68e9b2be..518b440a6 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -11,6 +11,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d" +Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" @@ -18,3 +19,4 @@ TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" [compat] Aqua = "0.5, 0.6" StableRNGs = "0.1, 1" +Suppressor = "0.2" diff --git a/test/fit.jl b/test/fit.jl index 48f9f1643..2ca2c71e1 100644 --- a/test/fit.jl +++ b/test/fit.jl @@ -1,4 +1,6 @@ -using MixedModels, Test +using MixedModels +using Suppressor +using Test @testset "linear" begin m1 = fit(MixedModel, @formula(yield ~ 1 + (1|batch)), MixedModels.dataset(:dyestuff); progress=false) @@ -21,7 +23,7 @@ end end @testset "Normal Distribution GLMM" begin - @test isa(fit(MixedModel, @formula(yield ~ 1 + (1|batch)), MixedModels.dataset(:dyestuff), + @test @suppress isa(fit(MixedModel, @formula(yield ~ 1 + (1|batch)), MixedModels.dataset(:dyestuff), Normal(), SqrtLink(); progress=false), - GeneralizedLinearMixedModel) + GeneralizedLinearMixedModel) end diff --git a/test/likelihoodratiotest.jl b/test/likelihoodratiotest.jl index c9e9dcddf..28f066122 100644 --- a/test/likelihoodratiotest.jl +++ b/test/likelihoodratiotest.jl @@ -1,6 +1,7 @@ using DataFrames using GLM using MixedModels +using Suppressor using Test using MixedModels: dataset, likelihoodratiotest @@ -38,8 +39,7 @@ include("modelcache.jl") m2 = fit(MixedModel, @formula(rt_trunc ~ 1 + prec + (1+prec|subj)), kb07, REML=true, progress=false) @test isnested(m1, m2) m2 = fit(MixedModel, @formula(rt_trunc ~ 1 + (1+prec|subj)), kb07, REML=true, progress=false) - @test !isnested(m1, m2) - + @test @suppress !isnested(m1, m2) end @testset "likelihoodratio test" begin diff --git a/test/mime.jl b/test/mime.jl index a5f8c8961..21c6d188b 100644 --- a/test/mime.jl +++ b/test/mime.jl @@ -1,4 +1,5 @@ using MixedModels +using Suppressor using Test using MixedModels: dataset, likelihoodratiotest @@ -14,9 +15,11 @@ pirls!(setβθ!(gm3, βθ)) fm0θ = [1.1656121258575225] fm0 = updateL!(setθ!(first(models(:sleepstudy)), fm0θ)) +fm0.optsum.feval = 1 fm1θ = [0.9292213288149662, 0.018168393450877257, 0.22264486671069741] fm1 = updateL!(setθ!(last(models(:sleepstudy)), fm1θ)) +fm1.optsum.feval = 1 fmreθ = [0.32352483854887326, 0.4715395478019364, 0.0, 0.43705610601403755, 0.016565641868150047, 0.17732248078617097] @@ -29,6 +32,7 @@ lrt = likelihoodratiotest(fm0, fm1) @testset "markdown" begin mime = MIME"text/markdown"() + gm3.optsum.feval = -1 @test_logs (:warn, "Model has not been fit: results will be nonsense") sprint(show, mime, gm3) gm3.optsum.feval = 1 @testset "lmm" begin diff --git a/test/pls.jl b/test/pls.jl index d07ba3e4d..1e1edc2e4 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -3,6 +3,7 @@ using MixedModels using PooledArrays using Random using SparseArrays +using Suppressor using Statistics using StatsModels using Tables @@ -595,7 +596,7 @@ end rng = MersenneTwister(0); x = rand(rng, 100); data = (x = x, x2 = 1.5 .* x, y = rand(rng, 100), z = repeat('A':'T', 5)) - model = fit(MixedModel, @formula(y ~ x + x2 + (1|z)), data; progress=false) + model = @suppress fit(MixedModel, @formula(y ~ x + x2 + (1|z)), data; progress=false) @test length(fixef(model)) == 2 @test rank(model) == 2 @test length(coef(model)) == 3 diff --git a/test/predict.jl b/test/predict.jl index 55f2639a0..a55272bbc 100644 --- a/test/predict.jl +++ b/test/predict.jl @@ -2,6 +2,7 @@ using DataFrames using LinearAlgebra using MixedModels using Random +using Suppressor using StableRNGs using Tables using Test @@ -89,20 +90,20 @@ end refvals = predict(first(models(:sleepstudy)), slp) slprd = transform(slp, :days => ByRow(x -> 2x) => :days2) - m = fit(MixedModel, @formula(reaction ~ 1 + days + days2 + (1|subj)), slprd; progress=false) + m = @suppress fit(MixedModel, @formula(reaction ~ 1 + days + days2 + (1|subj)), slprd; progress=false) # predict assumes that X is the correct length and stored pivoted # so these first two tests will fail if we change that storage detail @test size(m.X) == (180, 3) @test all(2 .* view(m.X, :, m.feterm.piv[2]) .== view(m.X, :, m.feterm.piv[3])) - @test predict(m, slprd) == refvals + @test @suppress predict(m, slprd) == refvals slprd0 = transform(slp, :days => zero => :days0) - m = fit(MixedModel, @formula(reaction ~ 1 + days0 + days + (1|subj)), slprd0; progress=false) - @test predict(m, slprd0) == refvals + m = @suppress fit(MixedModel, @formula(reaction ~ 1 + days0 + days + (1|subj)), slprd0; progress=false) + @test @suppress predict(m, slprd0) == refvals # change the formula order slightly so that the original ordering and hence the # permutation vector for pivoting isn't identical - m = fit(MixedModel, @formula(reaction ~ 1 + days + days0 + (1|subj)), slprd0; progress=false) - @test predict(m, slprd0) == refvals + m = @suppress fit(MixedModel, @formula(reaction ~ 1 + days + days0 + (1|subj)), slprd0; progress=false) + @test @suppress predict(m, slprd0) == refvals end @testset "in newdata" begin @@ -110,7 +111,7 @@ end # remove days refvals = fitted(mref) .- view(mref.X, :, 2) * mref.β[2] slp0 = transform(slp, :days => zero => :days) - vals = predict(mref, slp0) + vals = @suppress predict(mref, slp0) @test all(refvals .≈ vals) end @@ -121,10 +122,10 @@ end refvals = fitted(mref) .- view(mref.X, :, 2) * mref.β[2] # days gets pivoted out slprd = transform(slp, :days => ByRow(x -> 2x) => :days2) - m = fit(MixedModel, @formula(reaction ~ 1 + days + days2 + (1|subj)), slprd; progress=false) + m = @suppress fit(MixedModel, @formula(reaction ~ 1 + days + days2 + (1|subj)), slprd; progress=false) # days2 gets pivoted out slp0 = transform(slp, :days => zero => :days2) - vals = predict(m, slp0) + vals = @suppress predict(m, slp0) # but in the original fit, days gets pivoted out, so its coef is zero # and now we have a column of zeros for days2 # leaving us with only the intercept @@ -132,7 +133,7 @@ end @test all(refvals .≈ vals) slp1 = transform(slp, :days => ByRow(one) => :days2) - vals = predict(m, slp1) + vals = @suppress predict(m, slp1) refvals = fitted(mref) .- view(mref.X, :, 2) * mref.β[2] .+ last(fixef(m)) @test all(refvals .≈ vals) end From ba1fcf51442a8e0122d9497a91239e44145dcc5d Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Tue, 16 May 2023 18:45:52 -0500 Subject: [PATCH 40/51] Avoid repeated def'n of models method for tests (#692) --- test/modelcache.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/modelcache.jl b/test/modelcache.jl index f482b4eb2..ead74ace3 100644 --- a/test/modelcache.jl +++ b/test/modelcache.jl @@ -44,8 +44,11 @@ using MixedModels: dataset @isdefined(allfms) || const global allfms = merge(fms, gfms) -function models(nm::Symbol) - get!(fittedmodels, nm) do - [fit(MixedModel, f, dataset(nm); progress=false) for f in allfms[nm]] + +if !@isdefined(models) + function models(nm::Symbol) + get!(fittedmodels, nm) do + [fit(MixedModel, f, dataset(nm); progress=false) for f in allfms[nm]] + end end end From d11061c1ca81e410162c7a9fa11de05fb17e1f3e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 17:18:47 +0000 Subject: [PATCH 41/51] CompatHelper: bump compat for BSplineKit to 0.16, (keep existing compat) (#693) * CompatHelper: bump compat for BSplineKit to 0.16, (keep existing compat) * spacing tweak * patch bump --------- Co-authored-by: CompatHelper Julia Co-authored-by: Phillip Alday --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index faa92debb..448e08f74 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.14.0" +version = "4.14.1" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" @@ -31,7 +31,7 @@ TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" [compat] Arrow = "1, 2" -BSplineKit = "0.14,0.15" +BSplineKit = "0.14, 0.15, 0.16" DataAPI = "1" Distributions = "0.21, 0.22, 0.23, 0.24, 0.25" GLM = "1.8.2" From 491f7a769f7b759bfa700cda44217f57c57bfb34 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 21 Jun 2023 22:16:23 +0000 Subject: [PATCH 42/51] update CI actions (#695) * update coverage action * update buildpackage version * update runtest version * add in caching step * drop MKL CI * precompilation cache * tweak --- .github/workflows/MKL.yml | 25 ------------------------- .github/workflows/current.yml | 13 ++++++++++--- .github/workflows/documenter.yml | 3 +++ .github/workflows/minimum.yml | 13 ++++++++++--- .github/workflows/nightly.yml | 13 ++++++++++--- 5 files changed, 33 insertions(+), 34 deletions(-) delete mode 100644 .github/workflows/MKL.yml diff --git a/.github/workflows/MKL.yml b/.github/workflows/MKL.yml deleted file mode 100644 index c7395dbe6..000000000 --- a/.github/workflows/MKL.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: MKL -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true -on: - workflow_dispatch: -jobs: - ci: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - julia-version: [nightly] - julia-arch: [x64] - os: [ubuntu-20.04] - steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 - with: - version: ${{ matrix.julia-version }} - - uses: julia-actions/julia-buildpkg@v0.1 - - run: julia -e 'using Pkg; Pkg.add("MKL"); Pkg.build("MKL"; verbose=true)' - - uses: julia-actions/julia-runtest@v0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/current.yml b/.github/workflows/current.yml index 8745e0e93..f11a2eee5 100644 --- a/.github/workflows/current.yml +++ b/.github/workflows/current.yml @@ -28,8 +28,15 @@ jobs: - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.julia-version }} - - uses: julia-actions/julia-buildpkg@v0.1 - - uses: julia-actions/julia-runtest@v0.1 + - uses: julia-actions/cache@v1 + with: + cache-compiled: "true" + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: julia-actions/julia-uploadcodecov@v0.1 + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v2 + with: + flags: current + files: lcov.info diff --git a/.github/workflows/documenter.yml b/.github/workflows/documenter.yml index 4379603de..3ae86a5e6 100644 --- a/.github/workflows/documenter.yml +++ b/.github/workflows/documenter.yml @@ -25,6 +25,9 @@ jobs: - uses: julia-actions/setup-julia@v1 with: version: 1.8 + - uses: julia-actions/cache@v1 + with: + cache-compiled: "true" - uses: julia-actions/julia-buildpkg@latest - uses: julia-actions/julia-docdeploy@latest env: diff --git a/.github/workflows/minimum.yml b/.github/workflows/minimum.yml index 176fdefcd..9d4d90f83 100644 --- a/.github/workflows/minimum.yml +++ b/.github/workflows/minimum.yml @@ -28,8 +28,15 @@ jobs: - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.julia-version }} - - uses: julia-actions/julia-buildpkg@v0.1 - - uses: julia-actions/julia-runtest@v0.1 + - uses: julia-actions/cache@v1 + with: + cache-compiled: "true" + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: julia-actions/julia-uploadcodecov@v0.1 + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v2 + with: + flags: minimum + files: lcov.info diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index d56eff075..862873e1f 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -28,8 +28,15 @@ jobs: - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.julia-version }} - - uses: julia-actions/julia-buildpkg@v0.1 - - uses: julia-actions/julia-runtest@v0.1 + - uses: julia-actions/cache@v1 + with: + cache-compiled: "true" + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: julia-actions/julia-uploadcodecov@v0.1 + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v2 + with: + flags: nightly + files: lcov.info From 8d7196121e18010d75eb1d73ab49c0c345e6fa0e Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Thu, 6 Jul 2023 20:09:05 +0000 Subject: [PATCH 43/51] distributed and reduced precision bootstrap (#694) * distributed and reduced precision bootstrap * parallel example * note for reduced precision * version bump, notes * bootstrap save and restore * NEWS * (approximate) equality and tests --------- Co-authored-by: Douglas Bates --- NEWS.md | 7 + Project.toml | 2 +- docs/Project.toml | 2 + docs/src/bootstrap.md | 57 +++++++ issues/emotikon_bootstrap/Project.toml | 11 ++ issues/emotikon_bootstrap/cache.jl | 22 +++ .../emotikon_bootstrap/emotikon_bootstrap.jl | 82 ++++++++++ src/MixedModels.jl | 3 + src/bootstrap.jl | 147 +++++++++++++++++- src/optsummary.jl | 4 +- test/bootstrap.jl | 70 +++++++++ 11 files changed, 399 insertions(+), 8 deletions(-) create mode 100644 issues/emotikon_bootstrap/Project.toml create mode 100644 issues/emotikon_bootstrap/cache.jl create mode 100644 issues/emotikon_bootstrap/emotikon_bootstrap.jl diff --git a/NEWS.md b/NEWS.md index ed5d9e1dd..af3463200 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +MixedModels v4.15.0 Release Notes +============================== +* Support for different optimization criteria during the bootstrap. [#694] +* Support for combining bootstrap results with `vcat`. [#694] +* Support for saving and restoring bootstrap replicates with `savereplicates` and `restorereplicates`. [#694] + MixedModels v4.14.0 Release Notes ============================== * New function `profile` for computing likelihood profiles for `LinearMixedModel`. The resultant `MixedModelProfile` can be then be used for computing confidence intervals with `confint`. Note that this API is still somewhat experimental and as such the internal storage details of `MixedModelProfile` may change in a future release without being considered breaking. [#639] @@ -435,3 +441,4 @@ Package dependencies [#680]: https://github.com/JuliaStats/MixedModels.jl/issues/680 [#681]: https://github.com/JuliaStats/MixedModels.jl/issues/681 [#682]: https://github.com/JuliaStats/MixedModels.jl/issues/682 +[#694]: https://github.com/JuliaStats/MixedModels.jl/issues/694 diff --git a/Project.toml b/Project.toml index 448e08f74..1078a09f3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.14.1" +version = "4.15.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/docs/Project.toml b/docs/Project.toml index e1581a96f..299dc45a5 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,10 +2,12 @@ BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DisplayAs = "0b91fe84-8a4c-11e9-3e1d-67c38462b6d6" +Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" FreqTables = "da1fdf0e-e0ff-5433-a45f-9bb5ff651cb1" Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004" MixedModels = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" +ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" StatsAPI = "82ae8749-77ed-4fe6-ae5f-f523153014b0" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" diff --git a/docs/src/bootstrap.md b/docs/src/bootstrap.md index 549c80413..018a024d8 100644 --- a/docs/src/bootstrap.md +++ b/docs/src/bootstrap.md @@ -164,3 +164,60 @@ This operation is encapsulated in a method for the `issingular` function. ```@example Main count(issingular(samp2)) ``` + +## Reduced Precision Bootstrap + +`parametricbootstrap` accepts an optional keyword argument `optsum_overrides`, which can be used to override the convergence criteria for bootstrap replicates. One possibility is setting `ftol_rel=1e-8`, i.e., considering the model converged when the relative change in the objective between optimizer iterations is smaller than 0.00000001. +This threshold corresponds approximately to the precision from treating the value of the objective as a single precision (`Float32`) number, while not changing the precision of the intermediate computations. +The resultant loss in precision will generally be smaller than the variation that the bootstrap captures, but can greatly speed up the fitting process for each replicates, especially for large models. +More directly, lowering the fit quality for each replicate will reduce the quality of each replicate, but this may be more than compensated for by the ability to fit a much larger number of replicates in the same time. + +```@example Main +t = @timed parametricbootstrap(MersenneTwister(42), 1000, m2; hide_progress=true) +t.time +``` + +```@example Main +optsum_overrides = (; ftol_rel=1e-8) +t = @timed parametricbootstrap(MersenneTwister(42), 1000, m2; optsum_overrides, hide_progress=true) +t.time +``` + +## Distributed Computing and the Bootstrap + +Earlier versions of MixedModels.jl supported a multi-threaded bootstrap via the `use_threads` keyword argument. +However, with improved BLAS multithreading, the Julia-level threads often wound up competing with the BLAS threads, leading to no improvement or even a worsening of performance when `use_threads=true`. +Nonetheless, the bootstrap is a classic example of an [embarrassingly parallel](https://en.wikipedia.org/wiki/Embarrassingly_parallel) problem and so we provide a few convenience methods for combining results computed separately. +In particular, there are `vcat` and an optimized `reduce(::typeof(vcat))` methods for `MixedModelBootstrap` objects. +For computers with many processors (as opposed to a single processor with several cores) or for computing clusters, these provide a convenient way to split the computation across nodes. + +```@example Main +using Distributed +using ProgressMeter +# you already have 1 proc by default, so add the number of additional cores with `addprocs` +# you need at least as many RNGs as cores you want to use in parallel +# but you shouldn't use all of your cores because nested within this +# is the multithreading of the linear algebra +@info "Currently using $(nprocs()) processors total and $(nworkers()) for work" + +# copy everything to workers +@showprogress for w in workers() + remotecall_fetch(() -> coefnames(m2), w) +end + +# split the replicates across the workers +# this rounds down, so if the number of workers doesn't divide the +# number of replicates, you'll be a few replicates short! +n_replicates = 1000 +n_rep_per_worker = n_replicates ÷ nworkers() +# NB: You need a different seed/RNG for each worker otherwise you will +# have copies of the same replicates and not independent replicates! +pb_map = @showprogress pmap(MersenneTwister.(1:nworkers())) do rng + parametricbootstrap(rng, n_rep_per_worker, m2; optsum_overrides) +end; + +# get rid of all the workers +# rmprocs(workers()) + +confint(reduce(vcat, pb_map)) +``` diff --git a/issues/emotikon_bootstrap/Project.toml b/issues/emotikon_bootstrap/Project.toml new file mode 100644 index 000000000..d17d91b5f --- /dev/null +++ b/issues/emotikon_bootstrap/Project.toml @@ -0,0 +1,11 @@ +[deps] +Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" +CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" +Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +MixedModels = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" +ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Scratch = "6c6a2e73-6563-6170-7368-637461726353" +StandardizedPredictors = "5064a6a7-f8c2-40e2-8bdc-797ec6f1ae18" diff --git a/issues/emotikon_bootstrap/cache.jl b/issues/emotikon_bootstrap/cache.jl new file mode 100644 index 000000000..9649cef8e --- /dev/null +++ b/issues/emotikon_bootstrap/cache.jl @@ -0,0 +1,22 @@ +module Cache +using Downloads +using Scratch +# This will be filled in inside `__init__()` +download_cache = "" +url = "https://github.com/RePsychLing/SMLP2022/raw/main/data/fggk21.arrow" +#"https://github.com/bee8a116-0383-4365-8df7-6c6c8d6c1322" + +function data_path() + fname = joinpath(download_cache, basename(url)) + if !isfile(fname) + @info "Local cache not found, downloading" + Downloads.download(url, fname) + end + return fname +end + +function __init__() + global download_cache = get_scratch!(@__MODULE__, "downloaded_files") + return nothing +end +end diff --git a/issues/emotikon_bootstrap/emotikon_bootstrap.jl b/issues/emotikon_bootstrap/emotikon_bootstrap.jl new file mode 100644 index 000000000..4e6c3f44f --- /dev/null +++ b/issues/emotikon_bootstrap/emotikon_bootstrap.jl @@ -0,0 +1,82 @@ +include("cache.jl") +using .Cache +using Arrow +using CategoricalArrays +using DataFrames +using Distributed +using MixedModels +using ProgressMeter +using Random +using StandardizedPredictors + +kb07 = MixedModels.dataset(:kb07) +contrasts = Dict(:item => Grouping(), + :subj => Grouping(), + :spkr => EffectsCoding(), + :prec => EffectsCoding(), + :load => EffectsCoding()) +m07 = fit(MixedModel, + @formula( + 1000 / rt_raw ~ + 1 + spkr * prec * load + + (1 + spkr * prec * load | item) + + (1 + spkr * prec * load | subj) + ), + kb07; contrasts, progress=true, thin=1) + +pbref = @time parametricbootstrap(MersenneTwister(42), 1000, m07); +pb_restricted = @time parametricbootstrap( + MersenneTwister(42), 1000, m07; optsum_overrides=(; ftol_rel=1e-3) +); +pb_restricted2 = @time parametricbootstrap( + MersenneTwister(42), 1000, m07; optsum_overrides=(; ftol_rel=1e-6) +); +confint(pbref) +confint(pb_restricted) +confint(pb_restricted2) + +using .Cache +using Distributed +addprocs(3) +@everywhere using MixedModels, Random, StandardizedPredictors +df = DataFrame(Arrow.Table(Cache.data_path())) + +transform!(df, :Sex => categorical, :Test => categorical; renamecols=false) +recode!(df.Test, + "Run" => "Endurance", + "Star_r" => "Coordination", + "S20_r" => "Speed", + "SLJ" => "PowerLOW", + "BPT" => "PowerUP") +df = combine(groupby(df, :Test), :, :score => zscore => :zScore) +describe(df) + +contrasts = Dict(:Cohort => Grouping(), + :School => Grouping(), + :Child => Grouping(), + :Test => SeqDiffCoding(), + :Sex => EffectsCoding(), + :age => Center(8.5)) + +f1 = @formula( + zScore ~ + 1 + age * Test * Sex + + (1 + Test + age + Sex | School) + + (1 + Test | Child) + + zerocorr(1 + Test | Cohort) +) +m1 = fit(MixedModel, f1, df; contrasts, progress=true, thin=1) + +# copy everything to workers +@showprogress for w in workers() + remotecall_fetch(() -> coefnames(m1), w) +end + +# you need at least as many RNGs as cores you want to use in parallel +# but you shouldn't use all of your cores because nested within this +# is the multithreading of the linear algebra +# 5 RNGS and 10 replicates from each +pb_map = @time @showprogress pmap(MersenneTwister.(41:45)) do rng + parametricbootstrap(rng, 100, m1; optsum_overrides=(; maxfeval=300)) +end; +@time confint(reduce(vcat, pb_map)) diff --git a/src/MixedModels.jl b/src/MixedModels.jl index 38c37dc04..db21aef19 100644 --- a/src/MixedModels.jl +++ b/src/MixedModels.jl @@ -142,6 +142,9 @@ export @formula, weights, zerocorr +# TODO: move this to the correct spot in list once we've decided on name +export savereplicates, restorereplicates + """ MixedModel diff --git a/src/bootstrap.jl b/src/bootstrap.jl index c76257961..5161a6468 100644 --- a/src/bootstrap.jl +++ b/src/bootstrap.jl @@ -1,5 +1,9 @@ +""" + MixedModelFitCollection{T<:AbstractFloat} -abstract type MixedModelFitCollection{T<:AbstractFloat} end # model with fixed and random effects +Abstract supertype for [`MixedModelBootstrap`](@ref) and related functionality in other packages. +""" +abstract type MixedModelFitCollection{T<:AbstractFloat} end """ MixedModelBootstrap{T<:AbstractFloat} <: MixedModelFitCollection{T} @@ -34,9 +38,130 @@ struct MixedModelBootstrap{T<:AbstractFloat} <: MixedModelFitCollection{T} fcnames::NamedTuple end +Base.:(==)(a::MixedModelFitCollection{T}, b::MixedModelFitCollection{S}) where {T,S} = false + +function Base.:(==)(a::MixedModelFitCollection{T}, b::MixedModelFitCollection{T}) where {T} + return a.fits == b.fits && + a.λ == b.λ && + a.inds == b.inds && + a.lowerbd == b.lowerbd && + a.fcnames == b.fcnames +end + +function Base.isapprox(a::MixedModelFitCollection, b::MixedModelFitCollection; + atol::Real=0, rtol::Real=atol > 0 ? 0 : √eps()) + fits = all(zip(a.fits, b.fits)) do (x, y) + return isapprox(x.objective, y.objective; atol, rtol) && + isapprox(x.θ, y.θ; atol, rtol) && + isapprox(x.σ, y.σ; atol, rtol) && + all(isapprox(a, b; atol, rtol) for (a, b) in zip(x.β, y.β)) + end + + λ = all(zip(a.λ, b.λ)) do (x, y) + return isapprox(x, y; atol, rtol) + end + + return fits && λ && + # Vector{Vector{Int}} so no need for isapprox + a.inds == b.inds && + isapprox(a.lowerbd, b.lowerbd; atol, rtol) && + a.fcnames == b.fcnames +end + +""" + restorereplicates(f, m::MixedModel{T}) + restorereplicates(f, m::MixedModel{T}, ftype::Type{<:AbstractFloat}) + restorereplicates(f, m::MixedModel{T}, ctype::Type{<:MixedModelFitCollection{S}}) + +Restore replicates from `f`, using `m` to create the desired subtype of [`MixedModelFitCollection`](@ref). + +`f` can be any entity suppored by `Arrow.Table`. `m` does not have to be fitted, but it must have +been constructed with the same structure as the source of the saved replicates. + +The two-argument method constructs a [`MixedModelBootstrap`](@ref) with the same eltype as `m`. +If an eltype is specified as the third argument, then a `MixedModelBootstrap` is returned. +If a subtype of `MixedModelFitCollection` is specified as the third argument, then that +is the return type. + +See also [`savereplicates`](@ref), [`restoreoptsum!`](@ref). +""" +function restorereplicates(f, m::MixedModel{T}, ftype::Type{<:AbstractFloat}=T) where {T} + return restorereplicates(f, m, MixedModelBootstrap{ftype}) +end + +# why this weird second method? it allows us to define custom types and write methods +# to load into those types directly. For example, we could define a `PowerAnalysis <: MixedModelFitCollection` +# in MixedModelsSim and then overload this method to get a convenient object. +# Also, this allows us to write `restorereplicateS(f, m, ::Type{<:MixedModelNonparametricBoostrap})` for +# entities in MixedModels bootstrap +function restorereplicates( + f, m::MixedModel, ctype::Type{<:MixedModelFitCollection{T}} +) where {T} + tbl = Arrow.Table(f) + # use a lazy iterator to get the first element for checks + # before doing a conversion of the entire Arrow column table to row table + rep = first(Tables.rows(tbl)) + allgood = + length(rep.θ) == length(m.θ) && + string.(propertynames(rep.β)) == Tuple(coefnames(m)) + allgood || + throw(ArgumentError("Model is not compatible with saved replicates.")) + + samp = Tables.rowtable(tbl) + return ctype( + samp, + map(vv -> T.(vv), m.λ), # also does a deepcopy if no type conversion is necessary + getfield.(m.reterms, :inds), + T.(m.optsum.lowerbd[1:length(first(samp).θ)]), + NamedTuple{Symbol.(fnames(m))}(map(t -> Tuple(t.cnames), m.reterms)), + ) +end + +""" + savereplicates(f, b::MixedModelFitCollection) + +Save the replicates associated with a [`MixedModelFitCollection`](@ref), +e.g. [`MixedModelBootstrap`](@ref) as an Arrow file. + +See also [`restorereplicates`](@ref), [`saveoptsum`](@ref) + +!!! note + **Only** the replicates are saved, not the entire contents of the `MixedModelFitCollection`. + `restorereplicates` requires a model compatible with the bootstrap to restore the full object. +""" +savereplicates(f, b::MixedModelFitCollection) = Arrow.write(f, b.fits) + +# TODO: write methods for GLMM +function Base.vcat(b1::MixedModelBootstrap{T}, b2::MixedModelBootstrap{T}) where {T} + for field in [:λ, :inds, :lowerbd, :fcnames] + getfield(b1, field) == getfield(b2, field) || + throw(ArgumentError("b1 and b2 must originate from the same model fit")) + end + return MixedModelBootstrap{T}(vcat(b1.fits, b2.fits), + deepcopy(b1.λ), + deepcopy(b1.inds), + deepcopy(b1.lowerbd), + deepcopy(b1.fcnames)) +end + +function Base.reduce(::typeof(vcat), v::AbstractVector{MixedModelBootstrap{T}}) where {T} + for field in [:λ, :inds, :lowerbd, :fcnames] + all(==(getfield(first(v), field)), getfield.(v, field)) || + throw(ArgumentError("All bootstraps must originate from the same model fit")) + end + + b1 = first(v) + fits = reduce(vcat, getfield.(v, :fits)) + return MixedModelBootstrap{T}(fits, + deepcopy(b1.λ), + deepcopy(b1.inds), + deepcopy(b1.lowerbd), + deepcopy(b1.fcnames)) +end + """ parametricbootstrap([rng::AbstractRNG], nsamp::Integer, m::MixedModel{T}, ftype=T; - β = coef(m), σ = m.σ, θ = m.θ, hide_progress=false) + β = coef(m), σ = m.σ, θ = m.θ, hide_progress=false, optsum_overrides=(;)) Perform `nsamp` parametric bootstrap replication fits of `m`, returning a `MixedModelBootstrap`. @@ -47,13 +172,18 @@ not a named argument because named arguments are not used in method dispatch and specialization. In other words, having `ftype` as a positional argument has some potential performance benefits. -# Named Arguments +# Keyword Arguments - `β`, `σ`, and `θ` are the values of `m`'s parameters for simulating the responses. - `σ` is only valid for `LinearMixedModel` and `GeneralizedLinearMixedModel` for families with a dispersion parameter. - `hide_progress` can be used to disable the progress bar. Note that the progress bar is automatically disabled for non-interactive (i.e. logging) contexts. +- `optsum_overrides` is used to override values of [OptSummary](@ref) in the models +fit during the bootstrapping process. For example, `optsum_overrides=(;ftol_rel=1e08)` +reduces the convergence criterion, which can greatly speed up the bootstrap fits. +Taking advantage of this speed up to increase `n` can often lead to better estimates +of coverage intervals. """ function parametricbootstrap( rng::AbstractRNG, @@ -65,6 +195,7 @@ function parametricbootstrap( θ::AbstractVector=morig.θ, use_threads::Bool=false, hide_progress::Bool=false, + optsum_overrides=(;), ) where {T} if σ !== missing σ = T(σ) @@ -73,8 +204,13 @@ function parametricbootstrap( βsc, θsc = similar(ftype.(β)), similar(ftype.(θ)) p, k = length(β), length(θ) m = deepcopy(morig) + for (key, val) in pairs(optsum_overrides) + setfield!(m.optsum, key, val) + end + # this seemed to slow things down?! + # _copy_away_from_lowerbd!(m.optsum.initial, morig.optsum.final, m.lowerbd; incr=0.05) - β_names = (Symbol.(fixefnames(morig))...,) + β_names = Tuple(Symbol.(fixefnames(morig))) use_threads && Base.depwarn( "use_threads is deprecated and will be removed in a future release", @@ -83,6 +219,7 @@ function parametricbootstrap( samp = replicate(n; hide_progress=hide_progress) do simulate!(rng, m; β, σ, θ) refit!(m; progress=false) + # @info "" m.optsum.feval ( objective=ftype.(m.objective), σ=ismissing(m.σ) ? missing : ftype(m.σ), @@ -96,7 +233,7 @@ function parametricbootstrap( map(vv -> ftype.(vv), morig.λ), # also does a deepcopy if no type conversion is necessary getfield.(morig.reterms, :inds), ftype.(morig.optsum.lowerbd[1:length(first(samp).θ)]), - NamedTuple{Symbol.(fnames(morig))}(map(t -> (t.cnames...,), morig.reterms)), + NamedTuple{Symbol.(fnames(morig))}(map(t -> Tuple(t.cnames), morig.reterms)), ) end diff --git a/src/optsummary.jl b/src/optsummary.jl index 837868eb4..e79fb4557 100644 --- a/src/optsummary.jl +++ b/src/optsummary.jl @@ -176,9 +176,9 @@ const _NLOPT_FAILURE_MODES = [ :MAXTIME_REACHED, ] -function _check_nlopt_return(ret) +function _check_nlopt_return(ret, failure_modes=_NLOPT_FAILURE_MODES) ret == :ROUNDOFF_LIMITED && @warn("NLopt was roundoff limited") - if ret ∈ _NLOPT_FAILURE_MODES + if ret ∈ failure_modes @warn("NLopt optimization failure: $ret") end end diff --git a/test/bootstrap.jl b/test/bootstrap.jl index 4943ccbc6..f787a5d0c 100644 --- a/test/bootstrap.jl +++ b/test/bootstrap.jl @@ -12,6 +12,13 @@ using MixedModels: dataset, MixedModelBootstrap include("modelcache.jl") +function quickboot(m, n=2) + return parametricbootstrap(MersenneTwister(42), n, m; + hide_progress=true, use_threads=false, + optsum_overrides=(;ftol_rel=1e-8)) +end + + @testset "simulate!(::MixedModel)" begin @testset "LMM" begin ds = dataset(:dyestuff) @@ -79,6 +86,19 @@ end @test length(bsamp.σs) == 100 allpars = DataFrame(bsamp.allpars) @test isa(allpars, DataFrame) + + @testset "optsum_overrides" begin + bsamp2 = parametricbootstrap(MersenneTwister(1234321), 100, fm; + use_threads=false, hide_progress=true, + optsum_overrides=(;ftol_rel=1e-8)) + # for such a simple, small model setting the function value + # tolerance has little effect until we do something extreme + @test bsamp.objective ≈ bsamp2.objective + bsamp2 = parametricbootstrap(MersenneTwister(1234321), 100, fm; + use_threads=false, hide_progress=true, + optsum_overrides=(;ftol_rel=1.0)) + @test !(bsamp.objective ≈ bsamp2.objective) + end cov = shortestcovint(shuffle(1.:100.)) # there is no unique shortest coverage interval here, but the left-most one # is currently returned, so we take that. If this behavior changes, then @@ -116,6 +136,56 @@ end hide_progress=true) end + @testset "vcat" begin + sleep = quickboot(last(models(:sleepstudy))) + zc1 = quickboot(models(:sleepstudy)[2]) + zc2 = quickboot(models(:sleepstudy)[3]) + + @test_throws ArgumentError vcat(sleep, zc1) + @test_throws ArgumentError reduce(vcat, [sleep, zc1]) + # these are the same model even if the formulae + # are expressed differently + @test length(vcat(zc1, zc2)) == 4 + @test length(reduce(vcat, [zc1, zc2])) == 4 + end + + @testset "save and restore replicates" begin + io = IOBuffer() + m0 = first(models(:sleepstudy)) + m1 = last(models(:sleepstudy)) + pb0 = quickboot(m0) + pb1 = quickboot(m1) + savereplicates(io, pb1) + # wrong model`` + @test_throws ArgumentError restorereplicates(seekstart(io), m0) + # need to specify an eltype! + @test_throws MethodError restorereplicates(seekstart(io), m1, MixedModelBootstrap) + + # make sure exact and approximate equality work + @test pb1 == pb1 + @test pb1 == restorereplicates(seekstart(io), m1) + @test pb1 ≈ restorereplicates(seekstart(io), m1) + @test pb1 ≈ pb1 + @test pb1 ≈ restorereplicates(seekstart(io), m1, Float64) + @test restorereplicates(seekstart(io), m1, Float32) ≈ restorereplicates(seekstart(io), m1, Float32) + # too much precision is lost + f16 = restorereplicates(seekstart(io), m1, Float16) + @test !isapprox(pb1, f16) + @test isapprox(pb1, f16; atol=eps(Float16)) + @test isapprox(pb1, f16; rtol=0.0001) + + + # two paths, one destination + @test restorereplicates(seekstart(io), m1, MixedModelBootstrap{Float16}) == restorereplicates(seekstart(io), m1, Float16) + # changing eltype breaks exact equality + @test pb1 != restorereplicates(seekstart(io), m1, Float32) + + # test that we don't need the model to be fit when restoring + @test pb1 == restorereplicates(seekstart(io), MixedModels.unfit!(deepcopy(m1))) + + @test pb1 ≈ restorereplicates(seekstart(io), m1, Float16) rtol=1 + end + @testset "Bernoulli simulate! and GLMM bootstrap" begin contra = dataset(:contra) # need a model with fast=false to test that we only From 5ade8c4613f52656bde992cc861d8396286c971d Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Tue, 8 Aug 2023 17:36:09 +0000 Subject: [PATCH 44/51] Add tolerances in deserialization (#703) * support passing tolerances to restoreoptsum! * test * NEWS * version bump * JuliaFormatter --------- Co-authored-by: Douglas Bates --- NEWS.md | 5 +++++ Project.toml | 2 +- src/serialization.jl | 17 +++++++++++------ test/pls.jl | 16 +++++++++++++--- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index af3463200..e8b325165 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.16.0 Release Notes +============================== +* Support for check tolerances in deserialization. [#703] + MixedModels v4.15.0 Release Notes ============================== * Support for different optimization criteria during the bootstrap. [#694] @@ -442,3 +446,4 @@ Package dependencies [#681]: https://github.com/JuliaStats/MixedModels.jl/issues/681 [#682]: https://github.com/JuliaStats/MixedModels.jl/issues/682 [#694]: https://github.com/JuliaStats/MixedModels.jl/issues/694 +[#703]: https://github.com/JuliaStats/MixedModels.jl/issues/703 diff --git a/Project.toml b/Project.toml index 1078a09f3..498deacd3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.15.0" +version = "4.16.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/serialization.jl b/src/serialization.jl index 9fb2b25e7..47cfade90 100644 --- a/src/serialization.jl +++ b/src/serialization.jl @@ -1,10 +1,13 @@ """ - restoreoptsum!(m::LinearMixedModel, io::IO) - restoreoptsum!(m::LinearMixedModel, filename) + restoreoptsum!(m::LinearMixedModel, io::IO; atol::Real=0, rtol::Real=atol>0 ? 0 : √eps) + restoreoptsum!(m::LinearMixedModel, filename; atol::Real=0, rtol::Real=atol>0 ? 0 : √eps) Read, check, and restore the `optsum` field from a JSON stream or filename. """ -function restoreoptsum!(m::LinearMixedModel{T}, io::IO) where {T} +function restoreoptsum!( + m::LinearMixedModel{T}, io::IO; atol::Real=zero(T), + rtol::Real=atol > 0 ? zero(T) : √eps(T), +) where {T} dict = JSON3.read(io) ops = m.optsum okay = @@ -22,7 +25,9 @@ function restoreoptsum!(m::LinearMixedModel{T}, io::IO) where {T} copyto!(ops.initial, dict.initial) copyto!(ops.final, dict.final) for (v, f) in (:initial => :finitial, :final => :fmin) - if !isapprox(objective(updateL!(setθ!(m, getfield(ops, v)))), getfield(ops, f)) + if !isapprox( + objective(updateL!(setθ!(m, getfield(ops, v)))), getfield(ops, f); rtol, atol + ) throw(ArgumentError("model m at $v does not give stored $f")) end end @@ -40,9 +45,9 @@ function restoreoptsum!(m::LinearMixedModel{T}, io::IO) where {T} return m end -function restoreoptsum!(m::LinearMixedModel{T}, filename) where {T} +function restoreoptsum!(m::LinearMixedModel{T}, filename; kwargs...) where {T} open(filename, "r") do io - restoreoptsum!(m, io) + restoreoptsum!(m, io; kwargs...) end end diff --git a/test/pls.jl b/test/pls.jl index 1e1edc2e4..2b2ab3928 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -167,7 +167,7 @@ end sigma0row = only(filter(r -> r.p == :σ && iszero(r.ζ), dspr01.tbl)) @test sigma0row.σ ≈ dspr01.m.σ @test sigma0row.β1 ≈ only(dspr01.m.β) - @test sigma0row.θ1 ≈ only(dspr01.m.θ) + @test sigma0row.θ1 ≈ only(dspr01.m.θ) end end @@ -500,14 +500,23 @@ end @testset "optsumJSON" begin fm = last(models(:sleepstudy)) - # using a IOBuffer for saving JSON + # using a IOBuffer for saving JSON saveoptsum(seekstart(io), fm) m = LinearMixedModel(fm.formula, MixedModels.dataset(:sleepstudy)) restoreoptsum!(m, seekstart(io)) @test loglikelihood(fm) ≈ loglikelihood(m) @test bic(fm) ≈ bic(m) @test coef(fm) ≈ coef(m) - # using a temporary file for saving JSON + + fm_mod = deepcopy(fm) + fm_mod.optsum.fmin += 1 + saveoptsum(seekstart(io), fm_mod) + @test_throws(ArgumentError("model m at final does not give stored fmin"), + restoreoptsum!(m, seekstart(io))) + restoreoptsum!(m, seekstart(io); atol=1) + @test m.optsum.fmin - fm.optsum.fmin ≈ 1 + + # using a temporary file for saving JSON fnm = first(mktemp()) saveoptsum(fnm, fm) m = LinearMixedModel(fm.formula, MixedModels.dataset(:sleepstudy)) @@ -516,6 +525,7 @@ end @test bic(fm) ≈ bic(m) @test coef(fm) ≈ coef(m) end + @testset "profile" begin pr = profile(last(models(:sleepstudy))) tbl = pr.tbl From 2af0322cab5d2bcf08ae9dedd34e3aa47795241c Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 9 Aug 2023 13:31:31 +0000 Subject: [PATCH 45/51] allow the user to disable amalgamation (#673) * kwarg for optional amalgmate * allow the user to disable amalgamation * issue xref * punt kwarg checking to the methods that can deal with them * update example * relocate news entry * add some tests * mark it experimental in NEWS * JuliaFormatter --- NEWS.md | 3 + issues/638/Manifest.toml | 534 +++++++++++++++-------------- issues/638/main.jl | 5 + src/generalizedlinearmixedmodel.jl | 14 +- src/linalg/rankUpdate.jl | 11 + src/linearmixedmodel.jl | 86 ++--- src/mixedmodel.jl | 10 +- src/remat.jl | 7 +- test/pls.jl | 11 + 9 files changed, 364 insertions(+), 317 deletions(-) diff --git a/NEWS.md b/NEWS.md index e8b325165..7980035c7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,5 @@ +* New kwarg `amalgamate` can be used to disable amalgation of random0effects terms sharing a single grouping variable. Generally, `amalgamate=false` will result in a slower fit, but may improve convergence in some pathological cases. Note that this feature is experimental and changes to it are **not** considered breakin. [#673] + MixedModels v4.16.0 Release Notes ============================== * Support for check tolerances in deserialization. [#703] @@ -439,6 +441,7 @@ Package dependencies [#664]: https://github.com/JuliaStats/MixedModels.jl/issues/664 [#665]: https://github.com/JuliaStats/MixedModels.jl/issues/665 [#667]: https://github.com/JuliaStats/MixedModels.jl/issues/667 +[#673]: https://github.com/JuliaStats/MixedModels.jl/issues/673 [#674]: https://github.com/JuliaStats/MixedModels.jl/issues/674 [#676]: https://github.com/JuliaStats/MixedModels.jl/issues/676 [#677]: https://github.com/JuliaStats/MixedModels.jl/issues/677 diff --git a/issues/638/Manifest.toml b/issues/638/Manifest.toml index a6110c715..9f096a1cb 100644 --- a/issues/638/Manifest.toml +++ b/issues/638/Manifest.toml @@ -1,1426 +1,1428 @@ # This file is machine-generated - editing it directly is not advised -[[AbstractFFTs]] +manifest_format = "2.0" + +[[deps.AbstractFFTs]] deps = ["ChainRulesCore", "LinearAlgebra"] git-tree-sha1 = "69f7020bd72f069c219b5e8c236c1fa90d2cb409" uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" version = "1.2.1" -[[AbstractTrees]] +[[deps.AbstractTrees]] git-tree-sha1 = "5c0b629df8a5566a06f5fef5100b53ea56e465a0" uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" version = "0.4.2" -[[Adapt]] +[[deps.Adapt]] deps = ["LinearAlgebra"] git-tree-sha1 = "195c5505521008abea5aee4f96930717958eac6f" uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" version = "3.4.0" -[[Animations]] +[[deps.Animations]] deps = ["Colors"] git-tree-sha1 = "e81c509d2c8e49592413bfb0bb3b08150056c79d" uuid = "27a7e980-b3e6-11e9-2bcd-0b925532e340" version = "0.4.1" -[[ArgTools]] +[[deps.ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" version = "1.1.1" -[[Arrow]] +[[deps.Arrow]] deps = ["ArrowTypes", "BitIntegers", "CodecLz4", "CodecZstd", "DataAPI", "Dates", "Mmap", "PooledArrays", "SentinelArrays", "Tables", "TimeZones", "UUIDs"] git-tree-sha1 = "4e7aa2021204bd9456ad3e87372237e84ee2c3c1" uuid = "69666777-d1a9-59fb-9406-91d4454c9d45" version = "2.3.0" -[[ArrowTypes]] +[[deps.ArrowTypes]] deps = ["UUIDs"] git-tree-sha1 = "a0633b6d6efabf3f76dacd6eb1b3ec6c42ab0552" uuid = "31f734f8-188a-4ce0-8406-c8a06bd891cd" version = "1.2.1" -[[Artifacts]] +[[deps.Artifacts]] uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" -[[Automa]] +[[deps.Automa]] deps = ["Printf", "ScanByte", "TranscodingStreams"] git-tree-sha1 = "d50976f217489ce799e366d9561d56a98a30d7fe" uuid = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b" version = "0.8.2" -[[AxisAlgorithms]] +[[deps.AxisAlgorithms]] deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] git-tree-sha1 = "66771c8d21c8ff5e3a93379480a2307ac36863f7" uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" version = "1.0.1" -[[Base64]] +[[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" -[[BenchmarkTools]] +[[deps.BenchmarkTools]] deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] git-tree-sha1 = "4c10eee4af024676200bc7752e536f858c6b8f93" uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" version = "1.3.1" -[[BitIntegers]] +[[deps.BitIntegers]] deps = ["Random"] git-tree-sha1 = "5a814467bda636f3dde5c4ef83c30dd0a19928e0" uuid = "c3b6d118-76ef-56ca-8cc7-ebb389d030a1" version = "0.2.6" -[[Bzip2_jll]] +[[deps.Bzip2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" version = "1.0.8+0" -[[CEnum]] +[[deps.CEnum]] git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90" uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" version = "0.4.2" -[[CSV]] +[[deps.CSV]] deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings"] git-tree-sha1 = "873fb188a4b9d76549b81465b1f75c82aaf59238" uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" version = "0.10.4" -[[Cairo]] +[[deps.Cairo]] deps = ["Cairo_jll", "Colors", "Glib_jll", "Graphics", "Libdl", "Pango_jll"] git-tree-sha1 = "d0b3f8b4ad16cb0a2988c6788646a5e6a17b6b1b" uuid = "159f3aea-2a34-519c-b102-8c37f9878175" version = "1.0.5" -[[CairoMakie]] +[[deps.CairoMakie]] deps = ["Base64", "Cairo", "Colors", "FFTW", "FileIO", "FreeType", "GeometryBasics", "LinearAlgebra", "Makie", "SHA", "SnoopPrecompile"] git-tree-sha1 = "f53b586e9489163ece213144a5a6417742f0388e" uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" version = "0.9.0" -[[Cairo_jll]] -deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +[[deps.Cairo_jll]] +deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" version = "1.16.1+1" -[[Calculus]] +[[deps.Calculus]] deps = ["LinearAlgebra"] git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" version = "0.5.1" -[[ChainRulesCore]] +[[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra", "SparseArrays"] git-tree-sha1 = "e7ff6cadf743c098e08fca25c91103ee4303c9bb" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" version = "1.15.6" -[[ChangesOfVariables]] +[[deps.ChangesOfVariables]] deps = ["ChainRulesCore", "LinearAlgebra", "Test"] git-tree-sha1 = "38f7a08f19d8810338d4f5085211c7dfa5d5bdd8" uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" version = "0.1.4" -[[CodecBzip2]] +[[deps.CodecBzip2]] deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"] git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7" uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd" version = "0.7.2" -[[CodecLz4]] +[[deps.CodecLz4]] deps = ["Lz4_jll", "TranscodingStreams"] git-tree-sha1 = "59fe0cb37784288d6b9f1baebddbf75457395d40" uuid = "5ba52731-8f18-5e0d-9241-30f10d1ec561" version = "0.4.0" -[[CodecZlib]] +[[deps.CodecZlib]] deps = ["TranscodingStreams", "Zlib_jll"] git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da" uuid = "944b1d66-785c-5afd-91f1-9de20f533193" version = "0.7.0" -[[CodecZstd]] +[[deps.CodecZstd]] deps = ["CEnum", "TranscodingStreams", "Zstd_jll"] git-tree-sha1 = "849470b337d0fa8449c21061de922386f32949d9" uuid = "6b39b394-51ab-5f42-8807-6242bab2b4c2" version = "0.7.2" -[[ColorBrewer]] +[[deps.ColorBrewer]] deps = ["Colors", "JSON", "Test"] git-tree-sha1 = "61c5334f33d91e570e1d0c3eb5465835242582c4" uuid = "a2cac450-b92f-5266-8821-25eda20663c8" version = "0.4.0" -[[ColorSchemes]] +[[deps.ColorSchemes]] deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Random"] git-tree-sha1 = "1fd869cc3875b57347f7027521f561cf46d1fcd8" uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" version = "3.19.0" -[[ColorTypes]] +[[deps.ColorTypes]] deps = ["FixedPointNumbers", "Random"] git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" version = "0.11.4" -[[ColorVectorSpace]] +[[deps.ColorVectorSpace]] deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] git-tree-sha1 = "d08c20eef1f2cbc6e60fd3612ac4340b89fea322" uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" version = "0.9.9" -[[Colors]] +[[deps.Colors]] deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" version = "0.12.8" -[[CommonSubexpressions]] +[[deps.CommonSubexpressions]] deps = ["MacroTools", "Test"] git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" version = "0.3.0" -[[Compat]] +[[deps.Compat]] deps = ["Dates", "LinearAlgebra", "UUIDs"] git-tree-sha1 = "5856d3031cdb1f3b2b6340dfdc66b6d9a149a374" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" version = "4.2.0" -[[CompilerSupportLibraries_jll]] +[[deps.CompilerSupportLibraries_jll]] deps = ["Artifacts", "Libdl"] uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "0.5.2+0" +version = "1.0.1+0" -[[Contour]] +[[deps.Contour]] git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781" uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" version = "0.6.2" -[[Crayons]] +[[deps.Crayons]] git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" version = "4.1.1" -[[DataAPI]] +[[deps.DataAPI]] git-tree-sha1 = "46d2680e618f8abd007bce0c3026cb0c4a8f2032" uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" version = "1.12.0" -[[DataFrames]] +[[deps.DataFrames]] deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Random", "Reexport", "SnoopPrecompile", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] git-tree-sha1 = "1df8f72c05cc83c1e6907f393312d3b009bcc3d4" uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" version = "1.4.0" -[[DataStructures]] +[[deps.DataStructures]] deps = ["Compat", "InteractiveUtils", "OrderedCollections"] git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" version = "0.18.13" -[[DataValueInterfaces]] +[[deps.DataValueInterfaces]] git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" version = "1.0.0" -[[Dates]] +[[deps.Dates]] deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" -[[DensityInterface]] +[[deps.DensityInterface]] deps = ["InverseFunctions", "Test"] git-tree-sha1 = "80c3e8639e3353e5d2912fb3a1916b8455e2494b" uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d" version = "0.4.0" -[[DiffResults]] +[[deps.DiffResults]] deps = ["StaticArraysCore"] git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" version = "1.1.0" -[[DiffRules]] +[[deps.DiffRules]] deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] git-tree-sha1 = "992a23afdb109d0d2f8802a30cf5ae4b1fe7ea68" uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" version = "1.11.1" -[[Distributed]] +[[deps.Distributed]] deps = ["Random", "Serialization", "Sockets"] uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" -[[Distributions]] +[[deps.Distributions]] deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Test"] git-tree-sha1 = "0d7d213133d948c56e8c2d9f4eab0293491d8e4a" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" version = "0.25.75" -[[DocStringExtensions]] +[[deps.DocStringExtensions]] deps = ["LibGit2"] git-tree-sha1 = "5158c2b41018c5f7eb1470d558127ac274eca0c9" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" version = "0.9.1" -[[Downloads]] +[[deps.Downloads]] deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" version = "1.6.0" -[[DualNumbers]] +[[deps.DualNumbers]] deps = ["Calculus", "NaNMath", "SpecialFunctions"] git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" version = "0.6.8" -[[EarCut_jll]] +[[deps.EarCut_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "e3290f2d49e661fbd94046d7e3726ffcb2d41053" uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" version = "2.2.4+0" -[[Expat_jll]] +[[deps.Expat_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "bad72f730e9e91c08d9427d5e8db95478a3c323d" uuid = "2e619515-83b5-522b-bb60-26c02a35a201" version = "2.4.8+0" -[[ExprTools]] +[[deps.ExprTools]] git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d" uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" version = "0.1.8" -[[Extents]] +[[deps.Extents]] git-tree-sha1 = "5e1e4c53fa39afe63a7d356e30452249365fba99" uuid = "411431e0-e8b7-467b-b5e0-f676ba4f2910" version = "0.1.1" -[[FFMPEG]] +[[deps.FFMPEG]] deps = ["FFMPEG_jll"] git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" version = "0.4.1" -[[FFMPEG_jll]] +[[deps.FFMPEG_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Pkg", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] git-tree-sha1 = "74faea50c1d007c85837327f6775bea60b5492dd" uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" version = "4.4.2+2" -[[FFTW]] +[[deps.FFTW]] deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] git-tree-sha1 = "90630efff0894f8142308e334473eba54c433549" uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" version = "1.5.0" -[[FFTW_jll]] +[[deps.FFTW_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea" uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" version = "3.3.10+0" -[[FileIO]] +[[deps.FileIO]] deps = ["Pkg", "Requires", "UUIDs"] git-tree-sha1 = "7be5f99f7d15578798f338f5433b6c432ea8037b" uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" version = "1.16.0" -[[FilePathsBase]] +[[deps.FilePathsBase]] deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"] git-tree-sha1 = "e27c4ebe80e8699540f2d6c805cc12203b614f12" uuid = "48062228-2e41-5def-b9a4-89aafe57970f" version = "0.9.20" -[[FileWatching]] +[[deps.FileWatching]] uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" -[[FillArrays]] +[[deps.FillArrays]] deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] git-tree-sha1 = "87519eb762f85534445f5cda35be12e32759ee14" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" version = "0.13.4" -[[FixedPointNumbers]] +[[deps.FixedPointNumbers]] deps = ["Statistics"] git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" version = "0.8.4" -[[Fontconfig_jll]] +[[deps.Fontconfig_jll]] deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" version = "2.13.93+0" -[[Formatting]] +[[deps.Formatting]] deps = ["Printf"] git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" version = "0.4.2" -[[ForwardDiff]] +[[deps.ForwardDiff]] deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"] git-tree-sha1 = "187198a4ed8ccd7b5d99c41b69c679269ea2b2d4" uuid = "f6369f11-7733-5829-9624-2563aa707210" version = "0.10.32" -[[FreeType]] +[[deps.FreeType]] deps = ["CEnum", "FreeType2_jll"] git-tree-sha1 = "cabd77ab6a6fdff49bfd24af2ebe76e6e018a2b4" uuid = "b38be410-82b0-50bf-ab77-7b57e271db43" version = "4.0.0" -[[FreeType2_jll]] +[[deps.FreeType2_jll]] deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" version = "2.10.4+0" -[[FreeTypeAbstraction]] +[[deps.FreeTypeAbstraction]] deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics"] git-tree-sha1 = "38a92e40157100e796690421e34a11c107205c86" uuid = "663a7486-cb36-511b-a19d-713bb74d65c9" version = "0.10.0" -[[FriBidi_jll]] +[[deps.FriBidi_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" uuid = "559328eb-81f9-559d-9380-de523a88c83c" version = "1.0.10+0" -[[Future]] +[[deps.Future]] deps = ["Random"] uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" -[[GLM]] +[[deps.GLM]] deps = ["Distributions", "LinearAlgebra", "Printf", "Reexport", "SparseArrays", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "StatsModels"] git-tree-sha1 = "039118892476c2bf045a43b88fcb75ed566000ff" uuid = "38e38edf-8417-5370-95a0-9cbb8c7f171a" version = "1.8.0" -[[GeoInterface]] +[[deps.GeoInterface]] deps = ["Extents"] git-tree-sha1 = "fb28b5dc239d0174d7297310ef7b84a11804dfab" uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" version = "1.0.1" -[[GeometryBasics]] +[[deps.GeometryBasics]] deps = ["EarCut_jll", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] git-tree-sha1 = "12a584db96f1d460421d5fb8860822971cdb8455" uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" version = "0.4.4" -[[Gettext_jll]] +[[deps.Gettext_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" version = "0.21.0+0" -[[Glib_jll]] +[[deps.Glib_jll]] deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "fb83fbe02fe57f2c068013aa94bcdf6760d3a7a7" +git-tree-sha1 = "d3b3624125c1474292d0d8ed0f65554ac37ddb23" uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" -version = "2.74.0+1" +version = "2.74.0+2" -[[Graphics]] +[[deps.Graphics]] deps = ["Colors", "LinearAlgebra", "NaNMath"] git-tree-sha1 = "d61890399bc535850c4bf08e4e0d3a7ad0f21cbd" uuid = "a2bd30eb-e257-5431-a919-1863eab51364" version = "1.1.2" -[[Graphite2_jll]] +[[deps.Graphite2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" version = "1.3.14+0" -[[GridLayoutBase]] +[[deps.GridLayoutBase]] deps = ["GeometryBasics", "InteractiveUtils", "Observables"] git-tree-sha1 = "678d136003ed5bceaab05cf64519e3f956ffa4ba" uuid = "3955a311-db13-416c-9275-1d80ed98e5e9" version = "0.9.1" -[[Grisu]] +[[deps.Grisu]] git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" version = "1.0.2" -[[HarfBuzz_jll]] +[[deps.HarfBuzz_jll]] deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" version = "2.8.1+1" -[[HypergeometricFunctions]] +[[deps.HypergeometricFunctions]] deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions", "Test"] git-tree-sha1 = "709d864e3ed6e3545230601f94e11ebc65994641" uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" version = "0.3.11" -[[ImageCore]] +[[deps.ImageCore]] deps = ["AbstractFFTs", "ColorVectorSpace", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"] git-tree-sha1 = "acf614720ef026d38400b3817614c45882d75500" uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534" version = "0.9.4" -[[ImageIO]] +[[deps.ImageIO]] deps = ["FileIO", "IndirectArrays", "JpegTurbo", "LazyModules", "Netpbm", "OpenEXR", "PNGFiles", "QOI", "Sixel", "TiffImages", "UUIDs"] git-tree-sha1 = "342f789fd041a55166764c351da1710db97ce0e0" uuid = "82e4d734-157c-48bb-816b-45c225c6df19" version = "0.6.6" -[[Imath_jll]] +[[deps.Imath_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "87f7662e03a649cffa2e05bf19c303e168732d3e" uuid = "905a6f67-0a94-5f89-b386-d35d92009cd1" version = "3.1.2+0" -[[IndirectArrays]] +[[deps.IndirectArrays]] git-tree-sha1 = "012e604e1c7458645cb8b436f8fba789a51b257f" uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959" version = "1.0.0" -[[Inflate]] +[[deps.Inflate]] git-tree-sha1 = "5cd07aab533df5170988219191dfad0519391428" uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" version = "0.1.3" -[[InlineStrings]] +[[deps.InlineStrings]] deps = ["Parsers"] git-tree-sha1 = "d0ca109edbae6b4cc00e751a29dcb15a124053d6" uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" version = "1.2.0" -[[IntelOpenMP_jll]] +[[deps.IntelOpenMP_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c" uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" version = "2018.0.3+2" -[[InteractiveUtils]] +[[deps.InteractiveUtils]] deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" -[[Interpolations]] +[[deps.Interpolations]] deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] git-tree-sha1 = "842dd89a6cb75e02e85fdd75c760cdc43f5d6863" uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" version = "0.14.6" -[[IntervalSets]] +[[deps.IntervalSets]] deps = ["Dates", "Random", "Statistics"] git-tree-sha1 = "3f91cd3f56ea48d4d2a75c2a65455c5fc74fa347" uuid = "8197267c-284f-5f27-9208-e0e47529a953" version = "0.7.3" -[[InverseFunctions]] +[[deps.InverseFunctions]] deps = ["Test"] git-tree-sha1 = "49510dfcb407e572524ba94aeae2fced1f3feb0f" uuid = "3587e190-3f89-42d0-90ee-14403ec27112" version = "0.1.8" -[[InvertedIndices]] +[[deps.InvertedIndices]] git-tree-sha1 = "bee5f1ef5bf65df56bdd2e40447590b272a5471f" uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" version = "1.1.0" -[[IrrationalConstants]] +[[deps.IrrationalConstants]] git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" version = "0.1.1" -[[Isoband]] +[[deps.Isoband]] deps = ["isoband_jll"] git-tree-sha1 = "f9b6d97355599074dc867318950adaa6f9946137" uuid = "f1662d9f-8043-43de-a69a-05efc1cc6ff4" version = "0.1.1" -[[IterTools]] +[[deps.IterTools]] git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5" uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" version = "1.4.0" -[[IteratorInterfaceExtensions]] +[[deps.IteratorInterfaceExtensions]] git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" uuid = "82899510-4779-5014-852e-03e436cf321d" version = "1.0.0" -[[JLLWrappers]] +[[deps.JLLWrappers]] deps = ["Preferences"] git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" version = "1.4.1" -[[JSON]] +[[deps.JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" version = "0.21.3" -[[JSON3]] +[[deps.JSON3]] deps = ["Dates", "Mmap", "Parsers", "StructTypes", "UUIDs"] git-tree-sha1 = "f1572de22c866dc92aea032bc89c2b137cbddd6a" uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" version = "1.10.0" -[[JpegTurbo]] +[[deps.JpegTurbo]] deps = ["CEnum", "FileIO", "ImageCore", "JpegTurbo_jll", "TOML"] git-tree-sha1 = "a77b273f1ddec645d1b7c4fd5fb98c8f90ad10a5" uuid = "b835a17e-a41a-41e7-81f0-2f016b05efe0" version = "0.1.1" -[[JpegTurbo_jll]] +[[deps.JpegTurbo_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "b53380851c6e6664204efb2e62cd24fa5c47e4ba" uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" version = "2.1.2+0" -[[KernelDensity]] +[[deps.KernelDensity]] deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] git-tree-sha1 = "9816b296736292a80b9a3200eb7fbb57aaa3917a" uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" version = "0.6.5" -[[LAME_jll]] +[[deps.LAME_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" version = "3.100.1+0" -[[LZO_jll]] +[[deps.LZO_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" version = "2.10.1+0" -[[LaTeXStrings]] +[[deps.LaTeXStrings]] git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" version = "1.3.0" -[[LazyArtifacts]] +[[deps.LazyArtifacts]] deps = ["Artifacts", "Pkg"] uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" -[[LazyModules]] +[[deps.LazyModules]] git-tree-sha1 = "a560dd966b386ac9ae60bdd3a3d3a326062d3c3e" uuid = "8cdb02fc-e678-4876-92c5-9defec4f444e" version = "0.3.1" -[[LibCURL]] +[[deps.LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" version = "0.6.3" -[[LibCURL_jll]] +[[deps.LibCURL_jll]] deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" version = "7.84.0+0" -[[LibGit2]] +[[deps.LibGit2]] deps = ["Base64", "NetworkOptions", "Printf", "SHA"] uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" -[[LibSSH2_jll]] +[[deps.LibSSH2_jll]] deps = ["Artifacts", "Libdl", "MbedTLS_jll"] uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" version = "1.10.2+0" -[[Libdl]] +[[deps.Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" -[[Libffi_jll]] +[[deps.Libffi_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" version = "3.2.2+1" -[[Libgcrypt_jll]] +[[deps.Libgcrypt_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" version = "1.8.7+0" -[[Libgpg_error_jll]] +[[deps.Libgpg_error_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" version = "1.42.0+0" -[[Libiconv_jll]] +[[deps.Libiconv_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" +git-tree-sha1 = "c7cb1f5d892775ba13767a87c7ada0b980ea0a71" uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" -version = "1.16.1+1" +version = "1.16.1+2" -[[Libmount_jll]] +[[deps.Libmount_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" version = "2.35.0+0" -[[Libuuid_jll]] +[[deps.Libuuid_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" version = "2.36.0+0" -[[LinearAlgebra]] +[[deps.LinearAlgebra]] deps = ["Libdl", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -[[LogExpFunctions]] +[[deps.LogExpFunctions]] deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] git-tree-sha1 = "94d9c52ca447e23eac0c0f074effbcd38830deb5" uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" version = "0.3.18" -[[Logging]] +[[deps.Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" -[[Lz4_jll]] +[[deps.Lz4_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "5d494bc6e85c4c9b626ee0cab05daa4085486ab1" uuid = "5ced341a-0733-55b8-9ab6-a4889d929147" version = "1.9.3+0" -[[MKL_jll]] +[[deps.MKL_jll]] deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"] git-tree-sha1 = "2ce8695e1e699b68702c03402672a69f54b8aca9" uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" version = "2022.2.0+0" -[[MacroTools]] +[[deps.MacroTools]] deps = ["Markdown", "Random"] git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" version = "0.5.9" -[[Makie]] +[[deps.Makie]] deps = ["Animations", "Base64", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "Distributions", "DocStringExtensions", "FFMPEG", "FileIO", "FixedPointNumbers", "Formatting", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageIO", "InteractiveUtils", "IntervalSets", "Isoband", "KernelDensity", "LaTeXStrings", "LinearAlgebra", "MakieCore", "Markdown", "Match", "MathTeXEngine", "MiniQhull", "Observables", "OffsetArrays", "Packing", "PlotUtils", "PolygonOps", "Printf", "Random", "RelocatableFolders", "Serialization", "Showoff", "SignedDistanceFields", "SnoopPrecompile", "SparseArrays", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "TriplotBase", "UnicodeFun"] git-tree-sha1 = "51e40869d076fbff25ab61d0aa3e198d80176c75" uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" version = "0.18.0" -[[MakieCore]] +[[deps.MakieCore]] deps = ["Observables"] git-tree-sha1 = "b87650f61f85fc2d4fb5923a479dbf05ba65ae4d" uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b" version = "0.5.0" -[[MappedArrays]] +[[deps.MappedArrays]] git-tree-sha1 = "e8b359ef06ec72e8c030463fe02efe5527ee5142" uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900" version = "0.4.1" -[[Markdown]] +[[deps.Markdown]] deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" -[[Match]] +[[deps.Match]] git-tree-sha1 = "1d9bc5c1a6e7ee24effb93f175c9342f9154d97f" uuid = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf" version = "1.2.0" -[[MathOptInterface]] +[[deps.MathOptInterface]] deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "Printf", "SparseArrays", "SpecialFunctions", "Test", "Unicode"] git-tree-sha1 = "2284cb18c8670fd5c57ad010ce9bd4e2901692d2" uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" version = "1.8.2" -[[MathProgBase]] +[[deps.MathProgBase]] deps = ["LinearAlgebra", "SparseArrays"] git-tree-sha1 = "9abbe463a1e9fc507f12a69e7f29346c2cdc472c" uuid = "fdba3010-5040-5b88-9595-932c9decdf73" version = "0.7.8" -[[MathTeXEngine]] +[[deps.MathTeXEngine]] deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "Test", "UnicodeFun"] git-tree-sha1 = "7f837e1884f1ef84984c919fc7a00638cff1e6d1" uuid = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" version = "0.5.3" -[[MbedTLS_jll]] +[[deps.MbedTLS_jll]] deps = ["Artifacts", "Libdl"] uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" version = "2.28.0+0" -[[MiniQhull]] +[[deps.MiniQhull]] deps = ["QhullMiniWrapper_jll"] git-tree-sha1 = "9dc837d180ee49eeb7c8b77bb1c860452634b0d1" uuid = "978d7f02-9e05-4691-894f-ae31a51d76ca" version = "0.4.0" -[[Missings]] +[[deps.Missings]] deps = ["DataAPI"] git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" version = "1.0.2" -[[MixedModels]] -deps = ["Arrow", "DataAPI", "Distributions", "GLM", "JSON3", "LazyArtifacts", "LinearAlgebra", "Markdown", "NLopt", "PooledArrays", "ProgressMeter", "Random", "SparseArrays", "StaticArrays", "Statistics", "StatsAPI", "StatsBase", "StatsFuns", "StatsModels", "StructTypes", "Tables"] -git-tree-sha1 = "31538466936a03a860d192d8db7bd1edb2179a91" +[[deps.MixedModels]] +deps = ["Arrow", "DataAPI", "Distributions", "GLM", "JSON3", "LazyArtifacts", "LinearAlgebra", "Markdown", "NLopt", "PooledArrays", "ProgressMeter", "Random", "SnoopPrecompile", "SparseArrays", "StaticArrays", "Statistics", "StatsAPI", "StatsBase", "StatsFuns", "StatsModels", "StructTypes", "Tables"] +path = "../.." uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" -version = "4.8.0" +version = "4.9.0" -[[MixedModelsMakie]] +[[deps.MixedModelsMakie]] deps = ["DataFrames", "Distributions", "KernelDensity", "LinearAlgebra", "Makie", "MixedModels", "Printf", "SpecialFunctions", "StatsBase"] git-tree-sha1 = "adb722b6cc9f61731f7835b967ce683ea366b1f5" uuid = "b12ae82c-6730-437f-aff9-d2c38332a376" version = "0.3.17" -[[Mmap]] +[[deps.Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" -[[Mocking]] +[[deps.Mocking]] deps = ["ExprTools"] git-tree-sha1 = "748f6e1e4de814b101911e64cc12d83a6af66782" uuid = "78c3b35d-d492-501b-9361-3d52fe80e533" version = "0.7.2" -[[MosaicViews]] +[[deps.MosaicViews]] deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"] git-tree-sha1 = "b34e3bc3ca7c94914418637cb10cc4d1d80d877d" uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389" version = "0.3.3" -[[MozillaCACerts_jll]] +[[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" version = "2022.2.1" -[[MutableArithmetics]] +[[deps.MutableArithmetics]] deps = ["LinearAlgebra", "SparseArrays", "Test"] git-tree-sha1 = "4e675d6e9ec02061800d6cfb695812becbd03cdf" uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" version = "1.0.4" -[[NLopt]] +[[deps.NLopt]] deps = ["MathOptInterface", "MathProgBase", "NLopt_jll"] git-tree-sha1 = "5a7e32c569200a8a03c3d55d286254b0321cd262" uuid = "76087f3c-5699-56af-9a33-bf431cd00edd" version = "0.6.5" -[[NLopt_jll]] +[[deps.NLopt_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "9b1f15a08f9d00cdb2761dcfa6f453f5d0d6f973" uuid = "079eb43e-fd8e-5478-9966-2cf3e3edb778" version = "2.7.1+0" -[[NaNMath]] +[[deps.NaNMath]] deps = ["OpenLibm_jll"] git-tree-sha1 = "a7c3d1da1189a1c2fe843a3bfa04d18d20eb3211" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" version = "1.0.1" -[[Netpbm]] +[[deps.Netpbm]] deps = ["FileIO", "ImageCore"] git-tree-sha1 = "18efc06f6ec36a8b801b23f076e3c6ac7c3bf153" uuid = "f09324ee-3d7c-5217-9330-fc30815ba969" version = "1.0.2" -[[NetworkOptions]] +[[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" version = "1.2.0" -[[Observables]] +[[deps.Observables]] git-tree-sha1 = "5a9ea4b9430d511980c01e9f7173739595bbd335" uuid = "510215fc-4207-5dde-b226-833fc4488ee2" version = "0.5.2" -[[OffsetArrays]] +[[deps.OffsetArrays]] deps = ["Adapt"] git-tree-sha1 = "f71d8950b724e9ff6110fc948dff5a329f901d64" uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" version = "1.12.8" -[[Ogg_jll]] +[[deps.Ogg_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" version = "1.3.5+1" -[[OpenBLAS_jll]] +[[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" version = "0.3.20+0" -[[OpenEXR]] +[[deps.OpenEXR]] deps = ["Colors", "FileIO", "OpenEXR_jll"] git-tree-sha1 = "327f53360fdb54df7ecd01e96ef1983536d1e633" uuid = "52e1d378-f018-4a11-a4be-720524705ac7" version = "0.3.2" -[[OpenEXR_jll]] +[[deps.OpenEXR_jll]] deps = ["Artifacts", "Imath_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] git-tree-sha1 = "923319661e9a22712f24596ce81c54fc0366f304" uuid = "18a262bb-aa17-5467-a713-aee519bc75cb" version = "3.1.1+0" -[[OpenLibm_jll]] +[[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" version = "0.8.1+0" -[[OpenSSL_jll]] +[[deps.OpenSSL_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "e60321e3f2616584ff98f0a4f18d98ae6f89bbb3" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" version = "1.1.17+0" -[[OpenSpecFun_jll]] +[[deps.OpenSpecFun_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" version = "0.5.5+0" -[[Opus_jll]] +[[deps.Opus_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" uuid = "91d4177d-7536-5919-b921-800302f37372" version = "1.3.2+0" -[[OrderedCollections]] +[[deps.OrderedCollections]] git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.4.1" -[[PCRE2_jll]] +[[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" version = "10.40.0+0" -[[PDMats]] +[[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] git-tree-sha1 = "cf494dca75a69712a72b80bc48f59dcf3dea63ec" uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" version = "0.11.16" -[[PNGFiles]] +[[deps.PNGFiles]] deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"] git-tree-sha1 = "f809158b27eba0c18c269cf2a2be6ed751d3e81d" uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883" version = "0.3.17" -[[Packing]] +[[deps.Packing]] deps = ["GeometryBasics"] git-tree-sha1 = "1155f6f937fa2b94104162f01fa400e192e4272f" uuid = "19eb6ba3-879d-56ad-ad62-d5c202156566" version = "0.4.2" -[[PaddedViews]] +[[deps.PaddedViews]] deps = ["OffsetArrays"] git-tree-sha1 = "03a7a85b76381a3d04c7a1656039197e70eda03d" uuid = "5432bcbf-9aad-5242-b902-cca2824c8663" version = "0.5.11" -[[Pango_jll]] +[[deps.Pango_jll]] deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "84a314e3926ba9ec66ac097e3635e270986b0f10" uuid = "36c8627f-9965-5494-a995-c6b170f724f3" version = "1.50.9+0" -[[Parsers]] +[[deps.Parsers]] deps = ["Dates"] git-tree-sha1 = "3d5bf43e3e8b412656404ed9466f1dcbf7c50269" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" version = "2.4.0" -[[Pixman_jll]] +[[deps.Pixman_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" uuid = "30392449-352a-5448-841d-b1acce4e97dc" version = "0.40.1+0" -[[Pkg]] +[[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" version = "1.8.0" -[[PkgVersion]] +[[deps.PkgVersion]] deps = ["Pkg"] git-tree-sha1 = "f6cf8e7944e50901594838951729a1861e668cb8" uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688" version = "0.3.2" -[[PlotUtils]] +[[deps.PlotUtils]] deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "SnoopPrecompile", "Statistics"] git-tree-sha1 = "21303256d239f6b484977314674aef4bb1fe4420" uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" version = "1.3.1" -[[PolygonOps]] +[[deps.PolygonOps]] git-tree-sha1 = "77b3d3605fc1cd0b42d95eba87dfcd2bf67d5ff6" uuid = "647866c9-e3ac-4575-94e7-e3d426903924" version = "0.1.2" -[[PooledArrays]] +[[deps.PooledArrays]] deps = ["DataAPI", "Future"] git-tree-sha1 = "a6062fe4063cdafe78f4a0a81cfffb89721b30e7" uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" version = "1.4.2" -[[Preferences]] +[[deps.Preferences]] deps = ["TOML"] git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d" uuid = "21216c6a-2e73-6563-6e65-726566657250" version = "1.3.0" -[[PrettyTables]] +[[deps.PrettyTables]] deps = ["Crayons", "Formatting", "Markdown", "Reexport", "StringManipulation", "Tables"] git-tree-sha1 = "460d9e154365e058c4d886f6f7d6df5ffa1ea80e" uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" version = "2.1.2" -[[Printf]] +[[deps.Printf]] deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" -[[Profile]] +[[deps.Profile]] deps = ["Printf"] uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" -[[ProgressMeter]] +[[deps.ProgressMeter]] deps = ["Distributed", "Printf"] git-tree-sha1 = "d7a7aef8f8f2d537104f170139553b14dfe39fe9" uuid = "92933f4c-e287-5a05-a399-4b506db050ca" version = "1.7.2" -[[QOI]] +[[deps.QOI]] deps = ["ColorTypes", "FileIO", "FixedPointNumbers"] git-tree-sha1 = "18e8f4d1426e965c7b532ddd260599e1510d26ce" uuid = "4b34888f-f399-49d4-9bb3-47ed5cae4e65" version = "1.0.0" -[[QhullMiniWrapper_jll]] +[[deps.QhullMiniWrapper_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Qhull_jll"] git-tree-sha1 = "607cf73c03f8a9f83b36db0b86a3a9c14179621f" uuid = "460c41e3-6112-5d7f-b78c-b6823adb3f2d" version = "1.0.0+1" -[[Qhull_jll]] +[[deps.Qhull_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "695c3049ad94fa38b7f1e8243cdcee27ecad0867" uuid = "784f63db-0788-585a-bace-daefebcd302b" version = "8.0.1000+0" -[[QuadGK]] +[[deps.QuadGK]] deps = ["DataStructures", "LinearAlgebra"] git-tree-sha1 = "3c009334f45dfd546a16a57960a821a1a023d241" uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" version = "2.5.0" -[[REPL]] +[[deps.REPL]] deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" -[[Random]] +[[deps.Random]] deps = ["SHA", "Serialization"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -[[Ratios]] +[[deps.Ratios]] deps = ["Requires"] git-tree-sha1 = "dc84268fe0e3335a62e315a3a7cf2afa7178a734" uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" version = "0.4.3" -[[RecipesBase]] +[[deps.RecipesBase]] deps = ["SnoopPrecompile"] git-tree-sha1 = "612a4d76ad98e9722c8ba387614539155a59e30c" uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" version = "1.3.0" -[[Reexport]] +[[deps.Reexport]] git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" uuid = "189a3867-3050-52da-a836-e630ba90ab69" version = "1.2.2" -[[RelocatableFolders]] +[[deps.RelocatableFolders]] deps = ["SHA", "Scratch"] git-tree-sha1 = "90bc7a7c96410424509e4263e277e43250c05691" uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" version = "1.0.0" -[[Requires]] +[[deps.Requires]] deps = ["UUIDs"] git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" uuid = "ae029012-a4dd-5104-9daa-d747884805df" version = "1.3.0" -[[Rmath]] +[[deps.Rmath]] deps = ["Random", "Rmath_jll"] git-tree-sha1 = "bf3188feca147ce108c76ad82c2792c57abe7b1f" uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" version = "0.7.0" -[[Rmath_jll]] +[[deps.Rmath_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "68db32dff12bb6127bac73c209881191bf0efbb7" uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" version = "0.3.0+0" -[[SHA]] +[[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" version = "0.7.0" -[[SIMD]] +[[deps.SIMD]] git-tree-sha1 = "7dbc15af7ed5f751a82bf3ed37757adf76c32402" uuid = "fdea26ae-647d-5447-a871-4b548cad5224" version = "3.4.1" -[[ScanByte]] +[[deps.ScanByte]] deps = ["Libdl", "SIMD"] git-tree-sha1 = "2436b15f376005e8790e318329560dcc67188e84" uuid = "7b38b023-a4d7-4c5e-8d43-3f3097f304eb" version = "0.3.3" -[[Scratch]] +[[deps.Scratch]] deps = ["Dates"] git-tree-sha1 = "f94f779c94e58bf9ea243e77a37e16d9de9126bd" uuid = "6c6a2e73-6563-6170-7368-637461726353" version = "1.1.1" -[[SentinelArrays]] +[[deps.SentinelArrays]] deps = ["Dates", "Random"] git-tree-sha1 = "c0f56940fc967f3d5efed58ba829747af5f8b586" uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" version = "1.3.15" -[[Serialization]] +[[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" -[[SharedArrays]] +[[deps.SharedArrays]] deps = ["Distributed", "Mmap", "Random", "Serialization"] uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" -[[ShiftedArrays]] +[[deps.ShiftedArrays]] git-tree-sha1 = "503688b59397b3307443af35cd953a13e8005c16" uuid = "1277b4bf-5013-50f5-be3d-901d8477a67a" version = "2.0.0" -[[Showoff]] +[[deps.Showoff]] deps = ["Dates", "Grisu"] git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" version = "1.0.3" -[[SignedDistanceFields]] +[[deps.SignedDistanceFields]] deps = ["Random", "Statistics", "Test"] git-tree-sha1 = "d263a08ec505853a5ff1c1ebde2070419e3f28e9" uuid = "73760f76-fbc4-59ce-8f25-708e95d2df96" version = "0.4.0" -[[Sixel]] +[[deps.Sixel]] deps = ["Dates", "FileIO", "ImageCore", "IndirectArrays", "OffsetArrays", "REPL", "libsixel_jll"] git-tree-sha1 = "8fb59825be681d451c246a795117f317ecbcaa28" uuid = "45858cf5-a6b0-47a3-bbea-62219f50df47" version = "0.1.2" -[[SnoopPrecompile]] +[[deps.SnoopPrecompile]] git-tree-sha1 = "f604441450a3c0569830946e5b33b78c928e1a85" uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" version = "1.0.1" -[[Sockets]] +[[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" -[[SortingAlgorithms]] +[[deps.SortingAlgorithms]] deps = ["DataStructures"] git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" version = "1.0.1" -[[SparseArrays]] +[[deps.SparseArrays]] deps = ["LinearAlgebra", "Random"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -[[SpecialFunctions]] +[[deps.SpecialFunctions]] deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] git-tree-sha1 = "d75bda01f8c31ebb72df80a46c88b25d1c79c56d" uuid = "276daf66-3868-5448-9aa4-cd146d93841b" version = "2.1.7" -[[StackViews]] +[[deps.StackViews]] deps = ["OffsetArrays"] git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c" uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15" version = "0.1.1" -[[StaticArrays]] +[[deps.StaticArrays]] deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] git-tree-sha1 = "f86b3a049e5d05227b10e15dbb315c5b90f14988" uuid = "90137ffa-7385-5640-81b9-e52037218182" version = "1.5.9" -[[StaticArraysCore]] +[[deps.StaticArraysCore]] git-tree-sha1 = "6b7ba252635a5eff6a0b0664a41ee140a1c9e72a" uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" version = "1.4.0" -[[Statistics]] +[[deps.Statistics]] deps = ["LinearAlgebra", "SparseArrays"] uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -[[StatsAPI]] +[[deps.StatsAPI]] deps = ["LinearAlgebra"] git-tree-sha1 = "f9af7f195fb13589dd2e2d57fdb401717d2eb1f6" uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" version = "1.5.0" -[[StatsBase]] +[[deps.StatsBase]] deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] git-tree-sha1 = "d1bf48bfcc554a3761a133fe3a9bb01488e06916" uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" version = "0.33.21" -[[StatsFuns]] +[[deps.StatsFuns]] deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] git-tree-sha1 = "5783b877201a82fc0014cbf381e7e6eb130473a4" uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" version = "1.0.1" -[[StatsModels]] +[[deps.StatsModels]] deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Printf", "REPL", "ShiftedArrays", "SparseArrays", "StatsBase", "StatsFuns", "Tables"] git-tree-sha1 = "a5e15f27abd2692ccb61a99e0854dfb7d48017db" uuid = "3eaba693-59b7-5ba5-a881-562e759f1c8d" version = "0.6.33" -[[StringManipulation]] +[[deps.StringManipulation]] git-tree-sha1 = "46da2434b41f41ac3594ee9816ce5541c6096123" uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" version = "0.3.0" -[[StructArrays]] +[[deps.StructArrays]] deps = ["Adapt", "DataAPI", "StaticArraysCore", "Tables"] git-tree-sha1 = "8c6ac65ec9ab781af05b08ff305ddc727c25f680" uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" version = "0.6.12" -[[StructTypes]] +[[deps.StructTypes]] deps = ["Dates", "UUIDs"] git-tree-sha1 = "ca4bccb03acf9faaf4137a9abc1881ed1841aa70" uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" version = "1.10.0" -[[SuiteSparse]] +[[deps.SuiteSparse]] deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" -[[TOML]] +[[deps.TOML]] deps = ["Dates"] uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" version = "1.0.0" -[[TableTraits]] +[[deps.TableTraits]] deps = ["IteratorInterfaceExtensions"] git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" version = "1.0.1" -[[Tables]] +[[deps.Tables]] deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits", "Test"] git-tree-sha1 = "2d7164f7b8a066bcfa6224e67736ce0eb54aef5b" uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" version = "1.9.0" -[[Tar]] +[[deps.Tar]] deps = ["ArgTools", "SHA"] uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" version = "1.10.1" -[[TensorCore]] +[[deps.TensorCore]] deps = ["LinearAlgebra"] git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" version = "0.1.1" -[[Test]] +[[deps.Test]] deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -[[TiffImages]] +[[deps.TiffImages]] deps = ["ColorTypes", "DataStructures", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "Mmap", "OffsetArrays", "PkgVersion", "ProgressMeter", "UUIDs"] git-tree-sha1 = "70e6d2da9210371c927176cb7a56d41ef1260db7" uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69" version = "0.6.1" -[[TimeZones]] +[[deps.TimeZones]] deps = ["Dates", "Downloads", "InlineStrings", "LazyArtifacts", "Mocking", "Printf", "RecipesBase", "Scratch", "Unicode"] git-tree-sha1 = "d634a3641062c040fc8a7e2a3ea17661cc159688" uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53" version = "1.9.0" -[[TranscodingStreams]] +[[deps.TranscodingStreams]] deps = ["Random", "Test"] git-tree-sha1 = "8a75929dcd3c38611db2f8d08546decb514fcadf" uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" version = "0.9.9" -[[TriplotBase]] +[[deps.TriplotBase]] git-tree-sha1 = "4d4ed7f294cda19382ff7de4c137d24d16adc89b" uuid = "981d1d27-644d-49a2-9326-4793e63143c3" version = "0.1.0" -[[UUIDs]] +[[deps.UUIDs]] deps = ["Random", "SHA"] uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" -[[Unicode]] +[[deps.Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" -[[UnicodeFun]] +[[deps.UnicodeFun]] deps = ["REPL"] git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" version = "0.4.1" -[[WeakRefStrings]] +[[deps.WeakRefStrings]] deps = ["DataAPI", "InlineStrings", "Parsers"] git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" version = "1.4.2" -[[WoodburyMatrices]] +[[deps.WoodburyMatrices]] deps = ["LinearAlgebra", "SparseArrays"] git-tree-sha1 = "de67fa59e33ad156a590055375a30b23c40299d3" uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" version = "0.5.5" -[[XML2_jll]] +[[deps.XML2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] git-tree-sha1 = "58443b63fb7e465a8a7210828c91c08b92132dff" uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" version = "2.9.14+0" -[[XSLT_jll]] +[[deps.XSLT_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" uuid = "aed1982a-8fda-507f-9586-7b0439959a61" version = "1.1.34+0" -[[Xorg_libX11_jll]] +[[deps.Xorg_libX11_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" version = "1.6.9+4" -[[Xorg_libXau_jll]] +[[deps.Xorg_libXau_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" version = "1.0.9+4" -[[Xorg_libXdmcp_jll]] +[[deps.Xorg_libXdmcp_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" version = "1.1.3+4" -[[Xorg_libXext_jll]] +[[deps.Xorg_libXext_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" version = "1.3.4+4" -[[Xorg_libXrender_jll]] +[[deps.Xorg_libXrender_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" version = "0.9.10+4" -[[Xorg_libpthread_stubs_jll]] +[[deps.Xorg_libpthread_stubs_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" version = "0.1.0+3" -[[Xorg_libxcb_jll]] +[[deps.Xorg_libxcb_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" version = "1.13.0+3" -[[Xorg_xtrans_jll]] +[[deps.Xorg_xtrans_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" version = "1.4.0+3" -[[Zlib_jll]] +[[deps.Zlib_jll]] deps = ["Libdl"] uuid = "83775a58-1f1d-513f-b197-d71354ab007a" version = "1.2.12+3" -[[Zstd_jll]] +[[deps.Zstd_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "e45044cd873ded54b6a5bac0eb5c971392cf1927" uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" version = "1.5.2+0" -[[isoband_jll]] +[[deps.isoband_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "51b5eeb3f98367157a7a12a1fb0aa5328946c03c" uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4" version = "0.2.3+0" -[[libaom_jll]] +[[deps.libaom_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4" uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" version = "3.4.0+0" -[[libass_jll]] +[[deps.libass_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" version = "0.15.1+0" -[[libblastrampoline_jll]] +[[deps.libblastrampoline_jll]] deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" version = "5.1.1+0" -[[libfdk_aac_jll]] +[[deps.libfdk_aac_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" version = "2.0.2+0" -[[libpng_jll]] +[[deps.libpng_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" version = "1.6.38+0" -[[libsixel_jll]] +[[deps.libsixel_jll]] deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "libpng_jll"] git-tree-sha1 = "d4f63314c8aa1e48cd22aa0c17ed76cd1ae48c3c" uuid = "075b6546-f08a-558a-be8f-8157d0f608a5" version = "1.10.3+0" -[[libvorbis_jll]] +[[deps.libvorbis_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" version = "1.3.7+1" -[[nghttp2_jll]] +[[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" version = "1.48.0+0" -[[p7zip_jll]] +[[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" version = "17.4.0+0" -[[x264_jll]] +[[deps.x264_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" version = "2021.5.5+0" -[[x265_jll]] +[[deps.x265_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" diff --git a/issues/638/main.jl b/issues/638/main.jl index 61ea6c682..55bc5ba0b 100644 --- a/issues/638/main.jl +++ b/issues/638/main.jl @@ -17,6 +17,7 @@ model_form = @formula(y ~ v1 + v2 + v3 + v4 + v5 + wts = data[!, :w] contrasts = Dict(:pl3 => Grouping(), :pl5 => Grouping()); # contrasts = Dict(:pl3 => DummyCoding(), :pl5 => DummyCoding()); +fit(MixedModel, model_form, data; wts, contrasts, amalgamate=false) lm(@formula(y ~ v1 + v2 + v3 + v4 + v5), data; wts) # y ~ 1 + v1 + v2 + v3 + v4 + v5 @@ -191,3 +192,7 @@ m_form_split = let f = @formula(y ~ v1 + v2 + v3 + v4 + v5 + ((0 + v5) | pl5e)) fit(MixedModel, f, data; wts, contrasts) end + +# test new kwarg + +fit(MixedModel, model_form, data; wts, contrasts, amalgamate=false) diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index d1612b2ad..01d0b94ef 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -181,10 +181,12 @@ function StatsAPI.fit( wts=[], contrasts=Dict{Symbol,Any}(), offset=[], + amalgamate=true, kwargs..., ) return fit!( - GeneralizedLinearMixedModel(f, tbl, d, l; wts, offset, contrasts); kwargs... + GeneralizedLinearMixedModel(f, tbl, d, l; wts, offset, contrasts, amalgamate); + kwargs..., ) end @@ -334,9 +336,10 @@ function GeneralizedLinearMixedModel( wts=[], offset=[], contrasts=Dict{Symbol,Any}(), + amalgamate=true, ) return GeneralizedLinearMixedModel( - f, Tables.columntable(tbl), d, l; wts=wts, offset=offset, contrasts=contrasts + f, Tables.columntable(tbl), d, l; wts, offset, contrasts, amalgamate ) end @@ -345,9 +348,7 @@ function GeneralizedLinearMixedModel( tbl::Tables.ColumnTable, d::Normal, l::IdentityLink; - wts=[], - offset=[], - contrasts=Dict{Symbol,Any}(), + kwargs... ) return throw( ArgumentError("use LinearMixedModel for Normal distribution with IdentityLink") @@ -362,6 +363,7 @@ function GeneralizedLinearMixedModel( wts=[], offset=[], contrasts=Dict{Symbol,Any}(), + amalgamate=true, ) if isa(d, Binomial) && isempty(wts) d = Bernoulli() @@ -376,7 +378,7 @@ function GeneralizedLinearMixedModel( the authors gain a better understanding of those cases.""" end - LMM = LinearMixedModel(f, tbl; contrasts=contrasts, wts=wts) + LMM = LinearMixedModel(f, tbl; contrasts, wts, amalgamate) y = copy(LMM.y) constresponse = all(==(first(y)), y) # the sqrtwts field must be the correct length and type but we don't know those diff --git a/src/linalg/rankUpdate.jl b/src/linalg/rankUpdate.jl index e12662323..1d215cb17 100644 --- a/src/linalg/rankUpdate.jl +++ b/src/linalg/rankUpdate.jl @@ -16,6 +16,17 @@ function rankUpdate!(C::AbstractMatrix, a::AbstractArray, α, β) ) end +function MixedModels.rankUpdate!( + C::Hermitian{T,Diagonal{T,Vector{T}}}, A::Diagonal{T,Vector{T}}, α, β +) where {T} + Cdiag = C.data.diag + Adiag = A.diag + @inbounds for idx in eachindex(Cdiag, Adiag) + Cdiag[idx] = β * Cdiag[idx] + α * abs2(Adiag[idx]) + end + return C +end + function rankUpdate!(C::HermOrSym{T,S}, a::StridedVector{T}, α, β) where {T,S} Cd = C.data isone(β) || rmul!(C.uplo == 'L' ? LowerTriangular(Cd) : UpperTriangular(Cd), β) diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index c06f607fc..3548ab780 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -42,16 +42,20 @@ struct LinearMixedModel{T<:AbstractFloat} <: MixedModel{T} end function LinearMixedModel( - f::FormulaTerm, tbl; contrasts=Dict{Symbol,Any}(), wts=[], σ=nothing + f::FormulaTerm, tbl; contrasts=Dict{Symbol,Any}(), wts=[], σ=nothing, amalgamate=true ) - return LinearMixedModel(f::FormulaTerm, Tables.columntable(tbl); contrasts, wts, σ) + return LinearMixedModel( + f::FormulaTerm, Tables.columntable(tbl); contrasts, wts, σ, amalgamate + ) end + const _MISSING_RE_ERROR = ArgumentError( "Formula contains no random effects; this isn't a mixed model. Perhaps you want to use GLM.jl?", ) function LinearMixedModel( - f::FormulaTerm, tbl::Tables.ColumnTable; contrasts=Dict{Symbol,Any}(), wts=[], σ=nothing + f::FormulaTerm, tbl::Tables.ColumnTable; contrasts=Dict{Symbol,Any}(), wts=[], + σ=nothing, amalgamate=true, ) # TODO: perform missing_omit() after apply_schema() when improved # missing support is in a StatsModels release @@ -74,11 +78,11 @@ function LinearMixedModel( y, Xs = modelcols(form, tbl) - return LinearMixedModel(y, Xs, form, wts, σ) + return LinearMixedModel(y, Xs, form, wts, σ, amalgamate) end """ - LinearMixedModel(y, Xs, form, wts=[], σ=nothing) + LinearMixedModel(y, Xs, form, wts=[], σ=nothing, amalgamate=true) Private constructor for a LinearMixedModel. @@ -96,6 +100,7 @@ function LinearMixedModel( form::FormulaTerm, wts=[], σ=nothing, + amalgamate=true, ) T = promote_type(Float64, float(eltype(y))) # ensure eltype of model matrices is at least Float64 @@ -128,11 +133,13 @@ function LinearMixedModel( end end isempty(reterms) && throw(_MISSING_RE_ERROR) - return LinearMixedModel(convert(Array{T}, y), only(feterms), reterms, form, wts, σ) + return LinearMixedModel( + convert(Array{T}, y), only(feterms), reterms, form, wts, σ, amalgamate + ) end """ - LinearMixedModel(y, feterm, reterms, form, wts=[], σ=nothing) + LinearMixedModel(y, feterm, reterms, form, wts=[], σ=nothing; amalgamate=true) Private constructor for a `LinearMixedModel` given already assembled fixed and random effects. @@ -152,10 +159,13 @@ function LinearMixedModel( form::FormulaTerm, wts=[], σ=nothing, + amalgamate=true, ) where {T} # detect and combine RE terms with the same grouping var - if length(reterms) > 1 - reterms = amalgamate(reterms) + if length(reterms) > 1 && amalgamate + # okay, this looks weird, but it allows us to have the kwarg with the same name + # as the internal function + reterms = MixedModels.amalgamate(reterms) end sort!(reterms; by=nranef, rev=true) @@ -187,23 +197,13 @@ function StatsAPI.fit( ::Type{LinearMixedModel}, f::FormulaTerm, tbl; - wts=[], - contrasts=Dict{Symbol,Any}(), - progress::Bool=true, - REML::Bool=false, - σ=nothing, - thin=typemax(Int), + kwargs..., ) return fit( LinearMixedModel, f, Tables.columntable(tbl); - wts, - contrasts, - progress, - REML, - σ, - thin, + kwargs..., ) end @@ -217,8 +217,11 @@ function StatsAPI.fit( REML=false, σ=nothing, thin=typemax(Int), + amalgamate=true, ) - return fit!(LinearMixedModel(f, tbl; contrasts, wts, σ); progress, REML, thin) + return fit!( + LinearMixedModel(f, tbl; contrasts, wts, σ, amalgamate); progress, REML, thin + ) end function _offseterr() @@ -233,18 +236,13 @@ function StatsAPI.fit( ::Type{MixedModel}, f::FormulaTerm, tbl; - wts=[], - contrasts=Dict{Symbol,Any}(), - progress::Bool=true, - REML::Bool=false, offset=[], - σ=nothing, - thin=typemax(Int), + kwargs..., ) return if !isempty(offset) _offseterr() else - fit(LinearMixedModel, f, tbl; wts, contrasts, progress, REML, σ, thin) + fit(LinearMixedModel, f, tbl; kwargs...) end end @@ -254,15 +252,10 @@ function StatsAPI.fit( tbl, d::Normal, l::IdentityLink; - wts=[], - contrasts=Dict{Symbol,Any}(), - progress::Bool=true, - REML::Bool=false, offset=[], - σ=nothing, - thin=typemax(Int), fast=nothing, nAGQ=nothing, + kwargs..., ) return if !isempty(offset) _offseterr() @@ -270,7 +263,7 @@ function StatsAPI.fit( if !isnothing(fast) || !isnothing(nAGQ) @warn "fast and nAGQ arguments are ignored when fitting a LinearMixedModel" end - fit(LinearMixedModel, f, tbl; wts, contrasts, progress, REML, σ, thin) + fit(LinearMixedModel, f, tbl; kwargs...) end end @@ -356,7 +349,7 @@ end Return the conditional covariance matrices of the random effects as a `NamedTuple` of columntables """ function condVartables(m::MixedModel{T}) where {T} - return NamedTuple{fnames(m)}((map(_cvtbl, condVar(m), m.reterms)...,)) + return NamedTuple{_unique_fnames(m)}((map(_cvtbl, condVar(m), m.reterms)...,)) end """ @@ -609,6 +602,19 @@ Return the names of the grouping factors for the random-effects terms. """ fnames(m::MixedModel) = (fname.(m.reterms)...,) +function _unique_fnames(m::MixedModel) + fn = fnames(m) + ufn = unique(fn) + length(fn) == length(ufn) && return fn + fn = collect(fn) + d = Dict(ufn .=> 0) + for i in eachindex(fn) + (d[fn[i]] += 1) == 1 && continue + fn[i] = Symbol(string(fn[i], ".", d[fn[i]])) + end + return Tuple(fn) +end + """ getθ(m::LinearMixedModel) @@ -662,7 +668,7 @@ function Base.getproperty(m::LinearMixedModel{T}, s::Symbol) where {T} elseif s == :vcov vcov(m; corr=false) elseif s == :PCA - NamedTuple{fnames(m)}(PCA.(m.reterms)) + PCA(m) elseif s == :pvalues ccdf.(Chisq(1), abs2.(coef(m) ./ stderror(m))) elseif s == :stderror @@ -958,7 +964,7 @@ always 1.0 representing the complete proportion of the variance. """ function rePCA(m::LinearMixedModel; corr::Bool=true) pca = PCA.(m.reterms, corr=corr) - return NamedTuple{fnames(m)}(getproperty.(pca, :cumvar)) + return NamedTuple{_unique_fnames(m)}(getproperty.(pca, :cumvar)) end """ @@ -969,7 +975,7 @@ covariance matrices or correlation matrices when `corr` is `true`. """ function PCA(m::LinearMixedModel; corr::Bool=true) - return NamedTuple{fnames(m)}(PCA.(m.reterms, corr=corr)) + return NamedTuple{_unique_fnames(m)}(PCA.(m.reterms, corr=corr)) end """ diff --git a/src/mixedmodel.jl b/src/mixedmodel.jl index 475a39252..12054c07a 100644 --- a/src/mixedmodel.jl +++ b/src/mixedmodel.jl @@ -106,7 +106,9 @@ Return the conditional means of the random effects as a `NamedTuple` of Tables.j The API guarantee is only that the NamedTuple contains Tables.jl tables and not on the particular concrete type of each table. """ function raneftables(m::MixedModel{T}; uscale=false) where {T} - return NamedTuple{fnames(m)}((map(retbl, ranef(m; uscale=uscale), m.reterms)...,)) + return NamedTuple{_unique_fnames(m)}(( + map(retbl, ranef(m; uscale=uscale), m.reterms)..., + )) end StatsAPI.residuals(m::MixedModel) = response(m) .- fitted(m) @@ -129,12 +131,14 @@ end function σs(m::MixedModel) σ = dispersion(m) - return NamedTuple{fnames(m)}(((σs(t, σ) for t in m.reterms)...,)) + fn = _unique_fnames(m) + return NamedTuple{fn}(((σs(t, σ) for t in m.reterms)...,)) end function σρs(m::MixedModel) σ = dispersion(m) - return NamedTuple{fnames(m)}(((σρs(t, σ) for t in m.reterms)...,)) + fn = _unique_fnames(m) + return NamedTuple{fn}(((σρs(t, σ) for t in m.reterms)...,)) end """ diff --git a/src/remat.jl b/src/remat.jl index a86ed6262..7272e1c58 100644 --- a/src/remat.jl +++ b/src/remat.jl @@ -509,14 +509,17 @@ function reweight!(A::ReMat, sqrtwts::Vector) return A end -rmulΛ!(A::Matrix{T}, B::ReMat{T,1}) where {T} = rmul!(A, only(B.λ)) +# why nested where? force specialization to eliminate dynamic dispatch +function rmulΛ!(A::M, B::ReMat{T,1}) where {M<:Union{Diagonal{T},Matrix{T}}} where {T} + return rmul!(A, only(B.λ)) +end function rmulΛ!(A::SparseMatrixCSC{T}, B::ReMat{T,1}) where {T} rmul!(nonzeros(A), only(B.λ)) return A end -function rmulΛ!(A::Matrix{T}, B::ReMat{T,S}) where {T,S} +function rmulΛ!(A::M, B::ReMat{T,S}) where {M<:Union{Diagonal{T},Matrix{T}}} where {T,S} m, n = size(A) q, r = divrem(n, S) iszero(r) || throw(DimensionMismatch("size(A, 2) is not a multiple of block size")) diff --git a/test/pls.jl b/test/pls.jl index 2b2ab3928..19ec323eb 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -490,6 +490,17 @@ end @test λ isa Diagonal{Float64, Vector{Float64}} end + @testset "disable amalgamation" begin + fm_chunky = fit(MixedModel, + @formula(reaction ~ 1 + days + (1 | subj) + (0 + days | subj)), + dataset(:sleepstudy); amalgamate=false, progress=false) + + @test loglikelihood(fm_chunky) ≈ loglikelihood(models(:sleepstudy)[2]) + @test length(fm_chunky.reterms) == 2 + vc = sprint(show, VarCorr(fm_chunky)) + @test all(occursin(vc), ["subj", "subj.2"]) + end + show(io, BlockDescription(first(models(:sleepstudy)))) @test countlines(seekstart(io)) == 3 @test "Diagonal" in Set(split(String(take!(io)), r"\s+")) From c99a2d320795a14e0a37e582bda41b3b90185684 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 9 Aug 2023 14:30:10 +0000 Subject: [PATCH 46/51] More informative error messages (#698) * informative error message when passed type instead of instance * more informative error for R2 * NEWS * JuliaFormatter --- NEWS.md | 3 +++ src/generalizedlinearmixedmodel.jl | 20 +++++++++++++++ src/mixedmodel.jl | 40 ++++++++++++++++++++++++++++++ test/pirls.jl | 14 +++++++++++ test/pls.jl | 15 +++++++++++ 5 files changed, 92 insertions(+) diff --git a/NEWS.md b/NEWS.md index 7980035c7..67cbb1e66 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,6 @@ * New kwarg `amalgamate` can be used to disable amalgation of random0effects terms sharing a single grouping variable. Generally, `amalgamate=false` will result in a slower fit, but may improve convergence in some pathological cases. Note that this feature is experimental and changes to it are **not** considered breakin. [#673] +* More informative error messages when passing a `Distribution` or `Link` type instead of the desired instance. [#698] +* More informative error message on the intentional decision not to define methods for the coefficient of determination. [#698] MixedModels v4.16.0 Release Notes ============================== @@ -449,4 +451,5 @@ Package dependencies [#681]: https://github.com/JuliaStats/MixedModels.jl/issues/681 [#682]: https://github.com/JuliaStats/MixedModels.jl/issues/682 [#694]: https://github.com/JuliaStats/MixedModels.jl/issues/694 +[#698]: https://github.com/JuliaStats/MixedModels.jl/issues/698 [#703]: https://github.com/JuliaStats/MixedModels.jl/issues/703 diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index 01d0b94ef..dacefefc6 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -328,6 +328,26 @@ end StatsAPI.fitted(m::GeneralizedLinearMixedModel) = m.resp.mu +function GeneralizedLinearMixedModel( + f::FormulaTerm, + tbl, + d::Type, + args...; + kwargs..., +) + throw(ArgumentError("Expected a Distribution instance (`$d()`), got a type (`$d`).")) +end + +function GeneralizedLinearMixedModel( + f::FormulaTerm, + tbl, + d::Distribution, + l::Type; + kwargs... +) + throw(ArgumentError("Expected a Link instance (`$l()`), got a type (`$l`).")) +end + function GeneralizedLinearMixedModel( f::FormulaTerm, tbl, diff --git a/src/mixedmodel.jl b/src/mixedmodel.jl index 12054c07a..ff4e6c7c2 100644 --- a/src/mixedmodel.jl +++ b/src/mixedmodel.jl @@ -74,6 +74,28 @@ issingular(m::GeneralizedLinearMixedModel, θ=m.optsum.final) = any(lowerbd(m) . # FIXME: better to base this on m.optsum.returnvalue StatsAPI.isfitted(m::MixedModel) = m.optsum.feval > 0 +function StatsAPI.fit( + ::Type{<:MixedModel}, + f::FormulaTerm, + tbl, + d::Type, + args...; + kwargs... +) + throw(ArgumentError("Expected a Distribution instance (`$d()`), got a type (`$d`).")) +end + +function StatsAPI.fit( + ::Type{<:MixedModel}, + f::FormulaTerm, + tbl, + d::Distribution, + l::Type; + kwargs... +) + throw(ArgumentError("Expected a Link instance (`$l()`), got a type (`$l`).")) +end + StatsAPI.meanresponse(m::MixedModel) = mean(m.y) """ @@ -97,6 +119,24 @@ function retbl(mat, trm) ) end +StatsAPI.adjr2(m::MixedModel) = r2(m) + +function StatsAPI.r2(m::MixedModel) + @error ( + """There is no uniquely defined coefficient of determination for mixed models + that has all the properties of the corresponding value for classical + linear models. The GLMM FAQ provides more detail: + + https://bbolker.github.io/mixedmodels-misc/glmmFAQ.html#how-do-i-compute-a-coefficient-of-determination-r2-or-an-analogue-for-glmms + + + Alternatively, MixedModelsExtras provides a naive implementation, but + the warnings there and in the FAQ should be taken seriously! + """ + ) + throw(MethodError(r2, (m,))) +end + """ raneftables(m::MixedModel; uscale = false) diff --git a/test/pirls.jl b/test/pirls.jl index 77a70c4a6..b50f0fa1a 100644 --- a/test/pirls.jl +++ b/test/pirls.jl @@ -18,6 +18,20 @@ include("modelcache.jl") @test MixedModel(f, d, Bernoulli(), ProbitLink()) isa GeneralizedLinearMixedModel end +@testset "Type for instance" begin + vaform = @formula(r2 ~ 1 + anger + gender + btype + situ + (1|subj) + (1|item)) + verbagg = dataset(:verbagg) + @test_throws ArgumentError fit(MixedModel, vaform, verbagg, Bernoulli, LogitLink) + @test_throws ArgumentError fit(MixedModel, vaform, verbagg, Bernoulli(), LogitLink) + @test_throws ArgumentError fit(MixedModel, vaform, verbagg, Bernoulli, LogitLink()) + @test_throws ArgumentError fit(GeneralizedLinearMixedModel, vaform, verbagg, Bernoulli, LogitLink) + @test_throws ArgumentError fit(GeneralizedLinearMixedModel, vaform, verbagg, Bernoulli(), LogitLink) + @test_throws ArgumentError fit(GeneralizedLinearMixedModel, vaform, verbagg, Bernoulli, LogitLink()) + @test_throws ArgumentError GeneralizedLinearMixedModel(vaform, verbagg, Bernoulli, LogitLink) + @test_throws ArgumentError GeneralizedLinearMixedModel(vaform, verbagg, Bernoulli(), LogitLink) + @test_throws ArgumentError GeneralizedLinearMixedModel(vaform, verbagg, Bernoulli, LogitLink()) +end + @testset "contra" begin contra = dataset(:contra) thin = 5 diff --git a/test/pls.jl b/test/pls.jl index 19ec323eb..4902555e3 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -1,3 +1,4 @@ +using GLM # bring r2 into scope using LinearAlgebra using MixedModels using PooledArrays @@ -688,3 +689,17 @@ end # but this is surprisingly hard to trigger in a reliable way across platforms # just because of the vagaries of floating point. end + +@testset "methods we don't define" begin + m = first(models(:sleepstudy)) + for f in [r2, adjr2] + @test_logs (:error,) begin + try + f(m) + catch + # capture the error, do nothing + end + end + @test_throws MethodError @suppress f(m) + end +end From 4833c11a6b3077418b80384763c34cb758df5a84 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Wed, 9 Aug 2023 15:16:52 +0000 Subject: [PATCH 47/51] Recover from PIRLS failure by returning finitial (#616) * attempt rescaling of poorly scaled problems * recover from PIRLS failure by returning finitial * fix try-catch * catch DomainError * NEWS * version bump * try a different test --- NEWS.md | 5 ++++- Project.toml | 2 +- src/generalizedlinearmixedmodel.jl | 10 +++++++++- test/pirls.jl | 7 ++++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 67cbb1e66..c3019459f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,9 @@ +MixedModels v4.17.0 Release Notes +============================== * New kwarg `amalgamate` can be used to disable amalgation of random0effects terms sharing a single grouping variable. Generally, `amalgamate=false` will result in a slower fit, but may improve convergence in some pathological cases. Note that this feature is experimental and changes to it are **not** considered breakin. [#673] * More informative error messages when passing a `Distribution` or `Link` type instead of the desired instance. [#698] * More informative error message on the intentional decision not to define methods for the coefficient of determination. [#698] +* **EXPERIMENTAL** Return `finitial` when PIRLS drifts into a portion of the parameter space that yields a (numerically) invalid covariance matrix. This recovery strategy may be removed in a future release. [#616] MixedModels v4.16.0 Release Notes ============================== @@ -80,7 +83,6 @@ MixedModels v4.6.5 Release Notes * Attempt recovery when the initial parameter values lead to an invalid covariance matrix by rescaling [#615] * Return `finitial` when the optimizer drifts into a portion of the parameter space that yields a (numerically) invalid covariance matrix [#615] - MixedModels v4.6.4 Release Notes ======================== * Support transformed responses in `predict` [#614] @@ -431,6 +433,7 @@ Package dependencies [#608]: https://github.com/JuliaStats/MixedModels.jl/issues/608 [#614]: https://github.com/JuliaStats/MixedModels.jl/issues/614 [#615]: https://github.com/JuliaStats/MixedModels.jl/issues/615 +[#616]: https://github.com/JuliaStats/MixedModels.jl/issues/616 [#628]: https://github.com/JuliaStats/MixedModels.jl/issues/628 [#634]: https://github.com/JuliaStats/MixedModels.jl/issues/634 [#637]: https://github.com/JuliaStats/MixedModels.jl/issues/637 diff --git a/Project.toml b/Project.toml index 498deacd3..0aceb5fa4 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.16.0" +version = "4.17.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/generalizedlinearmixedmodel.jl b/src/generalizedlinearmixedmodel.jl index dacefefc6..568740f4e 100644 --- a/src/generalizedlinearmixedmodel.jl +++ b/src/generalizedlinearmixedmodel.jl @@ -284,7 +284,15 @@ function StatsAPI.fit!( fitlog = optsum.fitlog function obj(x, g) isempty(g) || throw(ArgumentError("g should be empty for this objective")) - val = deviance(pirls!(setpar!(m, x), fast, verbose), nAGQ) + val = try + deviance(pirls!(setpar!(m, x), fast, verbose), nAGQ) + catch ex + # this allows us to recover from models where e.g. the link isn't + # as constraining as it should be + ex isa Union{PosDefException,DomainError} || rethrow() + iter == 1 && rethrow() + m.optsum.finitial + end iszero(rem(iter, thin)) && push!(fitlog, (copy(x), val)) verbose && println(round(val; digits=5), " ", x) progress && ProgressMeter.next!(prog; showvalues=[(:objective, val)]) diff --git a/test/pirls.jl b/test/pirls.jl index b50f0fa1a..96a005033 100644 --- a/test/pirls.jl +++ b/test/pirls.jl @@ -162,7 +162,7 @@ end center(v::AbstractVector) = v .- (sum(v) / length(v)) grouseticks = DataFrame(dataset(:grouseticks)) grouseticks.ch = center(grouseticks.height) - gm4 = fit(MixedModel, only(gfms[:grouseticks]), grouseticks, Poisson(); fast=true, progress=false) # fails in pirls! with fast=false + gm4 = fit(MixedModel, only(gfms[:grouseticks]), grouseticks, Poisson(); fast=true, progress=false) @test isapprox(deviance(gm4), 851.4046, atol=0.001) # these two values are not well defined at the optimum #@test isapprox(sum(x -> sum(abs2, x), gm4.u), 196.8695297987013, atol=0.1) @@ -173,6 +173,11 @@ end @test sdest(gm4) === missing @test varest(gm4) === missing @test gm4.σ === missing + gm4slow = fit(MixedModel, only(gfms[:grouseticks]), grouseticks, Poisson(); fast=false, progress=false) + # this tolerance isn't great, but then again the optimum isn't well defined + # @test gm4.θ ≈ gm4slow.θ rtol=0.05 + # @test gm4.β[2:end] ≈ gm4slow.β[2:end] atol=0.1 + @test isapprox(deviance(gm4), deviance(gm4slow); rtol=0.1) end @testset "goldstein" begin # from a 2020-04-22 msg by Ben Goldstein to R-SIG-Mixed-Models From 563d465b3be2d19f79f188c7c81593ad2599da52 Mon Sep 17 00:00:00 2001 From: Likan Zhan Date: Thu, 10 Aug 2023 09:43:37 +0800 Subject: [PATCH 48/51] typos (#704) --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index c3019459f..871f45f46 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,6 @@ MixedModels v4.17.0 Release Notes ============================== -* New kwarg `amalgamate` can be used to disable amalgation of random0effects terms sharing a single grouping variable. Generally, `amalgamate=false` will result in a slower fit, but may improve convergence in some pathological cases. Note that this feature is experimental and changes to it are **not** considered breakin. [#673] +* New kwarg `amalgamate` can be used to disable amalgation of random effects terms sharing a single grouping variable. Generally, `amalgamate=false` will result in a slower fit, but may improve convergence in some pathological cases. Note that this feature is experimental and changes to it are **not** considered breakings. [#673] * More informative error messages when passing a `Distribution` or `Link` type instead of the desired instance. [#698] * More informative error message on the intentional decision not to define methods for the coefficient of determination. [#698] * **EXPERIMENTAL** Return `finitial` when PIRLS drifts into a portion of the parameter space that yields a (numerically) invalid covariance matrix. This recovery strategy may be removed in a future release. [#616] From c9dbaf633e54a41a2340ef5fbe4daf00095c9934 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Sun, 20 Aug 2023 12:29:09 +0000 Subject: [PATCH 49/51] better error when formula variables missing from dataset (#707) * better error when formula variables missing from dataset * NEWS and version bump * JuliaFormatter --- NEWS.md | 7 ++++++- Project.toml | 2 +- src/linearmixedmodel.jl | 15 ++++++++++++--- test/pls.jl | 7 +++++++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index 871f45f46..995d069ff 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,10 @@ +MixedModels v4.18.0 Release Notes +============================== +* More user-friendly error messages when a formula contains variables not in the data. [#707] + MixedModels v4.17.0 Release Notes ============================== -* New kwarg `amalgamate` can be used to disable amalgation of random effects terms sharing a single grouping variable. Generally, `amalgamate=false` will result in a slower fit, but may improve convergence in some pathological cases. Note that this feature is experimental and changes to it are **not** considered breakings. [#673] +* **EXPERIMENTAL** New kwarg `amalgamate` can be used to disable amalgation of random effects terms sharing a single grouping variable. Generally, `amalgamate=false` will result in a slower fit, but may improve convergence in some pathological cases. Note that this feature is experimental and changes to it are **not** considered breakings. [#673] * More informative error messages when passing a `Distribution` or `Link` type instead of the desired instance. [#698] * More informative error message on the intentional decision not to define methods for the coefficient of determination. [#698] * **EXPERIMENTAL** Return `finitial` when PIRLS drifts into a portion of the parameter space that yields a (numerically) invalid covariance matrix. This recovery strategy may be removed in a future release. [#616] @@ -456,3 +460,4 @@ Package dependencies [#694]: https://github.com/JuliaStats/MixedModels.jl/issues/694 [#698]: https://github.com/JuliaStats/MixedModels.jl/issues/698 [#703]: https://github.com/JuliaStats/MixedModels.jl/issues/703 +[#707]: https://github.com/JuliaStats/MixedModels.jl/issues/707 diff --git a/Project.toml b/Project.toml index 0aceb5fa4..e55fbdcec 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.17.0" +version = "4.18.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index 3548ab780..aeed811b2 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -57,6 +57,15 @@ function LinearMixedModel( f::FormulaTerm, tbl::Tables.ColumnTable; contrasts=Dict{Symbol,Any}(), wts=[], σ=nothing, amalgamate=true, ) + fvars = StatsModels.termvars(f) + tvars = Tables.columnnames(tbl) + fvars ⊆ tvars || + throw( + ArgumentError( + "The following formula variables are not present in the table: $(setdiff(fvars, tvars))", + ), + ) + # TODO: perform missing_omit() after apply_schema() when improved # missing support is in a StatsModels release tbl, _ = StatsModels.missing_omit(tbl, f) @@ -354,14 +363,14 @@ end """ confint(pr::MixedModelProfile; level::Real=0.95) - + Compute profile confidence intervals for (fixed effects) coefficients, with confidence level `level` (by default 95%). !!! note - The API guarantee is for a Tables.jl compatible table. The exact return type is an + The API guarantee is for a Tables.jl compatible table. The exact return type is an implementation detail and may change in a future minor release without being considered breaking. - + """ function StatsBase.confint(m::MixedModel{T}; level=0.95) where {T} cutoff = sqrt.(quantile(Chisq(1), level)) diff --git a/test/pls.jl b/test/pls.jl index 4902555e3..41e12a6ce 100644 --- a/test/pls.jl +++ b/test/pls.jl @@ -271,6 +271,13 @@ end lrt = likelihoodratiotest(models(:pastes)...) @test length(lrt.deviance) == length(lrt.formulas) == length(lrt.models )== 2 @test first(lrt.tests.pvalues) ≈ 0.5233767966395597 atol=0.0001 + + @testset "missing variables in formula" begin + ae = ArgumentError("The following formula variables are not present in the table: [:reaction, :joy, :subj]") + @test_throws(ae, + fit(MixedModel, @formula(reaction ~ 1 + joy + (1|subj)), dataset(:pastes))) + + end end @testset "InstEval" begin From 66ec87d9cf3933b565544f4e89ca5eb7d4037f39 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Sun, 20 Aug 2023 14:47:38 +0000 Subject: [PATCH 50/51] support for NLopt 1.0 (#706) * NLopt compat bump + patch bump --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e55fbdcec..3850bb42a 100644 --- a/Project.toml +++ b/Project.toml @@ -37,7 +37,7 @@ Distributions = "0.21, 0.22, 0.23, 0.24, 0.25" GLM = "1.8.2" JSON3 = "1" LazyArtifacts = "1" -NLopt = "0.5, 0.6" +NLopt = "0.6, 1" PooledArrays = "0.5, 1" PrecompileTools = "1" ProgressMeter = "1.7" From df203bcb531a7c460e58df007f184cf4d5ec0e0f Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Sun, 20 Aug 2023 16:54:29 +0000 Subject: [PATCH 51/51] Add `coefnames(::ReMat)` (#709) * remove unnecessary specialization * add a `coefnames` method for ReMat * minor version bump * NEWS --- NEWS.md | 5 +++++ Project.toml | 2 +- src/linearmixedmodel.jl | 2 +- src/remat.jl | 2 ++ test/FactorReTerm.jl | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 995d069ff..5e73643ba 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +MixedModels v4.19.0 Release Notes +============================== +* New method `StatsAPI.coefnames(::ReMat)` returns the coefficient names associated with each grouping factor. [#709] + MixedModels v4.18.0 Release Notes ============================== * More user-friendly error messages when a formula contains variables not in the data. [#707] @@ -461,3 +465,4 @@ Package dependencies [#698]: https://github.com/JuliaStats/MixedModels.jl/issues/698 [#703]: https://github.com/JuliaStats/MixedModels.jl/issues/703 [#707]: https://github.com/JuliaStats/MixedModels.jl/issues/707 +[#709]: https://github.com/JuliaStats/MixedModels.jl/issues/709 diff --git a/Project.toml b/Project.toml index 3850bb42a..03e2a20a7 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MixedModels" uuid = "ff71e718-51f3-5ec2-a782-8ffcbfa3c316" author = ["Phillip Alday ", "Douglas Bates ", "Jose Bayoan Santiago Calderon "] -version = "4.18.0" +version = "4.19.0" [deps] Arrow = "69666777-d1a9-59fb-9406-91d4454c9d45" diff --git a/src/linearmixedmodel.jl b/src/linearmixedmodel.jl index aeed811b2..caa26eddf 100644 --- a/src/linearmixedmodel.jl +++ b/src/linearmixedmodel.jl @@ -599,7 +599,7 @@ fixef(m::LinearMixedModel{T}) where {T} = fixef!(Vector{T}(undef, m.feterm.rank) Return a (permuted and truncated in the rank-deficient case) vector of coefficient names. """ -function fixefnames(m::LinearMixedModel{T}) where {T} +function fixefnames(m::LinearMixedModel) Xtrm = m.feterm return Xtrm.cnames[1:(Xtrm.rank)] end diff --git a/src/remat.jl b/src/remat.jl index 7272e1c58..993e3f0aa 100644 --- a/src/remat.jl +++ b/src/remat.jl @@ -116,6 +116,8 @@ nranef(A::ReMat) = size(A.adjA, 1) LinearAlgebra.cond(A::ReMat) = cond(A.λ) +StatsAPI.coefnames(re::MixedModels.AbstractReMat) = re.cnames + """ fname(A::ReMat) diff --git a/test/FactorReTerm.jl b/test/FactorReTerm.jl index 24a584c02..e6f437471 100644 --- a/test/FactorReTerm.jl +++ b/test/FactorReTerm.jl @@ -263,6 +263,7 @@ end m2r = fit(MixedModel, term(:strength) ~ term(1) + (term(1)|term(:batch)) + (term(1)|term(:batch)&term(:cask)), psts; progress=false) @test fnames(m) == fnames(m2) == fnames(m2r) == (Symbol("batch & cask"), :batch) + @test coefnames(first(m.reterms)) == ["(Intercept)"] @test m.λ == m2.λ == m2r.λ @test deviance(m) == deviance(m2) == deviance(m2r) end