Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@GregForkutza
Copy link
Collaborator

@GregForkutza GregForkutza commented Jul 24, 2025

Summary

Adds structured covariance support to lme4 with cs(), ar1(), and diag() syntax, matching glmmTMB functionality while maintaining lme4's Cholesky parameterization philosophy.

New Features

  • Compound Symmetry: cs(Days | Subject, hom = TRUE/FALSE)
  • Autoregressive AR1: ar1(Days | Subject, hom = TRUE/FALSE)
  • Diagonal: diag(Days | Subject, hom = TRUE/FALSE)
  • Backward Compatible: Existing syntax unchanged

Files Changed

Implementation:

  • R/covariance_structures.R - S4 covariance classes and methods
  • R/covariance-helpers.R - Utility functions and transformations
  • R/formula-dispatch.R - Formula parsing and S4 object creation
  • R/modular.R - Integration with lFormula pipeline
  • R/lmer.R - VarCorr system with structured covariance support - adds theta parameter truncation, bifurcated mkVarCorr processing (traditional vs S4 structure dispatch), and structured theta naming system (tnames).

Tests:

  • tests/testthat/test-covariance_structures.R - Comprehensive structure tests for S4 classes (current version is not valid).

Tasks

  • Ensure consistent Cholesky parameterization across all structures

    • Fix compute_lambdat_x method d
    • Fix compute_covariance_matrix method
    • Fix get_interpretable_parameters method
    • Fix get_start_values method
    • Fix compute_inverse_covariance_matrix method
  • Verify all testthat tests pass when running devtools::test(), temporarily skipping tests/testthat/test-covariance_structures.R.

  • Verify all tests pass when running devtools::check()

  • Covariance Structure Unit Testing & Validation

    • Implementation Phase
      • Diagonal Covariance Structures
        • Homogeneous Diagonal
        • Heterogeneous Diagonal
      • Unstructured Covariance
      • Compound Symmetry (CS) Structures
        • Homogeneous CS
        • Heterogeneous CS
      • AR1 Structures
        • Homogeneous AR1
        • Heterogeneous AR1
    • Validation Phase
      • Verify all covariance structure tests pass
      • Run full test suite with covariance tests enabled
  • Verify all tests pass when running devtools::check() with covariance structures tests not skipped

  • Verify GitHub Actions CI passes with [run ci]

  • VarCorr Methods (

    • Test VarCorr() extracts correct variance-covariance information
    • Implement structure-specific methods for CS, AR1, Diagonal, US if required.
    • Validate output matches glmmTMB equivalent structures
  • Add support for glmer()

  • Implement solution for cov struct information Issue #857

  • Validate covariance structure implementations against glmmTMB consistency check:

    • Diagonal (homogeneous/heterogeneous)
    • CS (homogeneous/heterogeneous) Issue #844
    • AR1 (homogeneous/heterogeneous) Issue #843
  • Documentation

    • User facing documentation
    • Developer Documentation
  • Fix devfun2 to handle profiling for structured covariances matrices Issue #858

  • Print/Show Methods

    • Test show() methods display correct parameter summaries
    • Verify output format is informative and consistent
  • Write integration tests

  • Ensure all computational methods are robust and efficient

    • Remove explicit chol() calls from compute_lambdat_x methods
    • Remove solve() call from compute_inverse_structured() helper
      • Write analytic inverse methods that dispatch on AR1, CS, and US structures
  • Add support for nlmer()

GregForkutza and others added 30 commits March 24, 2025 21:32
Merge remote flexSigma into local flexSigma
Merge branch 'master' into flexSigma
GregForkutza and others added 10 commits August 26, 2025 15:03
- Replace split pathway with unified S4 system to enable mixed formulas (e.g., cs(x|g) + ar1(y|g))
- Route mkLmerDevfun through mkdevfun to support theta parameter transformation
- Add compute_lambdat_x methods for optimizer-to-Cholesky parameter conversion
- Store structured covariance metadata in rho environment for deviance function access
- Fix UnstructuredCovariance start values to maintain lme4 compatibility
@bbolker
Copy link
Member

bbolker commented Oct 20, 2025

current status: latest tests and info about commits are in https://github.com/lme4/lme4/blob/flexSigma/misc/cs_tests.R

It looks like Lambdat as constructed by the new machinery is transposed from where it should be ... (the other difference is that the new code path has the values from theta inserted into Lambdat already, but I don't think that's a relevant difference ...)

Screenshot from 2025-10-20 17-51-13

@bbolker
Copy link
Member

bbolker commented Oct 21, 2025

correcting the transposition fixes a lot of problems but there are still test failures, beyond the tests that Greg introduced for his stuff (which we may want to skip temporarily) - may try to track these down tomorrow, hoping they may actually be minor.

@jaganmn
Copy link
Collaborator

jaganmn commented Oct 21, 2025

The Dyestuff example is currently failing because the method for generic function compute_correlation_matrix with signature c(object="UnstructuredCovariance") does cov2cor(V) for V of class dsyMatrix and the method for cov2cor in package Matrix tests that V is positive definite, signaling an error if not. The old unstructured code behaved more like the cov2cor in stats by coping with standard deviations equal to zero.

Maybe it is blasphemous for me to say, but I don't see a real benefit of using Matrix classes in covariance_structures.R and covariance-helpers.R.

@bbolker
Copy link
Member

bbolker commented Oct 21, 2025

I commented out some of Greg's tests, fixed others, took out the dsyMatrix stuff. We're down to two errors, one of which is a mismatch in matrix dimensions (which suggests a real problem with Lambdat construction), one of which is a slight change in results from previous reference values (which I would definitely like to understand but is not necessarily problematic — I believe the example is fairly numerically unstable)

@bbolker
Copy link
Member

bbolker commented Oct 22, 2025

I believe the test failure in test-methods.R:43 (evaluating fmPix <- lmer(pixel ~ day + I(day^2) + (day | Dog) + (1 | Side/Dog), data = Pixel)) is serious but fixable. mkReTrms reorders the random effects terms from largest to small number of levels of the grouping variable (in this case Dog:Side=20, Dog=10, Side = 2). The s4_object_list that mkReLambdat operates on has not been correspondingly re-ordered. (I know we had conversations with Greg about this ...).

(There was an apparently unnecessary/redundant re-ordering step which I've commented out for now, which un-breaks that test and doesn't appear to break anything else in devtools::test() ... will try next with R CMD check ...)

@jaganmn
Copy link
Collaborator

jaganmn commented Oct 22, 2025

Examples run OK now. Tests show 4 errors:

  • tests/testthat/test-methods.R: lmer->lFormula->mkReLambdat constructs Lambdat with wrong dimensions (52 instead of 42)
  • tests/testthat/test-summary.R: difference from reference value
  • tests/boundary.R: m5B@optinfo$derivs is now NULL
  • tests/priorWeights.R: difference from reference value

Oops - crossed up.

@bbolker
Copy link
Member

bbolker commented Oct 22, 2025

Hmm, I thought I fixed the first one just now. Pull and try again?

when running at test level 5 (export LME4_TEST_LEVEL=5), I get one example failure, in the confint.merMod examples ...

Computing profile confidence intervals ...
Warning in split.default(v, rep.int(seq_along(n), n * (n + 1)/2)) :
  data length is not a multiple of split variable
Warning in m0[lower.tri(m0, diag = TRUE)] <- x :
  number of items to replace is not a multiple of replacement length
Error in dd(opt[seq(npar1)]) : length(pars) == np is not TRUE
Calls: confint ... profile.merMod -> all.equal -> unname -> dd -> stopifnot

In addition to the test-summary reference value, I get a few problems in test-predict that are enabled at test level > 1:

══ Failed tests════════════════════════
── Failure ('test-predict.R:239:5'): only look for columns that exist in re.form ──
unname(predict(m1, re.form = ~1 | h/f, newdata = dd[1, ])) not equal to 0.14786.
1/1 mismatches
[1] 0.151 - 0.148 == 0.00264
── Failure ('test-predict.R:240:5'): only look for columns that exist in re.form ──
unname(...) not equal to 0.1533.
1/1 mismatches
[1] 0.159 - 0.153 == 0.00545
── Failure ('test-summary.R:57:3'): lmer ───────────────────────────────────────
tfun(cc2) not equal to c(...).
1/10 mismatches
x[10]: "x.2  0.135 -0.103"
y[10]: "x.2  0.136 -0.103"

@jaganmn
Copy link
Collaborator

jaganmn commented Oct 22, 2025

Yeah, after pulling and rebuilding, I no longer see the error from tests/testthat/test-methods.R.

The confint.merMod example seems to fail because devfun2 expects that pp$theta is a concatenation of vectors of length p*(p+1)/2. That is no longer true here, where it parametrizes a diagonal covariance matrix. This issue is known: #858.

I reproduce the errors from tests/testthat/test-predict.R.

@bbolker
Copy link
Member

bbolker commented Oct 22, 2025

Finding the source of the differences in fitted values from reference values is going to take some more work. In theory the changes to the way unstructured models are built should result in identical problem set-up → identical solutions ... ???

@jaganmn jaganmn marked this pull request as ready for review October 22, 2025 14:40
@jaganmn jaganmn mentioned this pull request Oct 24, 2025
@jaganmn jaganmn removed their request for review October 24, 2025 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants