Changelog
LaMa 3.1.0
-
tpm_ct()is much faster: with AD and 2 states it uses an exact closed form instead ofMatrix::expm()for each interval (about 100x faster gradients), and for a constantQit computes the matrix exponential only once per unique time difference -
qreml()no longer evaluates the Hessian a second time for the returned model, which saves aboutlength(par)gradient evaluations per fit, and the final message now reads"Final sp: ..."as no fit follows it unless the last iterate was not the best one -
MCreport()forqreml()models samples around the final estimate, and withjoint = TRUE(orQfromjoint_uncertainty()) accounts for the uncertainty in the penalty strengths; needs RTMBdist >= 1.2.1 -
residuals(mod)gives the pseudo-residuals, callingpseudo_res(mod = mod) -
coef(mod)andvcov(mod)give the estimated fixed parameters and their covariance from the inverse Hessian (of the marginal likelihood with random effects, conditional on the smoothing parameters forqreml()models), soconfint(mod)works too -
qreml()no longer tries doubled steps after improving ones: each trial costs a full inner fit, and across the case studies tried it almost never reduced the number of inner fits -
qreml(lsp_min = -15)boundslog(lambda)from below, so a penalty strength on a smooth the data cannot inform stops falling and the iteration can converge; a penalty strength ending there gives a warning, andsummary()notes it: a larger basis dimension is suggested if no other penalty acts on the same coefficients, otherwise the penalty is reported as redundant (e.g. the wiggliness penalty of a tensor product with a random effect margin), which a larger basis does not help -
qreml(): a step that changes the restricted likelihood by less than1e-6 * (1 + |criterion|)counts as unchanged, instead of setting off up tomax_halverefits at essentially the same penalty strengths at the optimum -
qreml()also converges once the inner optimiser no longer moves from its warm start, so a penalty strength creeping towards zero along a flat restricted likelihood no longer runs on untillsp_minormaxiter -
qreml()returnsn_fits, the number of inner fits including rejected steps, shown bysummary()next to the number of outer iterations -
tpm()andgenerator()with a design matrix give a one-time message while taping ifTapeConfig(matmul = 'plain')would record more than 1e8 multiply-adds for the linear predictor (counting only nonzero entries ofZ, which RTMB skips otherwise), suggestingTapeConfig(matmul = 'atomic')as the tape may not fit into memory -
qreml()returnsedf_hist, the effective degrees of freedom of each smooth at the start of each outer iteration (column 1 is the initial fit) -
qreml():outer_hessian()now differentiates the approximate gradient of the restricted log-likelihood w.r.t.log(lambda)by central differences (2 inner fits per free penalty strength, steph = 0.1), instead of one-sided differences with an absolute step of 1e-4 inlambda, which was inaccurate and could give an indefinite Hessian. The fits are warm started at the final estimate with a tighter inner tolerance. The result is now on the log scale -
qreml():outer_hessian()no longer leaves the objective at the last perturbed penalty strength, so samples or Hessians computed frommod$objafterwards use the fitted penalty strengths again -
qreml()returnsjoint_uncertainty(), the joint precision matrix of the parameters and the log penalty strengths (the first-order correction of Wood, Pya and Saefken, 2016, for the uncertainty in the penalty strengths, in the form of TMB’ssdreport(getJointPrecision = TRUE)), which stays sparse withspHess = TRUE; withprecision = FALSEthe corrected covariance of the parameters -
sdreport_outer()works with the outer Hessian w.r.t.log(lambda)and obtains the standard deviations oflambdaand1/lambdafrom it by the delta method
LaMa 3.0.0
CRAN release: 2026-10-28
This is a major release: models are now built around statedens() and lama(), which give print(), summary(), plot(), simulate(), pseudo_res() and scores() from the model object alone. Several functions are renamed (old names still work but are deprecated), a few are removed, and some outputs change (e.g. llk instead of ll, sp instead of lambda), so existing code may need small adjustments.
New features
statedens()builds the matrix of state-dependent densities of one data stream forallprobs, with parameters given per state, for all states or per observation and state; missing observations are handled for each stream separately, andlog = TRUEgives log-densities forforward(..., logspace = TRUE);pseudo_res(mod)works with itforward()without AD gives an error for negativeallprobs, suggestinglogspace = TRUEforward(delta = "stationary")computes the initial distribution fromGamma: the stationary distribution (per track if track-specific, of the first slice of each track if time-varying) or, withtod, the periodically stationary distribution at the first time point of each trackplot(mod, type = "statedens")shows the state-dependent densities of each data stream built withstatedens()on a histogram, weighted by the local state probabilities (or decoded states, the stationary distribution or given weights), which also works with covariates, several tracks and inhomogeneous models; the weighted densities are returned invisiblyplot(mod, stream = ...)selects data streams, for residuals and state-dependent densitiesplot(mod, type = "statedens", xlim = ...)evaluates the density curves on the plotted range, not only the range of the datasimulate(mod)simulates states and observations of models built withstatedens()on the observed design: same tracks and lengths, withdelta,Gammaand the parameters as reported (conditional on the covariates, for continuous-time models on the observed time points); missing observations stay missing unlessfill_na = TRUE, andrdensgives random number generators for densities without a matching r-function; a data stream that isNAthroughout is a placeholder, so a likelihood function can be used to simulate data and then be fitted to themsimulate(mod, random = TRUE)andobj$simulate()of RTMB work withforward()andstatedens():statedens()registers its data likeOBS(x), so random effects (with their density evaluated first, e.g.u %~% dnorm(...)) are drawn first, then the states and data given them;forward()reports the simulated states asstatesprint()andsummary()for models fromlama()andqreml():print()gives a short overview,summary()the estimated state process (transition probability or generator matrix, stationary distribution and mean dwell times, averaged over tracks if track-specific) and the reported quantities, with those of lengthnStatesin one table;summary.qremlModel()adds the smooth terms and returns an object nowqreml()models have classc("qremlModel", "LaMaModel"), so allLaMaModelmethods apply to themforward()reports type"track-specific"for oneGammaper track (before"homogeneous")multistart(obj)optimises an RTMB object from several starting values (obj$parand perturbations of it, or of the first fit scaled by the unit information withscale = "unit_info"), stops by a Bayesian stopping rule or once the best optimum is reached often enough, and returns the best fit with a table of all runs;lama(obj)then builds the model from the best fitmodmat()returnssp0, initial penalty strengths frommgcv::initial.sp()(times 100, capped at 1e6), one per penalty matrix and named asS;rep_sp()repeats them aslambdafor smooths used more than once, e.g. one per stateThe penalty strengths are now called
sp:qreml()takes them fromdat$spif present, otherwise fromdat$lambdaas before, solambdais free for other things, e.g. a Poisson mean;spnamestill overrides this.penalty()andpenalty2()call their argumentsp,lambdastill worksprint()for objects frommodmat()shows the formulas and the initial penalty strengthssmoothdens()builds the objects for smooth (P-spline) densities from a data vector, or one object per stream from a data frame or list;density(beta)in the returned object gives theallprobsmatrix andpredict()the estimated densities, e.g. on the gridxseq
Changes
make_matrices()is renamed tomodmat();make_matrices()still worksreport()is renamed tolama(), as it does much more than callingobj$report();report()still works but is deprecatedold functions still work but are deprecated, with a message pointing to the new implementation:
forward_s()andforward_sp()(useforward_hsmm()andforward_phsmm()),tpm_hsmm2()andtpm_phsmm2()(usetpm_hsmm()andtpm_phsmm()),tpm_g2()(usetpm()),qreml_old()(useqreml()),stationary_cont()andtpm_cont()(usestationary_ct()andtpm_ct())deprecation messages are shown once per session, not at every call
lama(): the log-likelihood is calledllk(beforell), as forqreml()lama()andqreml():nobsdoes not count missing observations (rows ofallprobsthat are all 1), which changes BIC for data with missing observationslama()stores the maximum gradient componentmgcto check convergencepseudo_res(mod)computes pseudo-residuals from the model object alone: the likelihood function is evaluated again with its densities replaced by their CDFs, after checking that this is valid; several data streams give one set of residuals each; also forqreml()models and densities in helper functionsscores(mod)computes the score contribution of each observation for models usingforward(), e.g. for robust (sandwich) standard errors; it takes the model fromlama()or the RTMB object, respectsmap, and the likelihood function does not need to changelama()also storesobj(the same object, not a copy), soMCreport()can be called on the model object fromlama()orqreml()pred_matrix()is deprecated, usepredict()on the object frommodmat()insteadmake_matrices_old()is removedsmooth_dens_construct()is deprecated, usesmoothdens()insteadmake_matrices_dens()andsmooth_dens_construct()no longer print messages;basis$knotsincludes the boundary knots
Bug fixes
Examples and vignettes: the periodically stationary initial distribution matches
forward()’stod, whereGamma[,,tod[t]]is the transition intot, i.e.stationary_p(Gamma, tod[1] %% L + 1)lama(): the log-likelihood was evaluated at the last parameters the optimiser tried, not the bestsummary.qremlModel()failed for reported lists or character vectors, and ifGammawas not reported butdeltawaspseudo_res(): missing observations giveNAin all variants (before0withnormal = FALSE,-Inffor non-randomised discrete residuals)pseudo_res(): parameters given per observation (matrix or vector of lengthnObs) work with missing observationsforward(): with track-specificdeltaorGamma, the AD version matched them to the wrong tracks if the track IDs were not sorted (e.g."ID1", ..., "ID10")forward(): tracks of length one failed with ADlogspace = TRUEis now exact (deltais no longer modified) and also stable without ADone-state models are correct with
logspace = TRUEand report their quantitiesforward_p()works iftoddoes not contain all values1, ..., Lforward_g()works without AD for two observationsstateprobs_g(forecast = TRUE)withtrackIDused the transition matrix of the previous time point, which also affectedpseudo_res()for inhomogeneous models with tracksstateprobs()passesforecaston for time-varyingGammaviterbi()andstateprobs()work for tracks of length onestateprobs(forecast = TRUE): the first row of each track isdelta, not the filtered probabilities givenx_1, sopseudo_res()is correct for the first observationmodmat(): smooths with several penalties but not one per margin (e.g.bs = "fs","ad"ort2(full = TRUE)) kept only the first, so later smooths got the wrong penalty matricesmodmat(): a nested formula list failed if one data stream had no smooth termsmodmat(): tensor product margins over several covariates are named e.g."x,y"(two such margins failed); unpenalised smooths (fx = TRUE) give an informative errorsmooth_dens_construct(): coefficients of one state are a matrix (before a vector, socbind(coef, 0)was wrong); circular data with custom knots failed; angles outside [-pi, pi) are wrapped;paracceptskappanext toconcentrationmake_matrices_dens(): the basis is normalised on a midpoint grid (before a fixed 1e-3 offset, which gave negative weights for data on a small scale), which changes the weights very slightly
Minor changes
-
forward(),forward_g()andforward_p()share one implementation (one C++ and one R version for AD);forward_p()no longer expandsGammafor the computation - tracks need to be contiguous, otherwise
forward()gives an informative error - without AD,
forward()gives an error forNAinallprobs - the
TapeConfigperformance tip is shown only once per session -
viterbi(),stateprobs()and their_gand_pversions use the inputs offorward()and one C++ implementation each, soGammais no longer expanded; as inforward(), tracks need to be contiguous -
forward_p()reportsGammawith itsLslices and type"periodic" -
forward(),viterbi()andstateprobs()have an argumenttodfor periodic models, so they handle all model types;forward_g(),forward_p(),viterbi_g(),viterbi_p(),stateprobs_g()andstateprobs_p()are deprecated and give a message -
viterbi()andstateprobs()also take the model object as first argument, e.g.viterbi(mod)instead ofviterbi(mod = mod) -
tpm_g()andgenerator_g()are deprecated in favour oftpm(beta, Z)andgenerator(beta, Z), which also accept a single covariate vectorZ; thesparseargument oftpm_g()is gone -
modmat()sets up each basis once and no longer keepsgam$X(returned asZ), so it is faster and needs less memory
LaMa 2.1.1 (2026-05-13)
CRAN release: 2026-05-13
Major changes
vignettes 1-3 have been updated to work with automatic differentiation
tpm(),forward(),stateprobs(),viterbi()can now be used with inhomogeneous models: call their inhomogeneous counterparts internally-
function
MCreport()has been added for sampling- from the distribution of the MLE (fixed effects only models)
- from the joint post. distribution of parameters and random effects (random effects models)
Minor changes
some functions have been renamed, e.g.
stationary_cont()->stationary_ct()(old versions still exist)some internal cleanup