/******************************************************************************************* MUFROMSIGMA PROGRAM - called by mvmeta.ado, mvmeta_lmata.ado and mvmeta_bscov_*.ado *! version 3.5.0 # Ian White # 15nov2021 changed short equation name from "Oveall" to "Overall_mean" to match standard output version 3.1.3 Ian White 21jul2015 also outputs error observation number as $MVMETA_obserror version 3.1.2 Ian White 16jul2015 incorporate id stops with error in non-pos-def S+Sigma is found version 3.0.4 Ian White 15jun2015 correct the calculation with wscorr(riley) version 3.0.1 Ian White 27may2015 14may2015 - corrected bug in ll & rl constants - they now agree with those produced by mvmeta_lmata version 2.0.4 Ian White 1feb2011 - corrects bug in eqnames; gives useful error message with unidentified model version 2.0.5 Ian White 26feb2011 - names mu and varmu in same way as (RE)ML & optionally returns Qscalar *******************************************************************************************/ program mvmeta_mufromsigma syntax, sigma(string) [yhat(string) makeq debug] // yhat() is unused? local debug = 0 *local debug = !mi("`debug'") tempname mu varmu XWXsum sigmamat local add2pi = ("$MVMETA_2pi"=="") local makeq = ("`makeq'"=="makeq") local riley = ("$MVMETA_wscorr"=="riley") if `debug' di as input "mvmeta_mufromsigma `0'" * create string id variable tempvar idstring if mi("$MVMETA_id") { gen `idstring' = strofreal(_n) label var `idstring' "observation" } else { cap confirm string variable $MVMETA_id if !_rc { // id is string gen `idstring' = $MVMETA_id } else { // id is numeric: is it labelled? confirm numeric variable $MVMETA_id if mi("`:value label $MVMETA_id'") gen `idstring' = strofreal($MVMETA_id) else decode $MVMETA_id, gen(`idstring') } label var `idstring' "$MVMETA_id =" } mat `sigmamat' = `sigma' mata: mufromsigma("`sigmamat'", "`mu'", "`varmu'", "`XWXsum'", `add2pi', `makeq', `riley', `debug', "`idstring'") if matmissing(`XWXsum') { di as error "mvmeta_mufromsigma: XWXsum has missing values" exit 499 } if matmissing(`varmu') { di as error "mvmeta_mufromsigma: sum of XWX could not be inverted - is the model identified?" exit 499 } if "$MVMETA_xcons" != "" local xcons _cons // Apply suitable row and column names if "$MVMETA_parmtype"=="common" { local eqs $MVMETA_yvar_1 local names ${MVMETA_xvars_1} `xcons' } else if "$MVMETA_parmtype"=="long" { forvalues r=1/$MVMETA_p { local eqname : word `r' of $MVMETA_ylist foreach xvar in ${MVMETA_xvars_`r'} `xcons' { local eqs `eqs' `eqname' local names `names' `xvar' } } } else if "$MVMETA_parmtype"=="short" { local eqs "Overall_mean" local names $MVMETA_ylist } mat coleq `mu' = `eqs' mat coleq `varmu' = `eqs' mat roweq `varmu' = `eqs' mat colnames `mu' = `names' mat colnames `varmu' = `names' mat rownames `varmu' = `names' tempvar touse gen `touse' = $MVMETA_touse if `debug' { di "mvmeta_mufromsigma: debug is switched on" mat l `sigmamat', title(mvmeta_mufromsigma: sigma) mat l `mu', title(mvmeta_mufromsigma: mu) mat l `varmu', title(mvmeta_mufromsigma: varmu) } ereturn post `mu' `varmu', obs($MVMETA_n) esample(`touse') end mata: void mufromsigma(string scalar Sigmaname, // existing matrix name string scalar muname, // new matrix name string scalar varmuname, // new matrix name string scalar XWXsumname, // new matrix name real scalar add2pi, // 0/1 real scalar makeQ, // 0/1 real scalar riley, // 0/1 real scalar debug, // 0/1 string scalar idvar) { if(debug==1) "Debugging mvmeta_mufromsigma" Sig = st_matrix(Sigmaname) n = strtoreal(st_global("MVMETA_n")) p = rows(Sig) idname = st_varlabel(idvar) touse = st_data(.,st_global("MVMETA_touse")) idlist = st_sdata(.,idvar) obslist = (1..rows(idlist))' // new 21jul2015 idlist = select(idlist,touse) obslist = select(obslist,touse) // new 21jul2015 for(i=1;i<=n;++i) { identifier = idname + " " + idlist[i,1] y = st_matrix(st_global("MVMETA_ymat")+strofreal(i)) if(debug==1) identifier if(debug==1) "y" if(debug==1) y S = st_matrix(st_global("MVMETA_Smat")+strofreal(i)) if(debug==1) "S" if(debug==1) S X = st_matrix(st_global("MVMETA_Xmat")+strofreal(i)) if(debug==1) "X" if(debug==1) X /* Restrict to submatrices with non-missing values */ keep = !colmissing(y) S = select(S,keep) S = select(S,keep') Sigma = select(Sig,keep) Sigma = select(Sigma,keep') X = select(X,keep) y = select(y,keep) V = S+Sigma if (riley) { if(debug==1) "V before Riley-ising" if(debug==1) V V = sqrt(diag(diagonal(V))) V = V*corr(Sigma)*V if(debug==1) "V after Riley-ising" if(debug==1) V } W = cholinv(V) if(debug==1) "W" if(debug==1) W if (missing(W)>0) { errprintf("mvmeta_mufromsigma: error in S+Sigma at "+identifier+":\n") displayas("text") printf("Matrix S:\n") S printf("Matrix Sigma:\n") Sigma errprintf("S+Sigma is not positive definite\n") st_global("MVMETA_obserror",strofreal(obslist[i,1])) // new 21jul2015 exit(506) // New 17jul2015 } if (i==1) { yWXsum = y*W*X' XWXsum = X*W*X' } else { yWXsum = yWXsum + y*W*X' XWXsum = XWXsum + X*W*X' } } varmu = cholinv(XWXsum) if(debug==1) "varmu" if(debug==1) varmu if (missing(varmu)>0) { errprintf("mvmeta_mufromsigma: in Mata, XWXsum (below) could not be inverted\n") XWXsum exit(error(459)) // New 17jul2015 } mu = yWXsum*varmu if(debug==1) "mu" if(debug==1) mu if (makeQ == 1) { /* compute Qscalar */ real matrix Qscalar Qscalar = (0) sum_p = 0 for(i=1;i<=n;++i) { y = st_matrix(st_global("MVMETA_ymat")+strofreal(i)) S = st_matrix(st_global("MVMETA_Smat")+strofreal(i)) X = st_matrix(st_global("MVMETA_Xmat")+strofreal(i)) yhat = mu * X keep = !colmissing(y) S = select(S,keep) S = select(S,keep') yhat = select(yhat,keep) y = select(y,keep) Qscalar = Qscalar + (y-yhat)*cholinv(S)*(y-yhat)' sum_p = sum_p + cols(y) } st_numscalar("r(Qscalar)",Qscalar) st_numscalar("r(sum_p)",sum_p) } st_matrix(muname,mu) st_matrix(varmuname,varmu) st_matrix(XWXsumname,XWXsum) /* extra to return (restricted) loglik */ ll=0 for(i=1;i<=n;++i) { y = st_matrix(st_global("MVMETA_ymat")+strofreal(i)) S = st_matrix(st_global("MVMETA_Smat")+strofreal(i)) X = st_matrix(st_global("MVMETA_Xmat")+strofreal(i)) keep = !colmissing(y) S = select(S,keep) S = select(S,keep') Sigma = select(Sig,keep) Sigma = select(Sigma,keep') X = select(X,keep) y = select(y,keep) V = S+Sigma if (riley) { // V = sqrt(diag(diagonal(V))) V = sqrt( I(cols(V)) :* V) V = V*corr(Sigma)*V // for(r=1;r<=cols(S);r++) { // for(s=1;s<=cols(S);s++) { // V[r,s] = Sigma[r,s] * sqrt( (1+S[r,r]/Sigma[r,r]) * (1+S[s,s]/Sigma[s,s]) ) // } // } } W = cholinv(V) dev = y-mu*X ll = ll - add2pi*cols(y)*log(2*pi())/2 + log(det(W))/2 - dev*W*dev'/2 // 14may2015: cols(y) (i.e. p_i) replaces p } rl = ll - log(det(XWXsum))/2 + add2pi*cols(mu)*log(2*pi())/2 // 14may2015: cols(mu) (i.e. q_+) replaces p if(debug==1) "rl" if(debug==1) rl st_numscalar("r(ll)",ll) st_numscalar("r(rl)",rl) } end *========================== END OF MUFROMSIGMA PROGRAM ============================