Rev 2145 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#include "lmer.h"#include <float.h>/* These should be moved to the R sources *//*** Symmetrize a matrix by copying the strict upper triangle into the* lower triangle.** @param a pointer to a matrix in Fortran storage mode* @param nc number of columns (and rows and leading dimension) in the matrix** @return a, symmetrized*/static double*internal_symmetrize(double *a, int nc){int i, j;for (i = 1; i < nc; i++)for (j = 0; j < i; j++)a[i + j*nc] = a[j + i*nc];return a;}/*** Simulate the Cholesky factor of a standardized Wishart variate with* dimension p and df degrees of freedom.** @param df degrees of freedom* @param p dimension of the Wishart distribution* @param ans array of size p * p to hold the result** @return ans*/static double*std_rWishart_factor(double df, int p, double ans[]){int i, j, pp1 = p + 1;if (df < (double) p || p <= 0)error("inconsistent degrees of freedom and dimension");for (j = 0; j < p; j++) { /* jth column */ans[j * pp1] = sqrt(rchisq(df - (double) j));for (i = 0; i < j; i++) ans[i + j * p] = norm_rand();}return ans;}/* These should be moved to other source files such as chm_common.c */static cholmod_dense*numeric_as_chm_dense(double *v, int n){cholmod_dense *ans = Calloc(1, cholmod_dense);ans->d = ans->nzmax = ans->nrow = n;ans->ncol = 1;ans->x = (void *) v;ans->xtype = CHOLMOD_REAL;ans->dtype = CHOLMOD_DOUBLE;return ans;}staticSEXP alloc_dgeMatrix(int m, int n, SEXP rownms, SEXP colnms){SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dgeMatrix"))), dn;int *dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2));dims[0] = m; dims[1] = n;ALLOC_SLOT(ans, Matrix_xSym, REALSXP, m * n);dn = GET_SLOT(ans, Matrix_DimNamesSym);SET_VECTOR_ELT(dn, 0, duplicate(rownms));SET_VECTOR_ELT(dn, 1, duplicate(colnms));UNPROTECT(1);return ans;}staticSEXP alloc_dpoMatrix(int n, char *uplo, SEXP rownms, SEXP colnms){SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dpoMatrix"))), dn;int *dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2));dims[0] = dims[1] = n;ALLOC_SLOT(ans, Matrix_xSym, REALSXP, n * n);SET_SLOT(ans, Matrix_uploSym, mkString(uplo));dn = GET_SLOT(ans, Matrix_DimNamesSym);SET_VECTOR_ELT(dn, 0, duplicate(rownms));SET_VECTOR_ELT(dn, 1, duplicate(colnms));UNPROTECT(1);return ans;}staticSEXP alloc_dtrMatrix(int n, char *uplo, char *diag, SEXP rownms, SEXP colnms){SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dtrMatrix"))), dn;int *dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2));dims[0] = dims[1] = n;ALLOC_SLOT(ans, Matrix_xSym, REALSXP, n * n);SET_SLOT(ans, Matrix_uploSym, mkString(uplo));SET_SLOT(ans, Matrix_diagSym, mkString(diag));dn = GET_SLOT(ans, Matrix_DimNamesSym);SET_VECTOR_ELT(dn, 0, duplicate(rownms));SET_VECTOR_ELT(dn, 1, duplicate(colnms));UNPROTECT(1);return ans;}staticSEXP alloc_dsCMatrix(int n, int nz, char *uplo, SEXP rownms, SEXP colnms){SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dsCMatrix"))), dn;int *dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2));dims[0] = dims[1] = n;ALLOC_SLOT(ans, Matrix_xSym, REALSXP, nz);ALLOC_SLOT(ans, Matrix_iSym, INTSXP, nz);ALLOC_SLOT(ans, Matrix_pSym, INTSXP, n + 1);SET_SLOT(ans, Matrix_uploSym, mkString(uplo));dn = GET_SLOT(ans, Matrix_DimNamesSym);SET_VECTOR_ELT(dn, 0, duplicate(rownms));SET_VECTOR_ELT(dn, 1, duplicate(colnms));UNPROTECT(1);return ans;}/* Internally used utilities */#define flag_not_factored(x) *LOGICAL(GET_SLOT(x, Matrix_statusSym)) = 0/*** Create the diagonal blocks of the variance-covariance matrix of the* random effects** @param Linv - cholmod_sparse representation of L^{-1}* @param nf - number of grouping factors* @param Gp - group pointers* @param nc - number of columns per factor* @param bVar - list of 3-d arrays to be filled in* @param uplo - "U" or "L" for upper or lower triangle*/static voidLinv_to_bVar(cholmod_sparse *Linv, const int Gp[], const int nc[],SEXP bVar, const char uplo[]){int *Lii = (int*)(Linv->i), *Lip = (int*)(Linv->p), i, nf = LENGTH(bVar);double *Lix = (double*)(Linv->x), one[] = {1,0}, zero[] = {0,0};for (i = 0; i < nf; i++) {int *ind, j, nci = nc[i], maxnnz = 0;int ncisqr = nci * nci, nlev = (Gp[i + 1] - Gp[i])/nci;double *bVi = REAL(VECTOR_ELT(bVar, i)), *tmp;AZERO(bVi, nlev * ncisqr);for (j = 0; j < nlev; j++) {int nzm = Lip[Gp[i] + (j + 1) * nci] - Lip[Gp[i] + j * nci];if (nzm > maxnnz) maxnnz = nzm;}ind = Calloc(maxnnz, int);tmp = Calloc(maxnnz * nci, double);for (j = 0; j < nlev; j++) {int jj, k, kk;int *ap = Lip + Gp[i] + j * nci;int nr = ap[1] - ap[0];AZERO(tmp, maxnnz * nci);Memcpy(ind, Lii + ap[0], nr);Memcpy(tmp, Lix + ap[0], nr);for (jj = 1; jj < nci; jj++) {for (k = ap[jj]; k < ap[jj + 1]; k++) {int aik = Lii[k];for (kk = 0; kk < nr; kk++) {if (aik == ind[kk]) {tmp[kk + jj * maxnnz] = Lix[k];aik = -1;break;}}if (aik >= 0) { /* did not find the row index */ind[nr] = aik;tmp[nr + jj * maxnnz] = Lix[k];nr++;}}}F77_CALL(dsyrk)(uplo, "T", &nci, &nr, one, tmp, &maxnnz,zero, bVi + j * ncisqr, &nci);}Free(ind); Free(tmp);}}/*** Evaluate the quadratic form in b defined by Omega** @param b vector of random effects* @param Omega - list of dpoMatrix objects defining the pattern for Omega* @param nf - number of grouping factors* @param Gp - group pointers* @param nc - number of columns per factor** @return*/static doubleb_quadratic(const double b[], SEXP Omega, const int Gp[], const int nc[]){int i, ione = 1, nf = LENGTH(Omega);double ans = 0., one[] = {1.,0.};for (i = 0; i < nf; i++) {int nci = nc[i], ntot = Gp[i + 1] - Gp[i];int nlev = ntot/nci;double *bcp = Memcpy(Calloc(ntot, double), b + Gp[i], ntot),*omgf = REAL(GET_SLOT(dpoMatrix_chol(VECTOR_ELT(Omega, i)), Matrix_xSym));F77_CALL(dtrmm)("L", "U", "N", "N", &nci, &nlev, one, omgf, &nci, bcp, &nci);ans += F77_CALL(ddot)(&ntot, bcp, &ione, bcp, &ione);Free(bcp);}return ans;}/*** Calculate the length of the parameter vector (historically called "coef"* even though these are not coefficients).** @param nf number of factors* @param nc number of columns in the model matrices for each factor** @return total length of the coefficient vector*/static R_INLINEint coef_length(int nf, const int nc[]){int i, ans = 0;for (i = 0; i < nf; i++) ans += (nc[i] * (nc[i] + 1))/2;return ans;}/*** Find a variable of a given name in a given environment and check* that its length and mode are correct.** @param rho Environment in which to find the variable* @param nm Name of the variable to find* @param mode Desired mode* @param len Desired length** @return*/staticSEXP find_and_check(SEXP rho, SEXP nm, SEXPTYPE mode, int len){SEXP ans;if (R_NilValue == PROTECT(ans = findVarInFrame(rho, nm)))error(_("environment `rho' must contain an object `%s'"),CHAR(PRINTNAME(nm)));if (TYPEOF(ans) != mode)error(_("object `%s' of incorrect type"),CHAR(PRINTNAME(nm)));if (len && LENGTH(ans) != len)error(_("object `%s' must be of length `%d'"),CHAR(PRINTNAME(nm)), len);UNPROTECT(1);return ans;}/*** Evaluate an expression in an environment, check that the length and* mode are as expected and store the result.** @param fcn expression to evaluate* @param rho environment in which to evaluate it* @param vv position to store the result** @return vv with new contents*/staticSEXP eval_check_store(SEXP fcn, SEXP rho, SEXP vv){SEXP v = PROTECT(eval(fcn, rho));if (TYPEOF(v) != TYPEOF(vv) || LENGTH(v) != LENGTH(vv))error(_("fcn produced mode %d, length %d - wanted mode %d, length %d"),TYPEOF(v), LENGTH(v), TYPEOF(vv), LENGTH(vv));switch (TYPEOF(v)) {case LGLSXP:Memcpy(LOGICAL(vv), LOGICAL(v), LENGTH(vv));break;case INTSXP:Memcpy(INTEGER(vv), INTEGER(v), LENGTH(vv));break;case REALSXP:Memcpy(REAL(vv), REAL(v), LENGTH(vv));break;default:error(_("invalid type for eval_check_store"));}UNPROTECT(1);return vv;}/*** Evaluate an expression in an environment, check that the length and* mode are as expected and return the result.** @param fcn expression to evaluate* @param rho environment in which to evaluate it* @param mode desired mode* @param len desired length** @return evaluated expression*/static SEXPeval_check(SEXP fcn, SEXP rho, SEXPTYPE mode, int len) {SEXP v = PROTECT(eval(fcn, rho));if (TYPEOF(v) != mode || LENGTH(v) != len)error(_("fcn produced mode %d, length %d - wanted mode %d, length %d"),TYPEOF(v), LENGTH(v), mode, len);UNPROTECT(1);return v;}typedef struct glmer_struct{SEXP cv; /* control values */SEXP mer; /* mixed-effects representation */SEXP rho; /* environment in which to evaluate the calls */SEXP eta; /* linear predictor */SEXP mu; /* mean vector */SEXP unwtd; /* unweighted model matrices */SEXP wtd; /* weighted model matrices */SEXP linkinv; /* expression for inverse link evaluation */SEXP mu_eta; /* expression for dmu/deta evaluation */SEXP LMEopt; /* expression for LME optimization */SEXP dev_resids; /* expression for deviance residuals */SEXP var; /* expression for variance evaluation */double *off; /* offset for random effects only */double *offset; /* offset for GLM */double *wts; /* prior weights for GLM */double *w; /* vector of weights */double *X; /* copy of fixed-effects model matrix */double *y; /* copy of response vector */double *z; /* working residual */double *Zt; /* copy of x slot in transpose of random-effects model matrix */double *etaold; /* previous value of eta for evaluating */int n; /* length of the response vector */int p; /* length of fixed effects vector */int nf; /* number of grouping factors */int npar; /* total length of the parameter */int niterEM; /* default number of ECME iterations */int EMverbose; /* logical indicator */int maxiter; /* maximum number of IRLS iterations */double tol; /* convergence tolerance for IRLS iterations */} glmer_struct, *GlmerStruct;static voidinternal_mer_bVar(SEXP x){int q = LENGTH(GET_SLOT(x, Matrix_rZySym));cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym));cholmod_sparse *eye = cholmod_speye(q, q, CHOLMOD_REAL, &c), *Linv;int *Perm = (int *)(L->Perm), *iperm = Calloc(q, int), i;/* create the inverse permutation */for (i = 0; i < q; i++) iperm[Perm[i]] = i;/* apply iperm to the identity matrix */for (i = 0; i < q; i++) ((int*)(eye->i))[i] = iperm[i];/* Create Linv */Linv = cholmod_spsolve(CHOLMOD_L, L, eye, &c);cholmod_free_sparse(&eye, &c);Linv_to_bVar(Linv, INTEGER(GET_SLOT(x, Matrix_GpSym)),INTEGER(GET_SLOT(x, Matrix_ncSym)),GET_SLOT(x, Matrix_bVarSym), "U");cholmod_free_sparse(&Linv, &c);Free(L);}/*** Increment the fitted values from an mer object using the (possibly* externally stored) contents of the model matrices.** @param x pointer to an mer object* @param X contents of the X model matrix or (double *) NULL* @param Zt values of non-zeros in the Zt model matrix or (double *) NULL* @param initial initial values (i.e. an offset) or (double *) NULL* @param val array to hold the fitted values** @return pointer to a numeric array of fitted values*/static double *internal_mer_fitted(SEXP x, const double X[], const double Ztx[],const double initial[], double val[]){int ione = 1, n = LENGTH(GET_SLOT(x, Matrix_ySym));double one[] = {1,0};mer_secondary(x);if (initial) Memcpy(val, initial, n);else AZERO(val, n);if (X) {SEXP fixef = GET_SLOT(x, Matrix_fixefSym);int p = LENGTH(fixef);F77_CALL(dgemv)("N", &n, &p, one, X, &n, REAL(fixef),&ione, one, val, &ione);}if (Ztx) {SEXP ranef = GET_SLOT(x, Matrix_ranefSym);cholmod_sparse *Zt = as_cholmod_sparse(GET_SLOT(x, Matrix_ZtSym));cholmod_dense *chv = numeric_as_chm_dense(val, n),*chb = as_cholmod_dense(ranef);cholmod_sparse *Ztcp = cholmod_copy_sparse(Zt, &c);if (Ztx != (double*)(Zt->x)) Memcpy((double*)(Ztcp->x), Ztx, cholmod_nnz(Zt, &c));Free(Zt);if (!cholmod_sdmult(Ztcp, 1, one, one, chb, chv, &c))error(_("Error return from sdmult"));Free(chv); Free(chb); cholmod_free_sparse(&Ztcp, &c);}return val;}/*** Extract the coefficients** @param x pointer to an mer object* @param ptyp parameter type to extract* @param ans vector to hold the extracted values** @return ans*/static double *internal_mer_coef(SEXP x, int ptyp, double ans[]){SEXP Omega = GET_SLOT(x, Matrix_OmegaSym);int *nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),i, nf = length(Omega), vind;vind = 0; /* index in ans */for (i = 0; i < nf; i++) {int nci = nc[i], ncip1 = nci + 1;if (nci == 1) {double dd = REAL(GET_SLOT(VECTOR_ELT(Omega, i), Matrix_xSym))[0];ans[vind++] = ptyp ? ((ptyp == 1) ? log(dd) : 1./dd) : dd;} else {if (ptyp) { /* L log(D) L' factor of Omega[,,i] */int j, k, ncisq = nci * nci;double *tmp = Memcpy(Calloc(ncisq, double),REAL(GET_SLOT(dpoMatrix_chol(VECTOR_ELT(Omega, i)),Matrix_xSym)), ncisq);for (j = 0; j < nci; j++) {double diagj = tmp[j * ncip1];ans[vind++] = (ptyp == 1) ? (2. * log(diagj)) :1./(diagj * diagj);for (k = j + 1; k < nci; k++) {tmp[j + k * nci] /= diagj;}}for (j = 0; j < nci; j++) {for (k = j + 1; k < nci; k++) {ans[vind++] = tmp[j + k * nci];}}Free(tmp);} else { /* upper triangle of Omega[,,i] */int j, k, odind = vind + nci;double *omgi = REAL(GET_SLOT(VECTOR_ELT(Omega, i), Matrix_xSym));for (j = 0; j < nci; j++) {ans[vind++] = omgi[j * ncip1];for (k = j + 1; k < nci; k++) {ans[odind++] = omgi[k*nci + j];}}vind = odind;}}}return ans;}/*** Set the coefficient vector and perform a factorization** @param x pointer to an mer object* @param cc vector of coefficients to assign* @param ptyp indicator of the parametrization being used*/staticvoid internal_mer_coefGets(SEXP x, const double cc[], int ptyp){SEXP Omega = GET_SLOT(x, Matrix_OmegaSym);int *nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),cind, i, nf = length(Omega);cind = 0;for (i = 0; i < nf; i++) {SEXP Omegai = VECTOR_ELT(Omega, i);int j, k, nci = nc[i], ncisq = nc[i] * nc[i];double *choli, *omgi = REAL(GET_SLOT(Omegai, Matrix_xSym));if (nci == 1) {double dd = cc[cind++];*omgi = ptyp ? ((ptyp == 1) ? exp(dd) : 1./dd) : dd;} else {int odind = cind + nci, /* off-diagonal index */ncip1 = nci + 1;if (ptyp) {/* FIXME: Write this as an LDL decomposition */double *tmp = Calloc(ncisq, double),diagj, one = 1., zero = 0.;AZERO(omgi, ncisq);for (j = 0; j < nci; j++) {double dd = cc[cind++];tmp[j * ncip1] = diagj =(ptyp == 1) ? exp(dd/2.) : sqrt(1./dd);for (k = j + 1; k < nci; k++) {tmp[k*nci + j] = cc[odind++] * diagj;}}F77_CALL(dsyrk)("U", "T", &nci, &nci, &one,tmp, &nci, &zero, omgi, &nci);Free(tmp);} else {for (j = 0; j < nci; j++) {omgi[j * ncip1] = cc[cind++];for (k = j + 1; k < nci; k++) {omgi[k*nci + j] = cc[odind++];}}}cind = odind;}choli = REAL(GET_SLOT(dpoMatrix_chol(Omegai), Matrix_xSym));Memcpy(choli, omgi, ncisq);F77_CALL(dpotrf)("U", &nci, choli, &nci, &j);/* Yes, you really do need to do that decomposition.The contents of choli before the decomposition arefrom the previous value of Omegai. */if (j)error(_("Omega[[%d]] is not positive definite"), i + 1);}flag_not_factored(x);}/*** Evaluate current estimate of sigma from an mer object** @param x pointer to an mer object* @param REML indicator of whether to use REML.* < 0 -> determine REML or ML from x@method* == 0 -> use ML unconditionally* > 0 -> use REML unconditionally** @return*/static doubleinternal_mer_sigma(SEXP x, int REML){double *dcmp = REAL(GET_SLOT(x, Matrix_devCompSym));if (REML < 0) /* get REML from x */REML = !strcmp(CHAR(asChar(GET_SLOT(x,Matrix_methodSym))),"REML");mer_factor(x);return exp(dcmp[3]/2)/sqrt(dcmp[0] - (REML ? dcmp[1] : 0));}/*** Update the derived quantities (ZtZ, ZtX, XtX, Zty, Xty* and dcmp[2] = y'y when Z, X or y has been changed.** @param x pointer to an mer object* @param perm permutation from the Cholesky factor*/static voidinternal_mer_update_ZXy(SEXP x, int *perm){SEXP Xp = GET_SLOT(x, Matrix_XSym), ZtZ = GET_SLOT(x, Matrix_ZtZSym),Ztyp = GET_SLOT(x, Matrix_ZtySym);SEXP ZtZx = GET_SLOT(ZtZ, Matrix_xSym),ZtZp = GET_SLOT(ZtZ, Matrix_pSym), ZtZi = GET_SLOT(ZtZ, Matrix_iSym);int *dims = INTEGER(getAttrib(Xp, R_DimSymbol)), i, ione = 1, j;int n = dims[0], nnz, p = dims[1], q = LENGTH(Ztyp);cholmod_sparse *ts1, *ts2,*Zt = as_cholmod_sparse(GET_SLOT(x, Matrix_ZtSym));double *X = REAL(Xp),*XtX = REAL(GET_SLOT(GET_SLOT(x, Matrix_XtXSym), Matrix_xSym)),*Xty = REAL(GET_SLOT(x, Matrix_XtySym)),*ZtX = REAL(GET_SLOT(GET_SLOT(x, Matrix_ZtXSym), Matrix_xSym)),*Zty = REAL(Ztyp),*y = REAL(GET_SLOT(x, Matrix_ySym)),one[] = {1, 0}, zero[] = {0,0};cholmod_dense *td1, *Xd = as_cholmod_dense(Xp),*yd = as_cholmod_dense(GET_SLOT(x, Matrix_ySym));/* y'y */REAL(GET_SLOT(x, Matrix_devCompSym))[2] =F77_CALL(ddot)(&n, y, &ione, y, &ione);/* ZtZ */ts1 = cholmod_aat(Zt, (int *) NULL, (size_t) 0, 1/* mode */, &c);/* cholmod_aat returns stype == 0; copy to set stype == 1 */ts2 = cholmod_copy(ts1, 1/* stype */, 1/* mode */, &c);nnz = cholmod_nnz(ts2, &c);if (((int)(ts2->ncol) + 1) != LENGTH(ZtZp))error(_("Order of Z'Z has changed - was %d, now %d"),LENGTH(ZtZp) - 1, (int)(ts2->ncol));Memcpy(INTEGER(ZtZp), (int*)(ts2->p), LENGTH(ZtZp));if (nnz != LENGTH(ZtZx))error(_("Number of nonzeros in Z'Z has changed - was %d, now %d"),LENGTH(ZtZx), nnz);Memcpy(INTEGER(ZtZi), (int*)(ts2->i), nnz);Memcpy(REAL(ZtZx), (double*)(ts2->x), nnz);cholmod_free_sparse(&ts1, &c); cholmod_free_sparse(&ts2, &c);/* PZ'X into ZtX */td1 = cholmod_allocate_dense(q, p, q, CHOLMOD_REAL, &c);if (!cholmod_sdmult(Zt, 0, one, zero, Xd, td1, &c))error(_("cholmod_sdmult failed"));for (j = 0; j < p; j++) { /* apply the permutation to each column */double *dcol = ZtX + j * q,*scol = (double*)(td1->x) + j * q;for (i = 0; i < q; i++) dcol[i] = scol[perm[i]];}cholmod_free_dense(&td1, &c); Free(Xd);/* PZ'y into Zty */td1 = cholmod_allocate_dense(q, 1, q, CHOLMOD_REAL, &c);if (!cholmod_sdmult(Zt, 0, one, zero, yd, td1, &c))error(_("cholmod_sdmult failed"));for (i = 0; i < q; i++) Zty[i] = ((double *)(td1->x))[perm[i]];cholmod_free_dense(&td1, &c); Free(yd); Free(Zt);/* XtX and Xty */AZERO(XtX, p * p);F77_CALL(dsyrk)("U", "T", &p, &n, one, X, &n, zero, XtX, &p);F77_CALL(dgemv)("T", &n, &p, one, X, &n, y, &ione, zero, Xty, &ione);flag_not_factored(x);}static double chm_log_abs_det(cholmod_factor *F){double ans = 0;if (F->is_super) {int i;for (i = 0; i < F->nsuper; i++) {int j, nrp1 = 1 + ((int *)(F->pi))[i + 1] - ((int *)(F->pi))[i],nc = ((int *)(F->super))[i + 1] - ((int *)(F->super))[i];double *x = (double *)(F->x) + ((int *)(F->px))[i];for (j = 0; j < nc; j++) ans += log(fabs(x[j * nrp1]));}} elseerror(_("code for simplicial factorization not yet written"));return ans;}static doubleOmega_log_det(SEXP Omega, int *nc, int *Gp){double ans = 0;int i;for (i = 0; i < LENGTH(Omega); i++) {int j, nci = nc[i], ncip1 = nc[i] + 1, nlev = (Gp[i + 1] - Gp[i])/nc[i];double *omgi = REAL(GET_SLOT(dpoMatrix_chol(VECTOR_ELT(Omega, i)),Matrix_xSym));for (j = 0; j < nci; j++) ans += 2. * nlev * log(fabs(omgi[j * ncip1]));}return ans;}/*** Inflate Z'Z to Z'Z+Omega and factor. Form RZX and rZy and update* the status flags.** @param x pointer to an mer object.*/static voidinternal_mer_Zfactor(SEXP x, cholmod_factor *L){SEXP Omega = GET_SLOT(x, Matrix_OmegaSym),rZyP = GET_SLOT(x, Matrix_rZySym);int *Gp = INTEGER(GET_SLOT(x, Matrix_GpSym)),*nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),nf = LENGTH(Omega), q = LENGTH(rZyP),p = LENGTH(GET_SLOT(x, Matrix_rXySym));cholmod_sparse *A, *Omg,*zz = as_cholmod_sparse(GET_SLOT(x, Matrix_ZtZSym));cholmod_dense *ZtX = as_cholmod_dense(GET_SLOT(x, Matrix_ZtXSym)),*Zty = as_cholmod_dense(GET_SLOT(x, Matrix_ZtySym)),*rZy, *RZX;int *omp, *nnz = Calloc(nf + 1, int), i,*status = LOGICAL(GET_SLOT(x, Matrix_statusSym));double *dcmp = REAL(GET_SLOT(x, Matrix_devCompSym)), one[] = {1, 0};dcmp[5] = Omega_log_det(Omega, nc, Gp); /* logDet(Omega) */for (nnz[0] = 0, i = 0; i < nf; i++)nnz[i + 1] = nnz[i] + ((Gp[i + 1] - Gp[i])*(nc[i] + 1))/2;Omg = cholmod_allocate_sparse(zz->nrow, zz->ncol, (size_t) nnz[nf],TRUE, TRUE, 1, CHOLMOD_REAL, &c);omp = (int *) Omg->p;for (i = 0; i < nf; i++) {int bb = Gp[i], j, jj, k, nci = nc[i];int nlev = (Gp[i + 1] - bb)/nci;double *Omgi = REAL(GET_SLOT(VECTOR_ELT(Omega, i), Matrix_xSym));for (j = 0; j < nlev; j++) { /* column of result */int col0 = bb + j * nci; /* absolute column number */for (jj = 0; jj < nci; jj++) { /* column of Omega_i */int coljj = col0 + jj;omp[coljj + 1] = omp[coljj] + jj + 1;for (k = 0; k <= jj; k++) { /* row of Omega_i */int ind = omp[coljj];((int *)Omg->i)[ind + k] = col0 + k;((double *)Omg->x)[ind + k] = Omgi[jj * nci + k];}}}}Free(nnz);A = cholmod_add(zz, Omg, one, one, TRUE, TRUE, &c);Free(zz); cholmod_free_sparse(&Omg, &c);if (!cholmod_factorize(A, L, &c))error(_("rank_deficient Z'Z+Omega"));cholmod_free_sparse(&A, &c);dcmp[4] = 2 * chm_log_abs_det(L); /* 2 * logDet(L) *//* calculate and store RZX and rZy */RZX = cholmod_solve(CHOLMOD_L, L, ZtX, &c); Free(ZtX);rZy = cholmod_solve(CHOLMOD_L, L, Zty, &c); Free(Zty);Memcpy(REAL(GET_SLOT(GET_SLOT(x, Matrix_RZXSym), Matrix_xSym)),(double *) RZX->x, q * p);cholmod_free_dense(&RZX, &c);Memcpy(REAL(rZyP), (double *) rZy->x, q);cholmod_free_dense(&rZy, &c);/* signal that secondary slots are not valid */status[0] = 1;status[1] = status[2] = status[3] = 0;}/*** Update the relative precision matrices by sampling from a Wishart* distribution with scale factor determined by the current sample of* random effects.** @param Omega pointer to the list of relative precision matrices* @param b current sample from the random effects* @param sigma current value of sigma* @param nf number of grouping factors* @param nc number columns per grouping factor* @param Gp integer vector pointing to the beginning of each outer* group of columns* @param vals vector in which to store values* @param trans logical value indicating if variance components are* stored in the transformed scale.*/static voidinternal_Omega_update(SEXP Omega, const double b[], double sigma, int nf,const int nc[], const int Gp[], double *vals, int trans){int i, j, k, info;double one = 1, zero = 0;for (i = 0; i < nf; i++) {int nci = nc[i];int nlev = (Gp[i + 1] - Gp[i])/nci, ncip1 = nci + 1,ncisqr = nci * nci;double*scal = Calloc(ncisqr, double), /* factor of scale matrix */*tmp = Calloc(ncisqr, double),*var = Calloc(ncisqr, double), /* simulated variance-covariance */*wfac = Calloc(ncisqr, double); /* factor of Wishart variate *//* generate and factor the scale matrix */AZERO(scal, ncisqr);F77_CALL(dsyrk)("U", "N", &nci, &nlev, &one, b + Gp[i], &nci,&zero, scal, &nci);F77_CALL(dpotrf)("U", &nci, scal, &nci, &info);if (info)error(_("Singular random effects varcov at level %d"), i + 1);/* generate a random factor from a standard Wishart distribution */AZERO(wfac, ncisqr);std_rWishart_factor((double) (nlev - nci + 1), nci, wfac);/* form the variance-covariance matrix and store elements */Memcpy(tmp, scal, ncisqr);F77_CALL(dtrsm)("L", "U", "T", "N", &nci, &nci,&one, wfac, &nci, tmp, &nci);F77_CALL(dsyrk)("U", "T", &nci, &nci, &one, tmp, &nci,&zero, var, &nci);for (j = 0; j < nci; j++) {*vals++ = (trans ? log(var[j * ncip1]) : var[j * ncip1]);}for (j = 1; j < nci; j++) {for (k = 0; k < j; k++) {*vals++ = (trans ? atanh(var[k + j * nci]/sqrt(var[j * ncip1] * var[k * ncip1])): var[k + j * nci]);}}/* calculate and store the relative precision matrix */Memcpy(tmp, wfac, ncisqr);F77_CALL(dtrsm)("R", "U", "T", "N", &nci, &nci,&sigma, scal, &nci, tmp, &nci);F77_CALL(dsyrk)("U", "T", &nci, &nci, &one, tmp, &nci, &zero,REAL(GET_SLOT(VECTOR_ELT(Omega, i), Matrix_xSym)),&nci);dpoMatrix_chol(VECTOR_ELT(Omega, i));Free(scal); Free(tmp); Free(wfac); Free(var);}}/*** Evaluate new weights and working residuals.** @param GS a GlmerStruct object*/static voidinternal_glmer_reweight(GlmerStruct GS) {SEXP dmu_deta, var,mZt = GET_SLOT(GS->mer, Matrix_ZtSym);int *Zp = INTEGER(GET_SLOT(mZt, Matrix_pSym));int i, j,n = LENGTH(GET_SLOT(GS->mer, Matrix_ySym)),p = LENGTH(GET_SLOT(GS->mer, Matrix_rXySym));double *mX = REAL(GET_SLOT(GS->mer, Matrix_XSym)),*my = REAL(GET_SLOT(GS->mer, Matrix_ySym)),*mZx = REAL(GET_SLOT(mZt, Matrix_xSym));/* reweight mer */eval_check_store(GS->linkinv, GS->rho, GS->mu);dmu_deta = PROTECT(eval_check(GS->mu_eta, GS->rho,REALSXP, GS->n));var = PROTECT(eval_check(GS->var, GS->rho,REALSXP, GS->n));for (i = 0; i < GS->n; i++) {GS->w[i] = GS->wts[i] *REAL(dmu_deta)[i]/sqrt(REAL(var)[i]);GS->z[i] = REAL(GS->eta)[i] - GS->offset[i] +(GS->y[i] - REAL(GS->mu)[i])/REAL(dmu_deta)[i];}UNPROTECT(2);for (i = 0; i < n; i++) my[i] = GS->z[i] * GS->w[i];for (j = 0; j < p; j++)for (i = 0; i < n; i++) mX[i + j * n] =GS->X[i + j * n] * GS->w[i];for (j = 0; j < n; j++) {int i2 = Zp[j + 1];for (i = Zp[j]; i < i2; i++) mZx[i] = GS->Zt[i] * GS->w[j];}mer_update_ZXy(GS->mer);}/*** Update eta, evaluate the convergence criterion, then copy eta to* etaold** @param GS a GlmerStruct object* @param etaold previous values of the linear predictors** @return convergence criterion*/static doubleconv_crit(double etaold[], double eta[], int n) {double max_abs_eta = -1, max_abs_diff = -1;int i;for (i = 0; i < n; i++) {double abs_eta, abs_diff;abs_eta = fabs(eta[i]);if (abs_eta > max_abs_eta) max_abs_eta = abs_eta;abs_diff = fabs(eta[i] - etaold[i]);if (abs_diff > max_abs_diff) max_abs_diff = abs_diff;etaold[i] = eta[i];}return max_abs_diff / (0.1 + max_abs_eta);}/*** Evaluate the quadratic form (x-mn)'A'A(x-mn) from the multivariate* normal kernel.** @param n dimension of random variate* @param mn mean vector* @param a upper Cholesky factor of the precision matrix* @param lda leading dimension of A* @param x vector at which to evaluate the kernel** @return value of the normal kernel*/static doublenormal_kernel(int n, const double mn[],const double a[], int lda, const double x[]){int i, ione = 1;double *tmp = Calloc(n, double), ans;for (i = 0; i < n; i++) tmp[i] = x[i] - mn[i];F77_CALL(dtrmv)("U", "N", "N", &n, a, &lda, tmp, &ione);for (i = 0, ans = 0; i < n; i++) ans += tmp[i] * tmp[i];Free(tmp);return ans;}/*** Evaluate the conditional deviance for a given set of fixed effects.** @param GS Pointer to a GlmerStruct* @param fixed value of the fixed effects** @return conditional deviance*/static doublefixed_effects_deviance(GlmerStruct GS, const double fixed[]){SEXP devs;int i, ione = 1;double ans, one = 1, zero = 0;F77_CALL(dgemv)("N", &(GS->n), &(GS->p), &one,GS->X, &(GS->n), fixed,&ione, &zero, REAL(GS->eta), &ione);/* add in random effects and offset */vecIncrement(REAL(GS->eta), GS->off, GS->n);eval_check_store(GS->linkinv, GS->rho, GS->mu);devs = PROTECT(eval_check(GS->dev_resids, GS->rho, REALSXP, GS->n));for (i = 0, ans = 0; i < GS->n; i++) ans += REAL(devs)[i];UNPROTECT(1);return ans;}/*** Update the ranef slot assuming that the fixef, rZy, RZX and L slots* are up to date.** @param x Pointer to an mer object** @return*/static double*internal_mer_ranef(SEXP x){SEXP ranef = GET_SLOT(x, Matrix_ranefSym);int *status = LOGICAL(GET_SLOT(x, Matrix_statusSym));if (!status[0]) {error("Applying internal_mer_ranef without factoring");return (double*)NULL; /* -Wall */}if (!status[1]) {SEXP fixef = GET_SLOT(x, Matrix_fixefSym),ranef = GET_SLOT(x, Matrix_ranefSym);int ione = 1, p = LENGTH(fixef), q = LENGTH(ranef);cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym));cholmod_dense *td1, *td2,*chranef = as_cholmod_dense(ranef);double *RZX = REAL(GET_SLOT(GET_SLOT(x, Matrix_RZXSym), Matrix_xSym)),m1[] = {-1,0}, one[] = {1,0};Memcpy(REAL(ranef), REAL(GET_SLOT(x, Matrix_rZySym)), q);F77_CALL(dgemv)("N", &q, &p, m1, RZX, &q, REAL(fixef), &ione,one, REAL(ranef), &ione);td1 = cholmod_solve(CHOLMOD_Lt, L, chranef, &c);td2 = cholmod_solve(CHOLMOD_Pt, L, td1, &c);Free(chranef); cholmod_free_dense(&td1, &c);Memcpy(REAL(ranef), (double *)(td2->x), q);cholmod_free_dense(&td2, &c);status[1] = 1;status[2] = status[3] = 0;Free(L);}return REAL(ranef);}/*** Update the fixef slot on a factored mer object.** @param x Pointer to an mer object** @return fixed effects vector*/static double*internal_mer_fixef(SEXP x){SEXP fixef = GET_SLOT(x, Matrix_fixefSym);int *status = LOGICAL(GET_SLOT(x, Matrix_statusSym));if (!status[0]) {error("Applying internal_mer_fixef without factoring");return (double*)NULL; /* -Wall */}if (!status[1]) {int ione = 1, p = LENGTH(fixef);Memcpy(REAL(fixef), REAL(GET_SLOT(x, Matrix_rXySym)), p);F77_CALL(dtrsv)("U", "N", "N", &p,REAL(GET_SLOT(GET_SLOT(x, Matrix_RXXSym),Matrix_xSym)),&p, REAL(fixef), &ione);}return REAL(fixef);}/*** Establish off, the effective offset for the fixed effects, and* iterate to determine the conditional modes of the random effects.** @param GS a GlmerStruct object* @param fixed vector of fixed effects* @param varc vector of parameters for the variance-covariance** @return An indicator of whether the iterations converged*/static intinternal_bhat(GlmerStruct GS, const double fixed[], const double varc[]){SEXP fixef = GET_SLOT(GS->mer, Matrix_fixefSym);cholmod_factor *L = as_cholmod_factor(GET_SLOT(GS->mer, Matrix_LSym));int i;double crit = GS->tol + 1;if (varc) /* skip this step if varc == (double*) NULL */internal_mer_coefGets(GS->mer, varc, 2);Memcpy(REAL(fixef), fixed, LENGTH(fixef));internal_mer_Zfactor(GS->mer, L);internal_mer_ranef(GS->mer);internal_mer_fitted(GS->mer, GS->X, GS->Zt, GS->offset, REAL(GS->eta));Memcpy(GS->etaold, REAL(GS->eta), GS->n);for (i = 0; i < GS->maxiter && crit > GS->tol; i++) {internal_glmer_reweight(GS);internal_mer_Zfactor(GS->mer, L);internal_mer_ranef(GS->mer);internal_mer_fitted(GS->mer, GS->X, GS->Zt, GS->offset,REAL(GS->eta));crit = conv_crit(GS->etaold, REAL(GS->eta), GS->n);}Free(L);return (crit > GS->tol) ? 0 : i;}/*** Print the verbose output in the ECME iterations** @param x pointer to an ssclme object* @param iter iteration number* @param REML non-zero for REML, zero for ML*/static voidEMsteps_verbose_print(SEXP x, int iter, int REML){SEXP Omega = GET_SLOT(x, Matrix_OmegaSym),gradComp = GET_SLOT(x, Matrix_gradCompSym);int *nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),i, ifour = 4, ii, ione = 1, jj,nf = LENGTH(Omega);doublecc[] = {-1, 1, 1, REML ? 1 : 0},*dev = REAL(GET_SLOT(x, Matrix_devianceSym)),one = 1., zero = 0.;if (iter == 0) Rprintf(" EM iterations\n");Rprintf("%3d %.3f", iter, dev[REML ? 1 : 0]);for (i = 0; i < nf; i++) {int nci = nc[i], ncip1 = nci + 1, ncisqr = nci * nci;double*Omgi = REAL(GET_SLOT(VECTOR_ELT(Omega, i), Matrix_xSym)),*Grad = Calloc(ncisqr, double);/* diagonals */Rprintf(" (%#8g", Omgi[0]);for (jj = 1; jj < nci; jj++) {Rprintf(" %#8g", Omgi[jj * ncip1]);}for (jj = 1; jj < nci; jj++) /* offdiagonals */for (ii = 0; ii < jj; ii++)Rprintf(" %#8g", Omgi[ii + jj * nci]);/* Evaluate and print the gradient */F77_CALL(dgemv)("N", &ncisqr, &ifour, &one,REAL(VECTOR_ELT(gradComp, i)), &ncisqr,cc, &ione, &zero, Grad, &ione);Rprintf(":%#8.3g", Grad[0]);for (jj = 1; jj < nci; jj++) { /* diagonals */Rprintf(" %#8.3g", Grad[jj * ncip1]);}for (jj = 1; jj < nci; jj++) /* offdiagonals */for (ii = 0; ii < jj; ii++)Rprintf(" %#8.3g", Grad[ii + jj * nci]);Rprintf(")");Free(Grad);}Rprintf("\n");}/*** Perform a number of ECME steps** @param x pointer to an mer object* @param nEM number of iteration to perform* @param verb indicator of verbose output*/static voidinternal_ECMEsteps(SEXP x, int nEM, int verb){SEXP Omega = GET_SLOT(x, Matrix_OmegaSym),gradComp = GET_SLOT(x, Matrix_gradCompSym);int *Gp = INTEGER(GET_SLOT(x, Matrix_GpSym)),*nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),REML = !strcmp(CHAR(asChar(GET_SLOT(x, Matrix_methodSym))),"REML"),i, ifour = 4, info, ione = 1, iter,nf = LENGTH(Omega);doublecc[] = {0, 1, 1, REML ? 1 : 0},zero = 0.0;mer_gradComp(x);if (verb)EMsteps_verbose_print(x, 0, REML);for (iter = 0; iter < nEM; iter++) {for (i = 0; i < nf; i++) {SEXP Omgi = VECTOR_ELT(Omega, i);int nci = nc[i], ncisqr = nci * nci,nlev = (Gp[i + 1] - Gp[i])/nci;double *Omgx = REAL(GET_SLOT(Omgi, Matrix_xSym)),mult = 1./((double) nlev);F77_CALL(dgemm)("N", "N", &ncisqr, &ione, &ifour, &mult,REAL(VECTOR_ELT(gradComp, i)), &ncisqr,cc, &ifour, &zero, Omgx, &ncisqr);F77_CALL(dpotrf)("U", &nci, Omgx, &nci, &info);if (info)error(_("DPOTRF in ECME update gave code %d"),info);F77_CALL(dpotri)("U", &nci, Omgx, &nci, &info);if (info)error(_("Matrix inverse in ECME update gave code %d"), info);SET_SLOT(Omgi, Matrix_factorSym, allocVector(VECSXP, 0));}flag_not_factored(x);mer_gradComp(x);if (verb)EMsteps_verbose_print(x, iter + 1, REML);}}/* FIXME: Separate the calculation of the offset random effects from* the calculation of the deviance contributions. *//*** Determine the deviance components associated with each of the* levels of a grouping factor at the conditional modes or a value* offset from the conditional modes by delb.** @param GS pointer to a GlmerStruct* @param b conditional modes of the random effects* @param Gp group pointers* @param nc number of columns in the model matrix for the kth* grouping factor* @param k index (0-based) of the grouping factor* @param delb vector of length nc giving the changes in the* orthonormalized random effects* @param OmgFac Cholesky factor of the inverse of the penalty matrix* for this grouping factor* @param bVfac 3-dimensional array holding the factors of the* conditional variance-covariance matrix of the random effectsFIXME: This is wrong. It is bVar[[i]] not bVfac that is being passed.This only affects the AGQ method.* @param devcmp array to hold the deviance components** @return devcmp*/static double*rel_dev_1(GlmerStruct GS, const double b[], int nlev, int nc, int k,const double delb[], const double OmgFac[],const double bVfac[], double devcmp[]){SEXP devs;int *fv = INTEGER(VECTOR_ELT(GET_SLOT(GS->mer, Matrix_flistSym), k)),i, j;/* double *bcp = (double *) NULL; */AZERO(devcmp, nlev);#if 0if (delb) {int ione = 1, ntot = nlev * nc;double sumsq = 0;/* copy the contents of b */bcp = Memcpy(Calloc(ntot, double), b, ntot);if (nc == 1) {sumsq = delb[0] * delb[0];for (i = 0; i < nlev; i++) b[i] += delb[0] * bVfac[i];} else {int ncsq = nc * nc;double *tmp = Calloc(nc, double);for (i = 0; i < nlev; i++) {Memcpy(tmp, delb, nc);F77_CALL(dtrmv)("U", "N", "N", &nc, &(bVfac[i * ncsq]),&nc, tmp, &ione);for (j = 0; j < nc; j++) b[i + j * nc] = tmp[j];}/* sum of squares of delb */for (j = 0; j < nc; j++) sumsq += delb[j] * delb[j];}for (i = 0; i < nlev; i++) devcmp[i] = -sumsq;}#endifinternal_mer_fitted(GS->mer, (double *) NULL,REAL(GET_SLOT(GET_SLOT(GS->mer, Matrix_ZtSym), Matrix_xSym)),GS->off, REAL(GS->eta));eval_check_store(GS->linkinv, GS->rho, GS->mu);devs = PROTECT(eval_check(GS->dev_resids, GS->rho, REALSXP, GS->n));for (i = 0; i < GS->n; i++)devcmp[fv[i] - 1] += REAL(devs)[i];UNPROTECT(1);if (nc == 1) {for (i = 0; i < nlev; i++) {double tmp = *OmgFac * b[i];devcmp[i] += tmp * tmp;}} else {double *tmp = Calloc(nc, double);int ione = 1;for (i = 0; i < nlev; i++) {for (j = 0; j < nc; j++) tmp[j] = b[i + j * nlev];F77_CALL(dtrmv)("U", "N", "N", &nc, OmgFac, &nc,tmp, &ione);for (j = 0; j < nc; j++)devcmp[i] += tmp[j] * tmp[j];}}#if 0if (delb) {Memcpy(b, bcp, ntot);Free(bcp);}#endifreturn devcmp;}/*** Evaluate the conditional deviance for the stored random effects.** @param GS Pointer to a GlmerStruct* @param fixed value of the fixed effects** @return conditional deviance*/static doublerandom_effects_deviance(GlmerStruct GS){SEXP devs;int i;double ans;internal_mer_fitted(GS->mer, GS->X, GS->Zt, GS->offset, REAL(GS->eta));eval_check_store(GS->linkinv, GS->rho, GS->mu);devs = PROTECT(eval_check(GS->dev_resids, GS->rho, REALSXP, GS->n));for (i = 0, ans = 0; i < GS->n; i++) ans += REAL(devs)[i];UNPROTECT(1);return ans;}static voidinternal_glmer_ranef_update(GlmerStruct GS, SEXP b){SEXP bhat, bprop = PROTECT(duplicate(b)),bVar = GET_SLOT(GS->mer, Matrix_bVarSym),Omega = GET_SLOT(GS->mer, Matrix_OmegaSym);int i, ione = 1, j, k;/* double *b = REAL(GET_SLOT(GS->mer, Matrix_ranefSym); */double devr, one = 1;bhat = R_NilValue;/* subtract deviance at b *//* devr = -random_effects_deviance(GS, b); */for (i = 0; i < GS->nf; i++) {SEXP Bi = VECTOR_ELT(b, i);int *dims = INTEGER(getAttrib(Bi, R_DimSymbol));int nlev = dims[0], nci = dims[1];int ncisqr = nci * nci, ntot = nlev * nci;double *bcopy = Calloc(ntot, double),*bi = REAL(Bi),*bhati = REAL(VECTOR_ELT(bhat, i)),*bpropi = REAL(VECTOR_ELT(bprop, i)),*bVari = REAL(VECTOR_ELT(bVar, i)),*chol = Calloc(ncisqr, double),*delta = Calloc(nci, double),*omgfac = Memcpy(Calloc(ncisqr, double),REAL(VECTOR_ELT(Omega, i)),ncisqr);/* subtract quadratic form in *//* Omega[[i]] at b */F77_CALL(dpotrf)("U", &nci, omgfac, &nci, &j);if (j)error(_("Leading %d minor of Omega[[%d]] not positive definite"),j, i + 1);Memcpy(bcopy, bi, ntot);F77_CALL(dtrmm)("R", "U", "T", "N", &nlev, &nci, &one,omgfac, &nci, bcopy, &nlev);for (k = 0; k < ntot; k++) devr -= bcopy[k] * bcopy[k];/* form bprop and proposal density */for (k = 0; k < nlev; k++) {/* proposal density at b */for (j = 0; j < nci; j++)delta[j] = bi[k + j * nlev] - bhati[k + j * nlev];Memcpy(chol, &(bVari[k * ncisqr]), ncisqr);F77_CALL(dpotrf)("U", &nci, chol, &nci, &j);if (j)error(_("Leading %d minor of bVar[[%d]][,,%d] not positive definite"),j, i + 1, k + 1);F77_CALL(dtrsv)("U", "T", "N", &nci, chol, &nci,delta, &ione);for (j = 0; j < nci; j++) {double nrm = norm_rand(); /* proposal deviate */devr += delta[j] * delta[j] - nrm * nrm;delta[j] = nrm;}/* scale by Cholesky inverse */F77_CALL(dtrmv)("U", "T", "N", &nci, chol, &nci,delta, &ione);/* add mean */for (j = 0; j < nci; j++)bpropi[k + j * nlev] = bhati[k + j * nlev] + delta[j];}/* add quadratic form in *//* Omega[[i]] at bprop */Memcpy(bcopy, bpropi, ntot);F77_CALL(dtrmm)("R", "U", "T", "N", &nlev, &nci, &one,omgfac, &nci, bcopy, &nlev);for (k = 0; k < ntot; k++) devr += bcopy[k] * bcopy[k];Free(bcopy); Free(chol); Free(delta); Free(omgfac);}/* add deviance at bprop *//* devr += random_effects_deviance(GS, bprop); */if (unif_rand() < exp(-0.5 * devr))for (i = 0; i < GS->nf; i++) { /* copy each face of b */SEXP Bi = VECTOR_ELT(b, i);int *dims = INTEGER(getAttrib(Bi, R_DimSymbol));Memcpy(REAL(Bi), REAL(VECTOR_ELT(bprop, i)),dims[0] * dims[1]);}if (asLogical(Matrix_getElement(GS->cv, "msVerbose"))) {double *b0 = REAL(VECTOR_ELT(bprop, 0));Rprintf("%5.3f:", exp(-0.5 * devr));for (k = 0; k < 5; k++) Rprintf("%#10g ", b0[k]);Rprintf("\n");}UNPROTECT(2);}/*** Determine the conditional modes and the conditional variance of the* fixed effects given the data and the current random effects.* Create a Metropolis-Hasting proposal step from the multivariate* normal density, determine the acceptance probability and, if the* step is to be accepted, overwrite the contents of fixed with the* new contents.** @param GS a GlmerStruct* @param b list of random effects* @param fixed current value of the fixed effects** @return updated value of the fixed effects*/static double *internal_glmer_fixef_update(GlmerStruct GS, SEXP b,double fixed[]){SEXP dmu_deta, var;int i, ione = 1, it, j, lwork = -1;double *ans = Calloc(GS->p, double), /* proposal point */*md = Calloc(GS->p, double), /* conditional modes */*w = Calloc(GS->n, double), *work,*wtd = Calloc(GS->n * GS->p, double),*z = Calloc(GS->n, double),crit, devr, one = 1, tmp, zero = 0;if (!isNewList(b) || LENGTH(b) != GS->nf)error(_("%s must be a %s of length %d"), "b", "list", GS->nf);for (i = 0; i < GS->nf; i++) {SEXP bi = VECTOR_ELT(b, i);if (!isReal(bi) || !isMatrix(bi))error(_("b[[%d]] must be a numeric matrix"), i);}AZERO(z, GS->n); /* -Wall */Memcpy(md, fixed, GS->p);/* calculate optimal size of work array */F77_CALL(dgels)("N", &(GS->n), &(GS->p), &ione, wtd, &(GS->n),z, &(GS->n), &tmp, &lwork, &j);if (j) /* shouldn't happen */error(_("%s returned error code %d"), "dgels", j);lwork = (int) tmp;work = Calloc(lwork, double);AZERO(GS->off, GS->n); /* fitted values from random effects *//* fitted_ranef(GET_SLOT(GS->mer, Matrix_flistSym), GS->unwtd, b, *//* INTEGER(GET_SLOT(GS->mer, Matrix_ncSym)), GS->off); */for (i = 0; i < GS->n; i++)(GS->etaold)[i] = ((GS->off)[i] += (GS->offset)[i]);for (it = 0, crit = GS->tol + 1;it < GS->maxiter && crit > GS->tol; it++) {/* fitted values from current beta */F77_CALL(dgemv)("N", &(GS->n), &(GS->p), &one,GS->X, &(GS->n), md,&ione, &zero, REAL(GS->eta), &ione);/* add in random effects and offset */vecIncrement(REAL(GS->eta), (GS->off), GS->n);/* check for convergence */crit = conv_crit(GS->etaold, REAL(GS->eta), GS->n);/* obtain mu, dmu_deta, var */eval_check_store(GS->linkinv, GS->rho, GS->mu);dmu_deta = PROTECT(eval_check(GS->mu_eta, GS->rho,REALSXP, GS->n));var = PROTECT(eval_check(GS->var, GS->rho, REALSXP, GS->n));/* calculate weights and working residual */for (i = 0; i < GS->n; i++) {w[i] = GS->wts[i] * REAL(dmu_deta)[i]/sqrt(REAL(var)[i]);z[i] = w[i] * (REAL(GS->eta)[i] - (GS->off)[i] +((GS->y)[i] - REAL(GS->mu)[i]) /REAL(dmu_deta)[i]);}UNPROTECT(2);/* weighted copy of the model matrix */for (j = 0; j < GS->p; j++)for (i = 0; i < GS->n; i++)wtd[i + j * GS->n] = GS->X[i + j * GS->n] * w[i];/* weighted least squares solution */F77_CALL(dgels)("N", &(GS->n), &(GS->p), &ione, wtd, &(GS->n),z, &(GS->n), work, &lwork, &j);if (j) error(_("%s returned error code %d"), "dgels", j);Memcpy(md, z, GS->p);}/* wtd contains the Cholesky factor of* the precision matrix */devr = normal_kernel(GS->p, md, wtd, GS->n, fixed);devr -= fixed_effects_deviance(GS, fixed);for (i = 0; i < GS->p; i++) {double var = norm_rand();ans[i] = var;devr -= var * var;}F77_CALL(dtrsv)("U", "N", "N", &(GS->p), wtd, &(GS->n), ans, &ione);for (i = 0; i < GS->p; i++) ans[i] += md[i];devr += fixed_effects_deviance(GS, ans);crit = exp(-0.5 * devr); /* acceptance probability */tmp = unif_rand();if (asLogical(Matrix_getElement(GS->cv, "msVerbose"))) {Rprintf("%5.3f: ", crit);for (j = 0; j < GS->p; j++) Rprintf("%#10g ", ans[j]);Rprintf("\n");}if (tmp < crit) Memcpy(fixed, ans, GS->p);Free(ans); Free(md); Free(w);Free(work); Free(wtd); Free(z);return fixed;}/* Gauss-Hermite Quadrature x positions and weights */static const doubleGHQ_x1[1] = {0},GHQ_w1[1] = {1},GHQ_x2[1] = {1},GHQ_w2[1] = {0.5},GHQ_x3[2] = {1.7320507779261, 0},GHQ_w3[2] = {0.166666666666667, 0.666666666666667},GHQ_x4[2] = {2.3344141783872, 0.74196377160456},GHQ_w4[2] = {0.0458758533899086, 0.454124131589555},GHQ_x5[3] = {2.85696996497785, 1.35562615677371, 0},GHQ_w5[3] = {0.0112574109895360, 0.222075915334214,0.533333317311434},GHQ_x6[3] = {3.32425737665988, 1.88917584542184,0.61670657963811},GHQ_w6[3] = {0.00255578432527774, 0.0886157433798025,0.408828457274383},GHQ_x7[4] = {3.7504396535397, 2.36675937022918,1.15440537498316, 0},GHQ_w7[4] = {0.000548268839501628, 0.0307571230436095,0.240123171391455, 0.457142843409801},GHQ_x8[4] = {4.14454711519499, 2.80248581332504,1.63651901442728, 0.539079802125417},GHQ_w8[4] = {0.000112614534992306, 0.0096352198313359,0.117239904139746, 0.373012246473389},GHQ_x9[5] = {4.51274578616743, 3.20542894799789,2.07684794313409, 1.02325564627686, 0},GHQ_w9[5] = {2.23458433364535e-05, 0.00278914123744297,0.0499164052656755, 0.244097495561989,0.406349194142045},GHQ_x10[5] = {4.85946274516615, 3.58182342225163,2.48432579912153, 1.46598906930182,0.484935699216176},GHQ_w10[5] = {4.31065250122166e-06, 0.000758070911538954,0.0191115799266379, 0.135483698910192,0.344642324578594},GHQ_x11[6] = {5.18800113558601, 3.93616653976536,2.86512311160915, 1.87603498804787,0.928868981484148, 0},GHQ_w11[6] = {8.12184954622583e-07, 0.000195671924393029,0.0067202850336527, 0.066138744084179,0.242240292596812, 0.36940835831095};static const double*GHQ_x[12] = {(double *) NULL, GHQ_x1, GHQ_x2, GHQ_x3, GHQ_x4,GHQ_x5, GHQ_x6, GHQ_x7, GHQ_x8, GHQ_x9, GHQ_x10,GHQ_x11},*GHQ_w[12] = {(double *) NULL, GHQ_w1, GHQ_w2, GHQ_w3, GHQ_w4,GHQ_w5, GHQ_w6, GHQ_w7, GHQ_w8, GHQ_w9, GHQ_w10,GHQ_w11};/* Externally accessible functions *//*** Simulate a sample of random matrices from a Wishart distribution** @param ns Number of samples to generate* @param dfp Degrees of freedom* @param scal Positive-definite scale matrix** @return*/SEXPMatrix_rWishart(SEXP ns, SEXP dfp, SEXP scal){SEXP ans;int *dims = INTEGER(getAttrib(scal, R_DimSymbol)), j,n = asInteger(ns), psqr;double *scCp, *tmp, df = asReal(dfp), one = 1, zero = 0;if (!isMatrix(scal) || !isReal(scal) || dims[0] != dims[1])error("scal must be a square, real matrix");if (n <= 0) n = 1;psqr = dims[0] * dims[0];tmp = Calloc(psqr, double);AZERO(tmp, psqr);scCp = Memcpy(Calloc(psqr, double), REAL(scal), psqr);F77_CALL(dpotrf)("U", &(dims[0]), scCp, &(dims[0]), &j);if (j)error("scal matrix is not positive-definite");PROTECT(ans = alloc3Darray(REALSXP, dims[0], dims[0], n));GetRNGstate();for (j = 0; j < n; j++) {double *ansj = REAL(ans) + j * psqr;std_rWishart_factor(df, dims[0], tmp);F77_CALL(dtrmm)("R", "U", "N", "N", dims, dims,&one, scCp, dims, tmp, dims);F77_CALL(dsyrk)("U", "T", &(dims[1]), &(dims[1]),&one, tmp, &(dims[1]),&zero, ansj, &(dims[1]));internal_symmetrize(ansj, dims[0]);}PutRNGstate();Free(scCp); Free(tmp);UNPROTECT(1);return ans;}/*** Perform the PQL optimization** @param GSp pointer to a GlmerStruct object** @return R_NilValue*/SEXP glmer_PQL(SEXP GSp){GlmerStruct GS = (GlmerStruct) R_ExternalPtrAddr(GSp);int i; double crit;Memcpy(GS->etaold, REAL(GS->eta), GS->n);for (i = 0, crit = GS->tol + 1;i < GS->maxiter && crit > GS->tol; i++) {internal_glmer_reweight(GS);if (!i) mer_initial(GS->mer); /* initialize first fit */internal_ECMEsteps(GS->mer, i ? 2 : GS->niterEM,GS->EMverbose);eval(GS->LMEopt, GS->rho);internal_mer_fitted(GS->mer, GS->X, GS->Zt, GS->offset, REAL(GS->eta));crit = conv_crit(GS->etaold, REAL(GS->eta), GS->n);}if (crit > GS->tol)warning(_("IRLS iterations for PQL did not converge"));return R_NilValue;}#if 0SEXP glmer_bhat(SEXP pars, SEXP GSp){GlmerStruct GS = (GlmerStruct) R_ExternalPtrAddr(GSp);if (!isReal(pars) || LENGTH(pars) != GS->npar)error(_("`%s' must be a numeric vector of length %d"),"pars", GS->npar);if (!internal_bhat(GS, REAL(pars), REAL(pars) + (GS->p)))warning(_("internal_bhat did not converge"));return R_NilValue;}#endif/*** Compute the Laplace approximation to the deviance.** @param pars pointer to a numeric vector of parameters* @param GSp pointer to a GlmerStruct object** @return the Laplace approximation to the deviance*/SEXP glmer_devLaplace(SEXP pars, SEXP GSp){GlmerStruct GS = (GlmerStruct) R_ExternalPtrAddr(GSp);SEXP Omega = GET_SLOT(GS->mer, Matrix_OmegaSym);int *Gp = INTEGER(GET_SLOT(GS->mer, Matrix_GpSym)),*nc = INTEGER(GET_SLOT(GS->mer, Matrix_ncSym));double *bhat = REAL(GET_SLOT(GS->mer, Matrix_ranefSym)),*dcmp = REAL(GET_SLOT(GS->mer, Matrix_devCompSym)),*dev = REAL(GET_SLOT(GS->mer, Matrix_devianceSym));if (!isReal(pars) || LENGTH(pars) != GS->npar)error(_("`%s' must be a numeric vector of length %d"),"pars", GS->npar);if (!internal_bhat(GS, REAL(pars), REAL(pars) + (GS->p)))return ScalarReal(DBL_MAX);dev[0] = dcmp[4] - dcmp[5] + random_effects_deviance(GS) +b_quadratic(bhat, Omega, Gp, nc);dev[1] = NA_REAL;return ScalarReal(dev[0]);}/*** Compute the approximation to the deviance using adaptive* Gauss-Hermite quadrature (AGQ). When nAGQ == 1 this is the Laplace* approximation.** @param pars pointer to a numeric vector of parameters* @param GSp pointer to a GlmerStruct object* @param nAGQp pointer to a scalar integer representing the number of* points in AGQ to use** @return the approximation to the deviance as computed using AGQ*/SEXP glmer_devAGQ(SEXP pars, SEXP GSp, SEXP nAGQp){GlmerStruct GS = (GlmerStruct) R_ExternalPtrAddr(GSp);SEXP Omega = GET_SLOT(GS->mer, Matrix_OmegaSym),bVar = GET_SLOT(GS->mer, Matrix_bVarSym);int i, j, k, nAGQ = asInteger(nAGQp);int n2 = (nAGQ + 1)/2,*Gp = INTEGER(GET_SLOT(GS->mer, Matrix_GpSym)),*nc = INTEGER(GET_SLOT(GS->mer, Matrix_ncSym));double *f0, LaplaceDev = 0, AGQadjst = 0,*bhat = REAL(GET_SLOT(GS->mer, Matrix_ranefSym));if (!isReal(pars) || LENGTH(pars) != GS->npar)error(_("`%s' must be a numeric vector of length %d"),"pars", GS->npar);if (GS->nf > 1 && nAGQ > 1) {warning(_("AGQ not available for multiple grouping factors - using Laplace"));nAGQ = 1;}if (!internal_bhat(GS, REAL(pars), REAL(pars) + (GS->p)))return ScalarReal(DBL_MAX);for (i = 0; i < GS->nf; i++) {int nci = nc[i];int ncip1 = nci + 1, ncisqr = nci * nci,nlev = (Gp[i + 1] - Gp[i])/nci;double *omgf = REAL(GET_SLOT(dpoMatrix_chol(VECTOR_ELT(Omega, i)), Matrix_xSym)),*bVi = Memcpy(Calloc(ncisqr * nlev, double),REAL(VECTOR_ELT(bVar, i)), ncisqr * nlev);for (j = 0; j < nci; j++) { /* nlev * logDet(Omega_i) */LaplaceDev += 2 * nlev * log(omgf[j * ncip1]);}for (k = 0; k < nlev; k++) {double *bVik = bVi + k * ncisqr;F77_CALL(dpotrf)("U", &nci, bVik, &nci, &j);if (j)error(_("Leading %d minor of bVar[[%d]][,,%d] not positive definite"),j, i + 1, k + 1);for (j = 0; j < nci; j++) LaplaceDev -= 2 * log(bVik[j * ncip1]);}f0 = Calloc(nlev, double);rel_dev_1(GS, bhat, nlev, nci, i, (double *) NULL,omgf, bVi, f0);for (k = 0; k < nlev; k++) LaplaceDev += f0[k];if (nAGQ > 1) {double *fx = Calloc(nlev, double),*rellik = Calloc(nlev, double),*delb = Calloc(nci, double);if (nci > 1) error(_("code not yet written"));AZERO(rellik, nlev); /* zero accumulator */for (k = 0; k < n2; k++) {delb[0] = GHQ_x[nAGQ][k];if (delb[0]) {rel_dev_1(GS, bhat, nlev, nci, i, delb,omgf, bVi, fx);for (j = 0; j < nlev; j++) {rellik[j] += GHQ_w[nAGQ][k] *exp(-(fx[j] - f0[j])/2);}delb[0] *= -1;rel_dev_1(GS, bhat, nlev, nci, i, delb,omgf, bVi, fx);for (j = 0; j < nlev; j++) {rellik[j] += GHQ_w[nAGQ][k] *exp(-(fx[j] - f0[j])/2);}} else {for (j = 0; j < nlev; j++)rellik[j] += GHQ_w[nAGQ][k];}}for (j = 0; j < nlev; j++)AGQadjst -= 2 * log(rellik[j]);Free(fx); Free(rellik);}Free(f0); Free(bVi);}return ScalarReal(LaplaceDev + AGQadjst);}/*** Release the storage for a GlmerStruct** @param GSp External pointer to a GlmerStruct** @return R_NilValue*/SEXP glmer_finalize(SEXP GSp) {GlmerStruct GS = (GlmerStruct) R_ExternalPtrAddr(GSp);Free(GS->w); Free(GS->X); Free(GS->y); Free(GS->z);Free(GS->Zt); Free(GS->off); Free(GS->offset); Free(GS->wts);Free(GS->etaold);Free(GS);return R_NilValue;}/*** Determine the conditional modes and the conditional variance of the* fixed effects given the data and the current random effects.* Create a Metropolis-Hasting proposal step from the multivariate* normal density, determine the acceptance probability and return the* current value or the proposed value.** @param GSp pointer to a GlmerStruct* @param b list of random effects* @param fixed current value of the fixed effects** @return updated value of the fixed effects*/SEXP glmer_fixed_update(SEXP GSp, SEXP b, SEXP fixed){GlmerStruct GS = (GlmerStruct) R_ExternalPtrAddr(GSp);if (!isReal(fixed) || LENGTH(fixed) != GS->p)error(_("%s must be a %s of length %d"), "fixed","numeric vector", GS->p);GetRNGstate();internal_glmer_fixef_update(GS, b, REAL(fixed));PutRNGstate();return fixed;}/*** Return an external pointer object to a GlmerStruct created in* environment rho** @param rho An environment** @return An external pointer to a GlmerStruct*/SEXP glmer_init(SEXP rho) {GlmerStruct GS;SEXP tmp, y, Ztx;GS = (GlmerStruct) Calloc(1, glmer_struct);if (!isEnvironment(rho))error(_("`rho' must be an environment"));GS->rho = rho;GS->mer = find_and_check(rho, install("mer"), VECSXP, 0);y = GET_SLOT(GS->mer, Matrix_ySym);GS->n = LENGTH(y);GS->p = LENGTH(GET_SLOT(GS->mer, Matrix_rXySym));GS->X = Memcpy(Calloc(GS->n * GS->p, double),REAL(GET_SLOT(GS->mer, Matrix_XSym)), GS->n * GS->p);GS->y = Memcpy(Calloc(GS->n, double), REAL(y), GS->n);GS->w = Calloc(GS->n, double);GS->z = Calloc(GS->n, double);Ztx = GET_SLOT(GET_SLOT(GS->mer, Matrix_ZtSym), Matrix_xSym);GS->Zt = Memcpy(Calloc(LENGTH(Ztx), double), REAL(Ztx), LENGTH(Ztx));GS->mu = find_and_check(rho, install("mu"), REALSXP, GS->n);tmp = find_and_check(rho, install("offset"), REALSXP, GS->n);GS->offset = Memcpy(Calloc(GS->n, double), REAL(tmp), GS->n);tmp = find_and_check(rho, install("wts"), REALSXP, GS->n);GS->wts = Memcpy(Calloc(GS->n, double), REAL(tmp), GS->n);GS->off = Calloc(GS->n, double);GS->etaold = Calloc(GS->n, double);GS->cv = find_and_check(rho, install("cv"), VECSXP, 0);GS->niterEM = asInteger(Matrix_getElement(GS->cv, "niterEM"));GS->EMverbose = asLogical(Matrix_getElement(GS->cv, "EMverbose"));GS->tol = asReal(Matrix_getElement(GS->cv, "tolerance"));GS->maxiter = asInteger(Matrix_getElement(GS->cv, "maxIter"));GS->nf = LENGTH(GET_SLOT(GS->mer, Matrix_flistSym));GS->npar = GS->p +coef_length(GS->nf, INTEGER(GET_SLOT(GS->mer, Matrix_ncSym)));GS->eta = find_and_check(rho, install("eta"), REALSXP, GS->n);GS->linkinv = find_and_check(rho, install("linkinv"),LANGSXP, 0);GS->mu_eta = find_and_check(rho, install("mu.eta"),LANGSXP, 0);GS->var = find_and_check(rho, install("variance"),LANGSXP, 0);GS->LMEopt = find_and_check(rho, install("doLMEopt"),LANGSXP, 0);GS->dev_resids = find_and_check(rho, install("dev.resids"),LANGSXP, 0);return R_MakeExternalPtr(GS, R_NilValue, GS->mer);}/*** Determine the conditional modes and the conditional variance of the* random effects given the data and the current fixed effects and* variance components.** Create a Metropolis-Hasting proposal step from a multivariate* normal density centered at bhat with variance-covariance matrix* from bVar, determine the acceptance probability and return the* current value or the proposed value.** @param GSp pointer to a GlmerStruct* @param fixed pointer to a numeric vector of the fixed effects* @param varc pointer to a numeric vector of the variance components* @param varc pointer to current values of b** @return updated b from the Metropolis-Hastings step*/SEXP glmer_ranef_update(SEXP GSp, SEXP fixed, SEXP varc, SEXP b){GlmerStruct GS = (GlmerStruct) R_ExternalPtrAddr(GSp);int nvarc = GS->npar - GS->p;if (!isReal(fixed) || LENGTH(fixed) != GS->p)error(_("`%s' must be a numeric vector of length %d"),"fixed", GS->p);if (INTEGER(GET_SLOT(GS->mer, Matrix_ncSym))[GS->nf] > 0)error(_("the mer object must be set to skip fixed effects"));if (!isReal(varc) || LENGTH(varc) != nvarc)error(_("`%s' must be a numeric vector of length %d"),"varc", nvarc);GetRNGstate();/* Don't check for convergence failure after internal_bhat.* It is determining the mean of the proposal density and* does not need exact convergence. */internal_bhat(GS, REAL(fixed), REAL(varc));internal_glmer_ranef_update(GS, b);PutRNGstate();UNPROTECT(1);return b;}/*** Perform ECME steps for the REML or ML criterion.** @param x pointer to an mer object* @param nsteps pointer to an integer scalar - the number of ECME* steps to perform* @param Verbp pointer to a logical scalar indicating verbose output** @return R_NilValue*/SEXP mer_ECMEsteps(SEXP x, SEXP nsteps, SEXP Verbp){int nstp = asInteger(nsteps);if (nstp > 0) internal_ECMEsteps(x, nstp, asLogical(Verbp));return R_NilValue;}/*** Fill in five symmetric matrices, providing the information to* generate the Hessian.** @param x pointer to an mer object** @return an array consisting of five symmetric faces*/SEXP mer_Hessian(SEXP x){SEXPD = GET_SLOT(x, Matrix_DSym),Omega = GET_SLOT(x, Matrix_OmegaSym),RZXP = GET_SLOT(x, Matrix_RZXSym),gradComp = GET_SLOT(x, Matrix_gradCompSym),val;int *dRZX = INTEGER(getAttrib(RZXP, R_DimSymbol)),*nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),*Gp = INTEGER(GET_SLOT(x, Matrix_GpSym)),Q, Qsqr, RZXpos, facepos,i, ione = 1, j, nf = length(Omega), p = dRZX[1] - 1, pos;double*RZX = REAL(RZXP),*b = REAL(RZXP) + dRZX[0] * p,*bbface, /* vec of second faces of gradComp elts */one = 1.,zero = 0.;mer_gradComp(x);Q = 0; /* number of rows and columns in the result */for (i = 0; i < nf; i++) Q += nc[i] * nc[i];Qsqr = Q * Q;bbface = Calloc(Q, double);val = PROTECT(alloc3Darray(REALSXP, Q, Q, 5));AZERO(REAL(val), Qsqr * 5);pos = 0;for (i = 0; i < nf; i++) {int nci = nc[i];int ncisqr = nci * nci;double *fDi = REAL(VECTOR_ELT(gradComp, i)),mult = 1./((double)(Gp[i + 1] - Gp[i])/nci);Memcpy(bbface + pos, fDi + ncisqr, ncisqr);/* outer product of the third face of gradComp on the diagonal* of the third face of val */F77_CALL(dsyr)("U", &ncisqr, &mult, fDi + 2 * ncisqr, &ione,REAL(val) + 2 * Qsqr + pos * Q, &Q);pos += ncisqr;}/* fifth face is outer product of bbface */F77_CALL(dsyr)("U", &Q, &one, bbface, &ione, REAL(val) + 4 * Qsqr, &Q);/* fourth face from \bb\trans\der\vb\der\bb */AZERO(REAL(val) + 3 * Qsqr, Qsqr); /* zero accumulator */RZXpos = 0;facepos = 0;for (i = 0; i < nf; i++) {int ii, jj, nci = nc[i];int ncisqr = nci * nci, nctp = nci * p,nlev = (Gp[i + 1] - Gp[i])/nci;int maxpq = (p > nci) ? p : nci;double*Di = REAL(VECTOR_ELT(D, i)),*arr = Calloc(ncisqr * maxpq, double), /* tmp 3Darray */*face = REAL(val) + 3 * Qsqr,*mat = Calloc(nci * maxpq, double); /* tmp matrix */for (j = 0; j < nlev; j++) {F77_CALL(dgemm)("T", "T", &p, &nci, &nci,&one, RZX + j * nci, dRZX, Di + j * ncisqr, &nci,&zero, mat, &p);F77_CALL(dgemm)("N", "N", &nctp, &nci, &ione,&one, mat, &nctp, b + j * nci, &ione,&zero, arr, &nctp);F77_CALL(dsyrk)("U", "T", &ncisqr, &p, &one, arr, &p,&one, face + facepos, &Q);/* Add the D_{i,j}^{-T/2} term */Memcpy(mat, Di + j * ncisqr, ncisqr);for (jj = 1; jj < nci; jj++) { /* transpose mat */for (ii = 0; ii < jj; ii++) {mat[jj + ii * nci] = mat[ii + jj * nci];mat[ii + jj * nci] = 0.;}}F77_CALL(dgemm)("N", "N", &ncisqr, &nci, &ione,&one, mat, &ncisqr, b + j * nci, &ione,&zero, arr, &ncisqr);/* FIXME: Next call could be dsyr (it's rank one). */F77_CALL(dsyrk)("U", "T", &ncisqr, &nci, &one, arr, &nci,&one, face + facepos, &Q);}RZXpos += nci * nlev;facepos += ncisqr;Free(arr); Free(mat);}UNPROTECT(2);Free(bbface);return val;}/*** Generate a Markov-Chain Monte Carlo sample from a fitted* linear mixed model.** @param mer pointer to an mer object* @param savebp pointer to a logical scalar indicating if the* random-effects should be saved* @param nsampp pointer to an integer scalar of the number of samples* to generate* @param transp pointer to an logical scalar indicating if the* variance components should be transformed.** @return a matrix*/SEXPmer_MCMCsamp(SEXP x, SEXP savebp, SEXP nsampp, SEXP transp){SEXP ans, Omega = GET_SLOT(x, Matrix_OmegaSym),Omegacp = PROTECT(duplicate(Omega));cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym));int *Gp = INTEGER(GET_SLOT(x, Matrix_GpSym)),*nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),REML = !strcmp(CHAR(asChar(GET_SLOT(x, Matrix_methodSym))), "REML"),i, ione = 1, j, n = LENGTH(GET_SLOT(x, Matrix_ySym)),nf = LENGTH(Omega), nsamp = asInteger(nsampp),p = LENGTH(GET_SLOT(x, Matrix_rXySym)),q = LENGTH(GET_SLOT(x, Matrix_rZySym)),saveb = asLogical(savebp),trans = asLogical(transp);double*RXX = REAL(GET_SLOT(GET_SLOT(x, Matrix_RXXSym), Matrix_xSym)),*RZX = REAL(GET_SLOT(GET_SLOT(x, Matrix_RZXSym), Matrix_xSym)),*bhat = REAL(GET_SLOT(x, Matrix_ranefSym)),*betahat = REAL(GET_SLOT(x, Matrix_fixefSym)),*bnew = Calloc(q, double), *betanew = Calloc(p, double),*dcmp = REAL(GET_SLOT(x, Matrix_devCompSym)),df = n - (REML ? p : 0), m1[] = {-1,0}, one[] = {1,0};int nrbase = p + 1 + coef_length(nf, nc); /* rows always included */int nrtot = nrbase + (saveb ? q : 0);cholmod_dense *chb, *chbnew = numeric_as_chm_dense(bnew, q);if (nsamp <= 0) nsamp = 1;ans = PROTECT(allocMatrix(REALSXP, nrtot, nsamp));GetRNGstate();for (i = 0; i < nsamp; i++) {double *col = REAL(ans) + i * nrtot, sigma;/* factor x and get secondary values */mer_factor(x);mer_secondary(x);/* simulate and store new value of sigma */sigma = exp(dcmp[3]/2)/sqrt(rchisq(df));col[p] = (trans ? 2 * log(sigma) : sigma * sigma);/* simulate scaled, independent normals */for (j = 0; j < p; j++) betanew[j] = sigma * norm_rand();for (j = 0; j < q; j++) bnew[j] = sigma * norm_rand();/* betanew := RXX^{-1} %*% betanew */F77_CALL(dtrsv)("U", "N", "N", &p, RXX, &p, betanew, &ione);/* bnew := bnew - RZX %*% betanew */F77_CALL(dgemv)("N", &q, &p, m1, RZX, &q, betanew, &ione,one, bnew, &ione);/* chb := L^{-T} %*% bnew */chb = cholmod_solve(CHOLMOD_Lt, L, chbnew, &c);/* Copy chb to bnew and free chb */Memcpy(bnew, (double *)(chb->x), q);cholmod_free_dense(&chb, &c);/* Add conditional modes and store beta */for (j = 0; j < p; j++) {col[j] = (betanew[j] += betahat[j]);}/* Add conditional modes and* optionally store b */for (j = 0; j < q; j++) {bnew[j] += bhat[j];if (saveb) col[nrbase + j] = bnew[j];}/* Update and store variance-covariance of the random effects */internal_Omega_update(Omega, bnew, sigma, nf, nc, Gp, col + p + 1, trans);}PutRNGstate();Free(betanew); Free(bnew); Free(chbnew);/* Restore original Omega */SET_SLOT(x, Matrix_OmegaSym, Omegacp);mer_factor(x);Free(L);UNPROTECT(2);return ans;}/*** Create a Markov Chain Monte Carlo sample from a fitted generalized* linear mixed model** @param GSpt External pointer to a GlmerStruct* @param b Conditional modes of the random effects at the parameter* estimates* @param fixed Estimates of the fixed effects* @param varc Estimates of the variance components* @param savebp Logical indicator of whether or not to save the* random effects in the MCMC sample* @param nsampp Integer value of the number of samples to generate** @return*/SEXPglmer_MCMCsamp(SEXP GSpt, SEXP b, SEXP fixed, SEXP varc,SEXP savebp, SEXP nsampp){GlmerStruct GS = (GlmerStruct) R_ExternalPtrAddr(GSpt);int i, j, nf = LENGTH(b), nsamp = asInteger(nsampp),p = LENGTH(fixed), q = LENGTH(varc),saveb = asLogical(savebp);int *mcpar, nc = p + q;SEXP ans, mcparSym = install("mcpar");if (nsamp <= 0) nsamp = 1;nc = p + q;if (saveb)for (i = 0; i < nf; i++) {int *dims = INTEGER(getAttrib(VECTOR_ELT(b, i),R_DimSymbol));nc += dims[0] * dims[1];}ans = PROTECT(allocMatrix(REALSXP, nsamp, nc));GetRNGstate();for (i = 0; i < nsamp; i++) {internal_glmer_fixef_update(GS, b, REAL(fixed));internal_bhat(GS, REAL(fixed), REAL(varc));internal_glmer_ranef_update(GS, b);/* internal_Omega_update(GS->mer, b); */internal_mer_coef(GS->mer, 2, REAL(varc));for (j = 0; j < p; j++)REAL(ans)[i + j * nsamp] = REAL(fixed)[j];for (j = 0; j < q; j++)REAL(ans)[i + (j + p) * nsamp] = REAL(varc)[j];if (saveb) {int base = p + q, k;for (k = 0; k < nf; k++) {SEXP bk = VECTOR_ELT(b, k);int *dims = INTEGER(getAttrib(bk, R_DimSymbol));int klen = dims[0] * dims[1];for (j = 0; j < klen; j++)REAL(ans)[i + (j + base) * nsamp] = REAL(bk)[j];base += klen;}}}PutRNGstate();UNPROTECT(1);/* set (S3) class and mcpar attribute */setAttrib(ans, R_ClassSymbol, mkString("mcmc"));setAttrib(ans, mcparSym, allocVector(INTSXP, 3));mcpar = INTEGER(getAttrib(ans, mcparSym));mcpar[0] = mcpar[2] = 1;mcpar[1] = nsamp;return ans;}/*** Create an mer object from a list of grouping factors and a list of model* matrices.** @param fl named list of grouping factors* @param Ztl list of transposes of model matrices* @param Xp model matrix for the fixed effects* @param yp response vector* @param method character vector describing the estimation method** @return pointer to an mer object*/SEXP mer_create(SEXP fl, SEXP ZZt, SEXP Xp, SEXP yp, SEXP method,SEXP ncp, SEXP cnames, SEXP useS, SEXP call,SEXP family){SEXP Omega, bVar, gradComp, fnms = getAttrib(fl, R_NamesSymbol),val = PROTECT(NEW_OBJECT(MAKE_CLASS("mer"))), xnms;cholmod_sparse *ts1, *ts2, *Zt;cholmod_factor *F;int *nc = INTEGER(ncp), *Gp, *xdims, i,nf = LENGTH(fl), nobs = LENGTH(yp), p, q;char *devCmpnms[] = {"n", "p", "yty", "logryy2", "logDetL2","logDetOmega", "logDetRXX", ""};char *devnms[] = {"ML", "REML", ""};char *statusnms[] ={"factored", "secondary", "gradComp", "Hesscomp", ""};double *dcmp;/* Check arguments to be duplicated */if (!isReal(yp)) error(_("yp must be a real vector"));SET_SLOT(val, Matrix_ySym, duplicate(yp));if (!isMatrix(Xp) || !isReal(Xp))error(_("Xp must be a real matrix"));xdims = INTEGER(getAttrib(Xp, R_DimSymbol));if (xdims[0] != nobs) error(_("Xp must have %d rows"), nobs);p = xdims[1];xnms = VECTOR_ELT(getAttrib(Xp, R_DimNamesSymbol), 1);SET_SLOT(val, Matrix_XSym, duplicate(Xp));if (!isNewList(fl) || nf < 1) error(_("fl must be a nonempty list"));for (i = 0; i < nf; i++) {SEXP fli = VECTOR_ELT(fl, i);if (!isFactor(fli) || LENGTH(fli) != nobs)error(_("fl[[%d] must be a factor of length %d"), i+1, nobs);}SET_SLOT(val, Matrix_flistSym, duplicate(fl));if (!isString(method) || LENGTH(method) != 1)error(_("method must be a character vector of length 1"));SET_SLOT(val, Matrix_methodSym, duplicate(method));if (!isLogical(useS) || LENGTH(useS) != 1)error(_("useS must be a logical vector of length 1"));SET_SLOT(val, Matrix_useScaleSym, duplicate(useS));if (!isNewList(cnames) || LENGTH(cnames) != nf + 1)error(_("cnames must be a list of length %d"), nf + 1);SET_SLOT(val, Matrix_cnamesSym, duplicate(cnames));if (!isInteger(ncp) || LENGTH(ncp) != nf)error(_("ncp must be an integer vector of length %d"), nf);SET_SLOT(val, Matrix_callSym, duplicate(call));SET_SLOT(val, Matrix_familySym, duplicate(family));SET_SLOT(val, Matrix_ncSym, duplicate(ncp));Gp = INTEGER(ALLOC_SLOT(val, Matrix_GpSym, INTSXP, nf + 1));Gp[0] = 0;if (!isNewList(fl) || nf < 1) error(_("fl must be a nonempty list"));for (i = 0; i < nf; i++) {SEXP fli = VECTOR_ELT(fl, i);if (!isFactor(fli) || LENGTH(fli) != nobs)error(_("fl[[%d] must be a factor of length %d"), i+1, nobs);}SET_SLOT(val, Matrix_ZtSym, duplicate(ZZt));Zt = as_cholmod_sparse(GET_SLOT(val, Matrix_ZtSym));/* analyze Zt */q = Zt->nrow;i = c.supernodal;c.supernodal = CHOLMOD_SUPERNODAL; /* force a supernodal decomposition */F = cholmod_analyze(Zt, &c);c.supernodal = i;ts1 = cholmod_aat(Zt, (int*)NULL/* fset */,(size_t)0,CHOLMOD_PATTERN, &c);ts2 = cholmod_copy(ts1, 1/*upper triangle*/, CHOLMOD_PATTERN, &c);SET_SLOT(val, Matrix_ZtZSym,alloc_dsCMatrix(q, cholmod_nnz(ts2, &c), "U", R_NilValue,R_NilValue));cholmod_free_sparse(&ts1, &c); cholmod_free_sparse(&ts2, &c);/* allocate other slots */SET_SLOT(val, Matrix_devianceSym, Matrix_make_named(REALSXP, devnms));SET_SLOT(val, Matrix_devCompSym, Matrix_make_named(REALSXP, devCmpnms));SET_SLOT(val, Matrix_statusSym, Matrix_make_named(LGLSXP, statusnms));AZERO(LOGICAL(GET_SLOT(val, Matrix_statusSym)), 4);dcmp = REAL(GET_SLOT(val, Matrix_devCompSym));AZERO(dcmp, 7); /* cosmetic */dcmp[0] = (double) nobs;dcmp[1] = (double) p;/* allocate and populate list slots */Omega = ALLOC_SLOT(val, Matrix_OmegaSym, VECSXP, nf);bVar = ALLOC_SLOT(val, Matrix_bVarSym, VECSXP, nf);gradComp = ALLOC_SLOT(val, Matrix_gradCompSym, VECSXP, nf);setAttrib(Omega, R_NamesSymbol, duplicate(fnms));setAttrib(bVar, R_NamesSymbol, duplicate(fnms));setAttrib(gradComp, R_NamesSymbol, duplicate(fnms));for (i = 0; i < nf; i++) {int nci = nc[i];int nlev = LENGTH(getAttrib(VECTOR_ELT(fl, i), R_LevelsSymbol));SET_VECTOR_ELT(Omega, i,alloc_dpoMatrix(nci, "U",VECTOR_ELT(cnames, i),VECTOR_ELT(cnames, i)));SET_VECTOR_ELT(bVar, i, alloc3Darray(REALSXP, nci, nci, nlev));SET_VECTOR_ELT(gradComp, i, alloc3Darray(REALSXP, nci, nci, 4));Gp[i + 1] = Gp[i] + nlev * nci;}/* create ZtX, RZX, XtX, RXX */SET_SLOT(val, Matrix_ZtXSym, alloc_dgeMatrix(q, p, R_NilValue, xnms));SET_SLOT(val, Matrix_RZXSym, alloc_dgeMatrix(q, p, R_NilValue, xnms));SET_SLOT(val, Matrix_XtXSym, alloc_dpoMatrix(p, "U", xnms, xnms));SET_SLOT(val, Matrix_RXXSym, alloc_dtrMatrix(p, "U", "N", xnms, xnms));SET_SLOT(val, Matrix_ZtySym, allocVector(REALSXP, q));SET_SLOT(val, Matrix_rZySym, allocVector(REALSXP, q));SET_SLOT(val, Matrix_XtySym, allocVector(REALSXP, p));SET_SLOT(val, Matrix_rXySym, allocVector(REALSXP, p));internal_mer_update_ZXy(val, (int*)(F->Perm));Free(Zt);/* secondary slots */SET_SLOT(val, Matrix_ranefSym, allocVector(REALSXP, q));SET_SLOT(val, Matrix_fixefSym, allocVector(REALSXP, p));SET_SLOT(val, Matrix_RZXinvSym, alloc_dgeMatrix(q, p, R_NilValue, xnms));/* initialize */mer_initial(val);/* The next calls are simply to set up the L slot. At present the* factor F is a symbolic factor. We need to force it to become* numeric before allocating the L slot in the object. */internal_mer_Zfactor(val, F);/* One side effect of this call is to set the status as* factored. We need to reset it */LOGICAL(GET_SLOT(val, Matrix_statusSym))[0] = 0;/* Create the dCHMfactor object and store it in the L slot. This* also frees the storage. */SET_SLOT(val, Matrix_LSym, chm_factor_to_SEXP(F, 1));/* OK, done now. */UNPROTECT(1);return val;}/*** Extract parameters from the Omega matrices. These aren't* "coefficients" but the extractor is called coef for historical* reasons. Within each group these values are in the order of the* diagonal entries first then the strict upper triangle in row* order.** The parameters can be returned in three forms:* 0 - nonlinearly constrained - elements of the relative precision matrix* 1 - unconstrained - from the LDL' decomposition - logarithms of* the diagonal elements of D* 2 - box constrained - also from the LDL' decomposition - inverses* of the diagonal elements of D** @param x pointer to an mer object* @param pType pointer to an integer scalar indicating the form of the* parameters to be returned.** @return numeric vector of the values in the upper triangles of the* Omega matrices*/SEXP mer_coef(SEXP x, SEXP pType){int *nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),nf = LENGTH(GET_SLOT(x, Matrix_OmegaSym));SEXP val = PROTECT(allocVector(REALSXP, coef_length(nf, nc)));internal_mer_coef(x, asInteger(pType), REAL(val));UNPROTECT(1);return val;}/*** Assign the upper triangles of the Omega matrices according to a* vector of parameters.** @param x pointer to an lme object* @param coef pointer to an numeric vector of appropriate length* @param pType pointer to an integer scalar** @return R_NilValue*/SEXP mer_coefGets(SEXP x, SEXP coef, SEXP pType){int clen = coef_length(LENGTH(GET_SLOT(x, Matrix_flistSym)),INTEGER(GET_SLOT(x, Matrix_ncSym)));if (LENGTH(coef) != clen || !isReal(coef))error(_("coef must be a numeric vector of length %d"), clen);internal_mer_coefGets(x, REAL(coef), asInteger(pType));return x;}/*** Return L as a dtCMatrix object** @param x pointer to an mer object** @return L as an dtCMatrix object*/SEXP mer_dtCMatrix(SEXP x){cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym)), *Lcp;cholmod_sparse *Lm;SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dtCMatrix")));int *dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2)),nz, q;dims[0] = dims[1] = q = (int)(L->n);Lcp = cholmod_copy_factor(L, &c); Free(L); /* next call changes Lcp */Lm = cholmod_factor_to_sparse(Lcp, &c); cholmod_free_factor(&Lcp, &c);SET_SLOT(ans, Matrix_uploSym, mkString("L"));SET_SLOT(ans, Matrix_diagSym, mkString("N"));Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_pSym, INTSXP, q + 1)),(int*) Lm->p, q + 1);nz = ((int*)(Lm->p))[q];Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_iSym, INTSXP, nz)),(int*) Lm->i, nz);Memcpy(REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, nz)),(double*) Lm->x, nz);cholmod_free_sparse(&Lm, &c);UNPROTECT(1);return ans;}/*** Return L^{-1} as a dtCMatrix object** @param x pointer to an mer object** @return L^{-1} as an dtCMatrix object*/SEXP mer_dtCMatrix_inv(SEXP x){cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym));cholmod_sparse*b = cholmod_allocate_sparse(L->n, L->n, L->n, 1, 1,0, CHOLMOD_REAL, &c),*Linv;double *bx = (double *)(b->x);SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dtCMatrix")));int *bi = (int *) (b->i), *bp = (int *) (b->p),*dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2)),j, nz, q;dims[0] = dims[1] = q = (int)(L->n);for (j = 0; j < q; j++) {bp[j] = bi[j] = j;bx[j] = 1;}bp[q] = q;Linv = cholmod_spsolve(CHOLMOD_L, L, b, &c);cholmod_free_sparse(&b, &c);SET_SLOT(ans, Matrix_uploSym, mkString("L"));SET_SLOT(ans, Matrix_diagSym, mkString("N"));Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_pSym, INTSXP, q + 1)),(int *) Linv->p, q + 1);nz = ((int *)(Linv->p))[q];Memcpy(INTEGER(ALLOC_SLOT(ans, Matrix_iSym, INTSXP, nz)),(int *) Linv->i, nz);Memcpy(REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, nz)),(double *) Linv->x, nz);cholmod_free_sparse(&Linv, &c);UNPROTECT(1);return ans;}/*** Create and factor Z'Z+Omega. Also create RZX and RXX, the deviance* components, and the value of the deviance for both ML and REML.** @param x pointer to an lmer object** @return NULL*/SEXP mer_factor(SEXP x){int *status = LOGICAL(GET_SLOT(x, Matrix_statusSym));if (!status[0]) {SEXP rXyP = GET_SLOT(x, Matrix_rXySym),rZyP = GET_SLOT(x, Matrix_rZySym);int i, info, ione = 1, p = LENGTH(rXyP), q = LENGTH(rZyP);cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym));double *RXX = REAL(GET_SLOT(GET_SLOT(x, Matrix_RXXSym), Matrix_xSym)),*RZX = REAL(GET_SLOT(GET_SLOT(x, Matrix_RZXSym), Matrix_xSym)),*rXy = REAL(rXyP), *rZy = REAL(rZyP),*dcmp = REAL(GET_SLOT(x, Matrix_devCompSym)),*dev = REAL(GET_SLOT(x, Matrix_devianceSym)),one[2] = {1, 0}, m1[2] = {-1, 0};double nml = dcmp[0], nreml = dcmp[0] - dcmp[1];/* Inflate Z'Z to Z'Z+Omega and factor to form L. Form RZX and* rZy. Update status flags, dcmp[4] and dcmp[5]. */internal_mer_Zfactor(x, L);/* downdate XtX and factor */Memcpy(RXX, REAL(GET_SLOT(GET_SLOT(x, Matrix_XtXSym), Matrix_xSym)), p * p);F77_CALL(dsyrk)("U", "T", &p, &q, m1, RZX, &q, one, RXX, &p);F77_CALL(dpotrf)("U", &p, RXX, &p, &info);if (info) {error(_("Leading minor of order %d in downdated X'X is not positive definite"),info);dcmp[3] = dcmp[6] = dev[0] = dev[1] = NA_REAL;} else {for (dcmp[6] = 0, i = 0; i < p; i++) /* 2 * logDet(RXX) */dcmp[6] += 2. * log(RXX[i * (p + 1)]);/* solve for rXy and ryy^2 */Memcpy(rXy, REAL(GET_SLOT(x, Matrix_XtySym)), p);F77_CALL(dgemv)("T", &q, &p, m1, RZX, &q, rZy, &ione, one, rXy, &ione);F77_CALL(dtrsv)("U", "T", "N", &p, RXX, &p, rXy, &ione);dcmp[3] = log(dcmp[2] /* dcmp[3] = log(ryy^2); dcmp[2] = y'y; */- F77_CALL(ddot)(&p, rXy, &ione, rXy, &ione)- F77_CALL(ddot)(&q, rZy, &ione, rZy, &ione));/* evaluate ML and REML deviance */dev[0] = dcmp[4] - dcmp[5] +nml*(1.+dcmp[3]+log(2.*PI/nml));dev[1] = dcmp[4] - dcmp[5] + dcmp[6] +nreml*(1.+dcmp[3]+log(2.*PI/nreml));}Free(L);}return R_NilValue;}/*** Return the fitted values as an SEXP** @param x pointer to an mer object* @param useFe pointer to a logical scalar indicating if the fixed* effects should be used* @param useRe pointer to a logical scalar indicating if the random* effects should be used** @return pointer to a numeric array of fitted values*/SEXP mer_fitted(SEXP x, SEXP useFe, SEXP useRe){int n = LENGTH(GET_SLOT(x, Matrix_ySym));SEXP ans = PROTECT(allocVector(REALSXP, n));internal_mer_fitted(x,(asLogical(useFe)? REAL(GET_SLOT(x, Matrix_XSym)): (double *) NULL),(asLogical(useRe)? REAL(GET_SLOT(GET_SLOT(x, Matrix_ZtSym), Matrix_xSym)): (double *) NULL),(double *) NULL, REAL(ans));UNPROTECT(1);return ans;}/*** Extract the conditional estimates of the fixed effects** @param x Pointer to an mer object** @return a numeric vector containing the conditional estimates of* the fixed effects*/SEXP mer_fixef(SEXP x){int nf = LENGTH(GET_SLOT(x, Matrix_OmegaSym));SEXP ans;mer_secondary(x);ans = PROTECT(duplicate(GET_SLOT(x, Matrix_fixefSym)));setAttrib(ans, R_NamesSymbol,duplicate(VECTOR_ELT(GET_SLOT(x, Matrix_cnamesSym), nf)));UNPROTECT(1);return ans;}/*** Fill in the gradComp and bVar slots. Each component in the gradComp slot* consists of four symmetric matrices used to generate the gradient or the ECME* step. They are* 1) -m_i\bOmega_i^{-1}* 2) \bB_i\bB_i\trans* 3) \tr\left[\der_{\bOmega_i}\bOmega\left(\bZ\trans\bZ+\bOmega\right)\inv\right]* 4) The term added to 3) to get \tr\left[\der_{\bOmega_i}\bOmega\vb\right]** @param x pointer to an mer object* @param val pointer to a list of matrices of the correct sizes** @return NULL*/SEXP mer_gradComp(SEXP x){int *status = LOGICAL(GET_SLOT(x, Matrix_statusSym));mer_secondary(x);if (!status[2]) {SEXP bVarP = GET_SLOT(x, Matrix_bVarSym),OmegaP = GET_SLOT(x, Matrix_OmegaSym),RZXP = GET_SLOT(x, Matrix_RZXSym),gradComp = GET_SLOT(x, Matrix_gradCompSym),ranefP = GET_SLOT(x, Matrix_ranefSym);int q = LENGTH(ranefP), p = LENGTH(GET_SLOT(x, Matrix_rXySym));cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym));cholmod_dense *RZX = as_cholmod_dense(RZXP), *tmp1;int *Gp = INTEGER(GET_SLOT(x, Matrix_GpSym)),*Perm = (int *)(L->Perm),*iperm = Calloc(q, int),*nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),i, j, k, nf = length(OmegaP);double *b = REAL(GET_SLOT(x, Matrix_ranefSym)),*RZXinv = REAL(GET_SLOT(GET_SLOT(x, Matrix_RZXinvSym), Matrix_xSym)),m1[] = {-1, 0}, alpha;alpha = 1./internal_mer_sigma(x, -1);alpha = alpha * alpha;for (j = 0; j < q; j++) iperm[Perm[j]] = j; /* create the inverse permutation *//* form RZXinv, the section of R^{-1} from RZX */tmp1 = cholmod_solve(CHOLMOD_Lt, L, RZX, &c); Free(RZX);/* copy columns of tmp1 to RZXinv applying the inverse permutation */for (j = 0; j < p; j++) {double *dest = RZXinv + j * q, *src = ((double*)(tmp1->x)) + j * q;for (i = 0; i < q; i++) dest[i] = src[iperm[i]];}cholmod_free_dense(&tmp1, &c);F77_CALL(dtrsm)("R", "U", "N", "N", &q, &p, m1,REAL(GET_SLOT(GET_SLOT(x, Matrix_RXXSym), Matrix_xSym)),&p, RZXinv, &q);internal_mer_bVar(x);for (i = 0; i < nf; i++) {int nci = nc[i], RZXrows = Gp[i + 1] - Gp[i];int ncisq = nci * nci, nlev = RZXrows/nci;double *bVi = REAL(VECTOR_ELT(bVarP, i)),*bi = b + Gp[i], *mm = REAL(VECTOR_ELT(gradComp, i)),*tmp = Memcpy(Calloc(ncisq, double),REAL(GET_SLOT(dpoMatrix_chol(VECTOR_ELT(OmegaP, i)),Matrix_xSym)), ncisq),*RZXi = RZXinv + Gp[i],dlev = (double) nlev,one[] = {1,0}, zero[] = {0,0};if (nci == 1) {int ione = 1;mm[0] = ((double) nlev)/(tmp[0] * tmp[0]);mm[1] = alpha * F77_CALL(ddot)(&nlev, bi, &ione, bi, &ione);mm[2] = 0.;for (k = 0; k < nlev; k++) mm[2] += bVi[k];mm[3] = 0.;for (j = 0; j < p; j++) {mm[3] += F77_CALL(ddot)(&RZXrows, RZXi + j * q, &ione,RZXi + j * q, &ione);}} else {AZERO(mm, 4 * ncisq);F77_CALL(dtrtri)("U", "N", &nci, tmp, &nci, &j);if (j)error(_("Omega[[%d]] is not positive definite"), i + 1);F77_CALL(dsyrk)("U", "N", &nci, &nci, &dlev, tmp, &nci,zero, mm, &nci);mm += ncisq; /* \bB_i term */F77_CALL(dsyrk)("U", "N", &nci, &nlev, &alpha, bi, &nci,zero, mm, &nci);mm += ncisq; /* Sum of diagonal blocks of the inverse* (Z'Z+Omega)^{-1} */for (j = 0; j < ncisq; j++) {for (k = 0; k < nlev; k++) mm[j] += bVi[j + k*ncisq];}mm += ncisq; /* Extra term for \vb */for (j = 0; j < p; j++) {F77_CALL(dsyrk)("U", "N", &nci, &nlev, one,RZXi + j * q, &nci,one, mm, &nci);}}Free(tmp);}Free(iperm); Free(L);status[2] = 1; status[3] = 0;}return R_NilValue;}/*** Evaluate the gradient vector** @param x Pointer to an lmer object* @param pType Pointer to an integer indicator of the* parameterization being used** @return pointer to a gradient vector*/SEXP mer_gradient(SEXP x, SEXP pType){SEXP Omega = GET_SLOT(x, Matrix_OmegaSym);SEXP gradComp = GET_SLOT(x, Matrix_gradCompSym);int *nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),dind, i, ifour = 4, ione = 1, nf = length(Omega),odind, ptyp = asInteger(pType);int REML =!strcmp(CHAR(asChar(GET_SLOT(x, Matrix_methodSym))), "REML");SEXP val = PROTECT(allocVector(REALSXP, coef_length(nf, nc)));double cc[] = {-1, 1, 1, REML ? 1 : 0},one = 1.0, zero = 0.0;mer_gradComp(x);dind = 0; /* index into val for diagonals */for (i = 0; i < nf; i++) {SEXP Omgi = VECTOR_ELT(Omega, i);int nci = nc[i], ncisqr = nci * nci;double *tmp = Calloc(ncisqr, double);F77_CALL(dgemm)("N", "N", &ncisqr, &ione, &ifour, &one,REAL(VECTOR_ELT(gradComp, i)), &ncisqr,cc, &ifour, &zero, tmp, &ncisqr);if (nci == 1) {double omg = *REAL(GET_SLOT(Omgi, Matrix_xSym));REAL(val)[dind++] =(ptyp?((ptyp == 1)? omg : -omg * omg) : 1) * tmp[0];} else {int ii, j, ncip1 = nci + 1;odind = dind + nci; /* index into val for off-diagonals */if (ptyp) {double *chol = REAL(GET_SLOT(dpoMatrix_chol(Omgi), Matrix_xSym)),*tmp2 = Calloc(ncisqr, double);/* Overwrite the gradient with respect to positions in* Omega[[i]] by the gradient with respect to the* unconstrained parameters.*//* tmp2 := chol %*% tmp using only upper triangle of tmp */F77_CALL(dsymm)("R", "U", &nci, &nci, &one, tmp, &nci,chol, &nci, &zero, tmp2, &nci);/* full symmetric product gives diagonals */F77_CALL(dtrmm)("R", "U", "T", "N", &nci, &nci, &one, chol,&nci, Memcpy(tmp, tmp2, ncisqr), &nci);/* overwrite upper triangle with gradients for L' */for (ii = 1; ii < nci; ii++) {for (j = 0; j < ii; j++) {tmp[j + ii*nci] = chol[j*ncip1] * tmp2[j + ii*nci];tmp[ii + j*nci] = 0.;}}if (ptyp > 1)for (ii = 0; ii < nci; ii++) {int ind = ii * ncip1;double sqrtd = chol[ind];tmp[ind] *= -(sqrtd*sqrtd);}}for (j = 0; j < nci; j++) {REAL(val)[dind + j] = tmp[j * ncip1];for (ii = 0; ii < j; ii++) /* offdiagonals count twice */REAL(val)[odind++] = 2. * tmp[ii + j * nci];}dind = odind;}Free(tmp);}UNPROTECT(1);return val;}/*** Create and insert initial values for Omega.** @param x pointer to an mer object** @return NULL*/SEXP mer_initial(SEXP x){SEXP Omg = GET_SLOT(x, Matrix_OmegaSym),ZtZ = GET_SLOT(x, Matrix_ZtZSym);int *Gp = INTEGER(GET_SLOT(x, Matrix_GpSym)),*nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),*p = INTEGER(GET_SLOT(ZtZ, Matrix_pSym)),i, nf = length(Omg);double *xx = REAL(GET_SLOT(ZtZ, Matrix_xSym));for (i = 0; i < nf; i++) {SEXP Omgi = VECTOR_ELT(Omg, i);double *omgi = REAL(GET_SLOT(Omgi, Matrix_xSym));int bb = Gp[i], j, k, nci = nc[i];int ncip1 = nci + 1, nlev = (Gp[i + 1] - bb)/nci;AZERO(omgi, nci * nci);for (j = 0; j < nlev; j++) {int base = bb + j * nci;for (k = 0; k < nci; k++)/* add the last element in the column */omgi[k * ncip1] += xx[p[base + k + 1] - 1];}for (k = 0; k < nci; k++) omgi[k * ncip1] *= 0.375/nlev;SET_SLOT(Omgi, Matrix_factorSym, allocVector(VECSXP, 0));dpoMatrix_chol(Omgi);}flag_not_factored(x);return R_NilValue;}/*** Return the permutation of the columns of Z as a pMatrix object** @param x pointer to an mer object** @return the permutation as an pMatrix object*/SEXP mer_pMatrix(SEXP x){cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym));SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("pMatrix")));int *dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2)),*perm = INTEGER(ALLOC_SLOT(ans, Matrix_permSym, INTSXP, L->n)), i;dims[0] = dims[1] = (int) L->n;for (i = 0; i < (int) L->n; i++) perm[i] = ((int *)(L->Perm))[i] + 1;Free(L);UNPROTECT(1);return ans;}/*** Extract the conditional modes of the random effects.** @param x Pointer to an mer object** @return a list of matrices containing the conditional modes of the* random effects*/SEXP mer_ranef(SEXP x){SEXP cnames = GET_SLOT(x, Matrix_cnamesSym),flist = GET_SLOT(x, Matrix_flistSym);int *Gp = INTEGER(GET_SLOT(x, Matrix_GpSym)),*nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),i, ii, jj,nf = length(flist);SEXP val = PROTECT(allocVector(VECSXP, nf));double *b = REAL(GET_SLOT(x, Matrix_ranefSym));mer_secondary(x);setAttrib(val, R_NamesSymbol,duplicate(getAttrib(flist, R_NamesSymbol)));for (i = 0; i < nf; i++) {SEXP nms, rnms = getAttrib(VECTOR_ELT(flist, i), R_LevelsSymbol);int nci = nc[i], mi = length(rnms);double *bi = b + Gp[i], *mm;SET_VECTOR_ELT(val, i, allocMatrix(REALSXP, mi, nci));setAttrib(VECTOR_ELT(val, i), R_DimNamesSymbol, allocVector(VECSXP, 2));nms = getAttrib(VECTOR_ELT(val, i), R_DimNamesSymbol);SET_VECTOR_ELT(nms, 0, duplicate(rnms));SET_VECTOR_ELT(nms, 1, duplicate(VECTOR_ELT(cnames, i)));mm = REAL(VECTOR_ELT(val, i));for (jj = 0; jj < nci; jj++)for(ii = 0; ii < mi; ii++)mm[ii + jj * mi] = bi[jj + ii * nci];}UNPROTECT(1);return val;}/*** Update the secondary slots - fixef and ranef** @param x pointer to a mer object**/SEXP mer_secondary(SEXP x){int *status = LOGICAL(GET_SLOT(x, Matrix_statusSym));mer_factor(x);if (!status[1]) {internal_mer_fixef(x);internal_mer_ranef(x);}return R_NilValue;}/*** Extract the ML or REML conditional estimate of sigma** @param x pointer to an mer object* @param REML logical scalar - TRUE if REML estimates are requested** @return pointer to a numeric scalar*/SEXP mer_sigma(SEXP x, SEXP REML){return ScalarReal(internal_mer_sigma(x,(REML == R_NilValue) ? -1 :(asLogical(REML))));}/*** Simulate a set of linear predictors from the random effects part of* an mer object** @param x Pointer to an mer object* @param np Pointer to an integer giving the number of values to simulate* @param useScale Logical indicator of whether to use the scale** @return a matrix of simulated linear predictors*/SEXP mer_simulate(SEXP x, SEXP nsimP){int *nc = INTEGER(GET_SLOT(x, Matrix_ncSym)),*Gp = INTEGER(GET_SLOT(x, Matrix_GpSym)),REML = !strcmp(CHAR(asChar(GET_SLOT(x, Matrix_methodSym))),"REML"),i, ii, j, nsim = asInteger(nsimP),nf = LENGTH(GET_SLOT(x, Matrix_OmegaSym)),n = LENGTH(GET_SLOT(x, Matrix_ySym)),q = LENGTH(GET_SLOT(x, Matrix_ZtySym));SEXP ans = PROTECT(allocMatrix(REALSXP, n, nsim)),Omega = GET_SLOT(x, Matrix_OmegaSym);cholmod_dense *cha = as_cholmod_dense(ans),*chb = cholmod_allocate_dense(q, nsim, q, CHOLMOD_REAL, &c);double one[] = {1,0}, zero[] = {0,0},scale = (asLogical(GET_SLOT(x, Matrix_useScaleSym)) ?internal_mer_sigma(x, REML) : 1);cholmod_sparse *Zt = as_cholmod_sparse(GET_SLOT(x, Matrix_ZtSym));GetRNGstate();for (ii = 0; ii < nsim; ii++) {for (i = 0; i < nf; i++) {int nci = nc[i], relen = Gp[i + 1] - Gp[i];int nlev = relen/nci;double *bi = (double *)(chb->x) + ii * q + Gp[i],*Rmat = REAL(GET_SLOT(dpoMatrix_chol(VECTOR_ELT(Omega, i)),Matrix_xSym));for (j = 0; j < relen; j++) bi[j] = norm_rand();F77_CALL(dtrsm)("L", "U", "N", "N", &nci, &nlev, &scale,Rmat, &nci, bi, &nci);}}PutRNGstate();if (!cholmod_sdmult(Zt, 1, one, zero, chb, cha, &c))error(_("cholmod_sdmult failed"));cholmod_free_dense(&chb, &c);Free(Zt); Free(cha);UNPROTECT(1);return ans;}/*** Externally callable version of internal_mer_update_ZXy** @param x pointer to an mer object** @return NULL*/SEXP mer_update_ZXy(SEXP x){internal_mer_update_ZXy(x,INTEGER(GET_SLOT(GET_SLOT(x, Matrix_LSym),Matrix_permSym)));return R_NilValue;}/*** Update the y slot (and slots derived from it) in an mer object** @param x pointer to an mer object* @param ynew pointer to a numeric vector of length n** @return NULL*/SEXP mer_update_y(SEXP x, SEXP ynew){SEXP y = GET_SLOT(x, Matrix_ySym),Xty = GET_SLOT(x, Matrix_XtySym),Zty = GET_SLOT(x, Matrix_ZtySym);cholmod_factor *L = as_cholmod_factor(GET_SLOT(x, Matrix_LSym));int *perm = (int*)(L->Perm), i, ione = 1,n = LENGTH(y), p = LENGTH(Xty), q = LENGTH(Zty);cholmod_sparse *Zt = as_cholmod_sparse(GET_SLOT(x, Matrix_ZtSym));cholmod_dense *td1, *yd = as_cholmod_dense(GET_SLOT(x, Matrix_ySym));double one[] = {1,0}, zero[] = {0,0};if (!isReal(ynew) || LENGTH(ynew) != n)error(_("ynew must be a numeric vector of length %d"), n);Memcpy(REAL(y), REAL(ynew), n);/* y'y */REAL(GET_SLOT(x, Matrix_devCompSym))[2] =F77_CALL(ddot)(&n, REAL(y), &ione, REAL(y), &ione);/* PZ'y into Zty */td1 = cholmod_allocate_dense(q, 1, q, CHOLMOD_REAL, &c);if (!cholmod_sdmult(Zt, 0, one, zero, yd, td1, &c))error(_("cholmod_sdmult failed"));for (i = 0; i < q; i++) REAL(Zty)[i] = ((double *)(td1->x))[perm[i]];cholmod_free_dense(&td1, &c); Free(yd); Free(Zt);/* Xty */F77_CALL(dgemv)("T", &n, &p, one, REAL(GET_SLOT(x, Matrix_XSym)),&n, REAL(y), &ione, zero, REAL(Xty), &ione);flag_not_factored(x);Free(L);return R_NilValue;}/*** Check validity of an mer object.** @param x Pointer to an mer object** @return TRUE if the object is a valid lmer object, else a string* describing the nature of the violation.*/SEXP mer_validate(SEXP x){SEXP/* ZZxP = GET_SLOT(x, Matrix_ZZxSym), */ZtXP = GET_SLOT(x, Matrix_ZtXSym),XtXP = GET_SLOT(x, Matrix_XtXSym),RZXP = GET_SLOT(x, Matrix_RZXSym),RXXP = GET_SLOT(x, Matrix_RXXSym)/* , cnames = GET_SLOT(x, Matrix_cnamesSym) */;int *ZtXd = INTEGER(getAttrib(ZtXP, Matrix_DimSym)),*XtXd = INTEGER(getAttrib(XtXP, Matrix_DimSym));if (!match_mat_dims(ZtXd, INTEGER(getAttrib(RZXP, Matrix_DimSym))))return mkString(_("Dimensions of slots ZtX and RZX must match"));if (!match_mat_dims(XtXd, INTEGER(getAttrib(RXXP, Matrix_DimSym))))return mkString(_("Dimensions of slots XtX and RXX must match"));if (ZtXd[1] != XtXd[0] || XtXd[0] != XtXd[1])return mkString(_("Slot XtX must be a square matrix with same ncol as ZtX"));return ScalarLogical(1);}/*** Create the sparse Zt matrix from a factor list and list of model matrices** @param fl list of factors* @param Ztl list of transposes of model matrices** @return a freshly created sparse Zt object*/SEXP Zt_create(SEXP fl, SEXP Ztl){SEXP ans = PROTECT(NEW_OBJECT(MAKE_CLASS("dgCMatrix"))), fi, tmmat;int *dims, *p, *ii, i, nrtot = 0, nf = LENGTH(fl), nobs;int *Gp = Calloc(nf + 1, int), *nr = Calloc(nf, int),*offset = Calloc(nf + 1, int);double *x;if (!isNewList(fl) || nf < 1)error(_("fl must be a non-null list"));if (!isNewList(Ztl) || LENGTH(Ztl) != nf)error(_("Ztl must be a list of length %d"), nf);fi = VECTOR_ELT(fl, 0);nobs = LENGTH(fi);if (!isFactor(fi) || nobs < 1)error(_("fl[[1]] must be a non-empty factor"));offset[0] = Gp[0] = 0;for (i = 0; i < nf; i++) { /* check consistency and establish dimensions */fi = VECTOR_ELT(fl, i); /* grouping factor */if (!isFactor(fi) || LENGTH(fi) != nobs)error(_("fl[[%d]] must be a factor of length %d"), i + 1, nobs);tmmat = VECTOR_ELT(Ztl, i); /* transpose of model matrix */if (!isMatrix(tmmat) || !isReal(tmmat))error(_("Ztl[[%d]] must be real matrix"), i + 1);dims = INTEGER(getAttrib(tmmat, R_DimSymbol));if (dims[1] != nobs)error(_("Ztl[[%d]] must have %d columns"), i + 1, nobs);nrtot += (nr[i] = dims[0]);offset[i + 1] = offset[i] + nr[i];Gp[i + 1] = Gp[i] + dims[0] * LENGTH(getAttrib(fi, R_LevelsSymbol));}dims = INTEGER(ALLOC_SLOT(ans, Matrix_DimSym, INTSXP, 2));dims[0] = Gp[nf]; dims[1] = nobs;p = INTEGER(ALLOC_SLOT(ans, Matrix_pSym, INTSXP, nobs + 1));ii = INTEGER(ALLOC_SLOT(ans, Matrix_iSym, INTSXP, nrtot * nobs));x = REAL(ALLOC_SLOT(ans, Matrix_xSym, REALSXP, nrtot * nobs));p[0] = 0; for(i = 0; i < nobs; i++) p[i + 1] = p[i] + nrtot;for (i = 0; i < nf; i++) { /* fill ans */int *vals = INTEGER(VECTOR_ELT(fl, i)), j;double *xvals = REAL(VECTOR_ELT(Ztl, i));for (j = 0; j < nobs; j++) {int jbase = Gp[i] + nr[i] * (vals[j] - 1), k;for (k = 0; k < nr[i]; k++) {int ind = j * nrtot + offset[i] + k;ii[ind] = jbase + k;x[ind] = xvals[j * nr[i] + k];}}}Free(offset); Free(Gp); Free(nr);UNPROTECT(1);return ans;}