*! version 1.1.1 PR 28nov2005
/*
History

1.1.1 28nov2005 eform and eform() option styles now allowed.
		nowarning option to suppress warning message about supported regression cmds.
1.1.0 30sep2005 Generalization of supported commands (cmdchk.ado also modified).
		Version <=7 no longer supported.
1.0.9 18apr2005 Default rowid variable becomes _i.
		If not found, take from char _dta[MI_obsid] then char _dta[mi_id].
		Default impid variable is _j. If not found, take from _dta[MI_impid].
		These changes are for future compatibility with MItools.
1.0.8 04mar2005 Fixed problem with eform on redisplay
1.0.7 28jan2005 Fixed problem with null model estimation
		Fixed bug with noconstant option
1.0.6 25jan2005 e(sample) now correct for all imputations, via ereturn post.
		Add d.f. quantities from Barnard & Rubin (1999) Biometrika 86:948-955 eq (3)-(5).
		Minor additions to ereturn quantities for compatibility with misw.
		Allow null model and model only with constant for benefit of misw.
1.0.5 16nov2004 Update calculations of quantities stored for Li et al (1991) F test.
1.0.4 13oct2004 Change e(cmd) to `cmd', make e(cmd2)="micombine" (for use after mfx).
		Implementation of mean log likelihood and chisquare statistic saved
		(note undocumented -noclear- but v. useful option to ereturn post/estimates post).
*/
program define micombine, eclass

if _caller()<=7 {
	di as error "version 7 and earlier not supported"
	exit 9
}

if replay() {
	if `"`e(cmd2)'"'!="micombine" {
		error 301
	}
	syntax[, EForm EForm2(string)]
	if "`eform2'"!="" {
		if "`eform'"!="" di as err "[eform ignored]"
		local eform eform(`eform2')
	}
	else if "`eform'"!="" local eform eform("exp(b)")
	di as text _n "Multiple imputation parameter estimates (" as res e(m) as text " imputations)"
	capture ereturn  display, `eform'
	local rc=_rc
	if `rc'>0 {
		* Null model, or model with cc() only
		if `"`e(cmd)'"'!="stcox" {
			`e(cmd)' `0'
		}
		else di as text "[Null model - no estimates]"
	}
	else ereturn  display, `eform'
	di as result e(N) as text " observations."
	exit
}

gettoken cmd 0 : 0
if "`cmd'"=="stpm" {
	local dist 7
	local bad 0
}
else {
	cmdchk `cmd'
	local cmdnotknown `s(bad)'
	/*
		dist=0 (normal), 1 (binomial), 2 (poisson), 3 (cox), 4 (glm),
		5 (xtgee), 6(ereg/weibull).
	*/
	local dist `s(dist)'
}
syntax [anything] [if] [in] [aw fw pw iw] , [ IMPid(string) BR CC(varlist) noCONStant ///
 DEAD(varname) DETail EForm EForm2(string) GENxb(string) LRR noWARning OBSid(string) * ]

if `cmdnotknown' & "`warning'"!="nowarning" {
	di as err _n "Warning: " as inp "`cmd'" as err " is not a certified regression command for micombine."
	di as err "micombine will continue mechanically, but correct results are not guaranteed."
	di as err "You must take responsibility that Rubin's rules are appropriate here." _n
}

if "`eform2'"!="" {
	if "`eform'"!="" di as err "[eform ignored]"
	local eform eform(`eform2')
}
else if "`eform'"!="" local eform eform("exp(b)")

* Check for possible impid characteristic. If it does not exist use default _j
if "`impid'"=="" {
	local impid: char _dta[MI_impid]
	if "`impid'"=="" local impid _j
}
cap confirm var `impid'
if _rc {
	di as err "imputation identifier `impid' not found"
	exit 601
}

* Check for possible obsid chars. If none exist use default _i
if "`obsid'"=="" {
	local I: char _dta[MI_obsid]
	if "`I'"=="" local I: char _dta[mi_id]
	if "`I'"=="" local I _i
}
else local I `obsid'
cap confirm var `I'
if _rc {
	di as err "observation identifier `I' not found"
	exit 601
}

if "`detail'"!="" {
	local detail noisily
}
else local detail

*Change here 11/15/05, commenting out the line below !! PR DELETED XIAO CHEN'S EDIT, NOV 05
frac_cox "`dead'" `dist'

if "`constant'"=="noconstant" {
	if "`cmd'"=="fit" | "`cmd'"=="stcox" | "`cmd'"=="cox" {
		di as error "noconstant invalid with `cmd'"
		exit 198
	}
}

*Change here 11/15/05, `dist' could be null....  !! PR DELETED XIAO CHEN'S EDIT, NOV 05
*if "`dist'" =="7" {	/* stcox, streg, stpm */
if `dist'==7 {
	local y
	local yname _t
	local xvars `anything'
}
else {
	 gettoken y xvars : anything
	 gettoken xvars left: xvars, parse("(")
	 local yname `y'
}

tempvar touse
quietly {
	marksample touse
	markout `touse' `varlist' `dead' `cc'
	if "`dead'"!="" {
		local dead "dead(`dead')"
	}

* Deal with weights.
	frac_wgt `"`exp'"' `touse' `"`weight'"'
	local wgt `r(wgt)'

	tempvar J
	* Important (compatibility with mitools): ignore rows for which impid=0
	egen int `J'=group(`impid') if `touse'==1 & `impid'>0 & !missing(`impid')
	sum `J', meanonly
	local m=r(max)
	if `m'<2 {
		di as error "there must be at least 2 imputations"
		exit 198
	}

	local nxvar: word count `xvars'
/*
	if `nxvar'<1 {
		di as err "there must be at least one covariate"
		exit 198
	}
*/
	local ncc: word count `cc'		/* could legitimately be zero */
	local nvar=`nxvar'+`ncc'		/* number of covariates in model */

	count if `touse'==1 & `J'==1
	local nobs=r(N)

* Null Cox model (or model with only ccvars): fit on final imputation only, and quit
	if "`xvars'"=="" & ("`cmd'"=="cox" | "`cmd'"=="stcox") {
		if "`cmd'"=="stcox" & "`cc'"=="" {
			local options `options' estimate
		}
		`detail' `cmd' `y' `cc' if `touse'==1 & `J'==`m' `wgt', `options' `dead' `constant'
		noi `cmd'
		di as result `nobs' as text " observations."
		ereturn  scalar m=`m'
		ereturn  local impid `impid'
		ereturn  local cmd `cmd'
		ereturn  local cmd2 micombine
		exit
	}

* Compute model over m imputations
	tempname W Q B T QQ
	if "`genxb'"!="" {
		tempvar xb xbtmp
		gen `xb'=.
	}
	* Estimate mean LR chisquare statistic (where possible)
	tempname chi2 ell ell0 nucom
	scalar `chi2'=0
	scalar `ell'=0
	scalar `ell0'=0
	forvalues i=1/`m' {
		tempname Q`i'
		`detail' `cmd' `y' `xvars' `cc' `left' if `touse'==1 & `J'==`i' `wgt', ///
		 `options' `dead' `constant'
		scalar `nucom'=e(df_r)	// complete-data residual degrees of freedom
		if `nucom'==. {
			scalar `nucom'=100000
		}
		scalar `ell'=`ell'+e(ll)
		scalar `ell0'=`ell0'+e(ll_0)
		scalar `chi2'=`chi2'-2*(e(ll_0)-e(ll))
		if "`genxb'"!="" {
			predict `xbtmp' if `touse'==1 & `J'==`i', xb
			replace `xb'=`xbtmp' if  `touse'==1 & `J'==`i'
			drop `xbtmp'
		}
		matrix `Q`i''=e(b)
		if `i'==1 {
			matrix `Q'=e(b)
			matrix `W'=e(V)
		}
		else {
			matrix `Q'=`Q'+e(b)
			matrix `W'=`W'+e(V)
		}

	}
	if "`genxb'"!="" {
		sort `touse' `I' `J'
		by `touse' `I': gen `genxb'=sum(`xb')/`m' if `touse'==1
		by `touse' `I': replace `genxb'=`genxb'[_N] if _n<_N
		lab var `genxb' "Mean Linear Predictor (`m' imputations)"
	}
	matrix `Q'=`Q'/`m'		/* MI param estimates */
	matrix `W'=`W'/`m'
	scalar `chi2'=`chi2'/`m'
	scalar `ell'=`ell'/`m'
	scalar `ell0'=`ell0'/`m'
	local k=colsof(`Q')
	matrix `B'=J(`k',`k',0)
	forvalues i=1/`m' {
		matrix `QQ'=`Q`i''-`Q'
		if `i'==1 {
			matrix `B'=`QQ''*`QQ'
		}
		else matrix `B'=`B'+`QQ''*`QQ'
	}
	matrix `B'=`B'/(`m'-1)
	matrix `T'=`W'+(1+1/`m')*`B'	/* estimated VCE matrix */
	/*
		Relative increase in variance due to missing information (r) for
		each variable, and df and lambda, the fraction of missing information.
		All measures are unstable for low m. See Schafer (1997) p. 110.

		Note that BIF = sqrt(T/W) = sqrt(1 + (B/W)*(1+1/m)) = sqrt(1+r)
		is the between-imputation imprecision factor, i.e. the ratio
		of the SE derived from T to the SE derived from W,
		ignoring between-imputation variation in parameter estimates.
	*/
	tempname r t lambda nu BIF
	matrix `r'=J(1,`k',0)
	matrix `lambda'=J(1,`k',0)
	matrix `nu'=J(1,`k',0)
	matrix `BIF'=J(1,`k',0)
	scalar `t'=`m'-1
	* Next few lines assign quantities for tests of individual (1 df) components of Q (=beta)
	forvalues j=1/`k' {
		matrix `r'[1,`j']=(1+1/`m')*`B'[`j',`j']/`W'[`j',`j']
		matrix `nu'[1,`j']=cond(`t'>4, 4+(`t'-4)*(1+(1-2/`t')/`r'[1,`j'])^2, `t'*(1+1/`r'[1,`j'])^2)
		matrix `lambda'[1,`j']=(`r'[1,`j']+2/(`nu'[1,`j']+3))/(`r'[1,`j']+1)
		matrix `BIF'[1,`j']=sqrt(1+`r'[1,`j'])	/* = sqrt(`T'[`j',`j']/`W'[`j',`j']) */
	}
	* Next few lines assign quantities for d.f. from Barnard & Rubin 1999 B'ka 86(4): 948-955.
	tempname nutilde num nuobs gamma
	matrix `nutilde'=J(1,`k',0)
	matrix `num'=J(1,`k',0)
	matrix `nuobs'=J(1,`k',0)
	matrix `gamma'=J(1,`k',0)
	forvalues j=1/`k' {
		matrix `gamma'[1,`j']=(1+1/`m')*`B'[`j',`j']/`T'[`j',`j']
		matrix `nuobs'[1,`j']=((`nucom'+1)/(`nucom'+3))*`nucom'*(1-`gamma'[1,`j'])
		matrix `num'[1,`j']=(`m'-1)*`gamma'[1,`j']^-2
		matrix `nutilde'[1,`j']=1/((1/`num'[1,`j']+1/`nuobs'[1,`j']))
	}
	* use all varnames
	local names: colnames(`Q1')
	matrix colnames `r'=`names'
	matrix colnames `nu'=`names'
	matrix colnames `lambda'=`names'
	matrix colnames `BIF'=`names'

	matrix colnames `gamma'=`names'
	matrix colnames `nuobs'=`names'
	matrix colnames `num'=`names'
	matrix colnames `nutilde'=`names'

	* Li, Raghunathan & Rubin (1991) estimates of T and nu1
	* for F test of Q=0 on k,nu1 degrees of freedom
	tempname r1 t1 BW TLRR
	matrix `BW'=`B'*syminv(`W')
	scalar `r1'=trace(`BW')*(1+1/`m')/`k'
	matrix `TLRR'=`W'*(1+`r1')
	scalar `t1'=`k'*(`m'-1)
	matrix colnames `Q'=`names'
	matrix rownames `T'=`names'
	matrix colnames `T'=`names'
	matrix rownames `B'=`names'
	matrix colnames `B'=`names'
	matrix rownames `TLRR'=`names'
	matrix colnames `TLRR'=`names'

}
di as text _n "Multiple imputation parameter estimates (`m' imputations)"
if "`lrr'"!="" {
	di as text "[Using Li-Raghunathan-Rubin (LRR) estimate of VCE matrix]"
	ereturn  post `Q' `TLRR', depname(`yname') obs(`nobs') esample(`touse') noclear
	ereturn  matrix T `T'
}
else {
	ereturn  post `Q' `T', depname(`yname') obs(`nobs') esample(`touse') noclear
	ereturn  matrix TLRR `TLRR'
}
if "`br'"=="" {
	ereturn  display, `eform'
	di as result `nobs' as text " observations."
}
ereturn  matrix B `B'
ereturn  matrix W `W'
ereturn  matrix r `r'
ereturn  matrix nu `nu'
ereturn  matrix lambda `lambda'
ereturn  matrix BIF `BIF'

* Quantities for calculating df `nutilde' according to Barnard & Rubin (1999)
ereturn  matrix gamma `gamma'
ereturn  matrix nuobs `nuobs'
ereturn  matrix num `num'
ereturn  matrix nutilde `nutilde'

ereturn  scalar r1=`r1'
ereturn  scalar nu1=cond(`t1'>4, 4+(`t1'-4)*(1+(1-2/`t1')/`r1')^2, 0.5*`t1'*(1+1/`k')*(1+1/`r1')^2)
ereturn  scalar m=`m'
ereturn  scalar chi2=`chi2'
ereturn  scalar ll=`ell'
ereturn  scalar ll_0=`ell0'
ereturn  local eform `eform'
ereturn  local impid `impid'
ereturn  local cmd `cmd'
ereturn  local cmd2 micombine
if "`br'"!="" {
	display_t
	di as result `nobs' as text " observations."
}
end

program define display_t
* Display results with t-statistics estimated according to Barnard & Rubin (1999)
	tempname V Q nu
	matrix `V'=e(V)
	matrix `Q'=e(b)
	matrix `nu'=e(nutilde)
	local yname `e(depvar)'
	local xs: colnames `Q'
	local k=colsof(`Q')
	di as text _n "Intervals and inference based on d.f. from Barnard & Rubin (1999)"
	di as txt "{hline 13}{c TT}{hline 64}"
	local t0 = abbrev("`yname'",12)
	if `"`e(eform)'"'!="" {
		local tt "Odds Ratio"
	}
	else {
		local tt "     Coef."
	}

	#delimit ;
	di as text
	%12s "`t0'" _col(14)"{c |}`tt'  Std. Err.     t   P>|t|  [$S_level% Conf. Intvl]     MI.df"
	_n "{hline 13}{c +}{hline 64}" ;
	#delimit cr
	tempname df mn se t p invt l u
	forvalues i=1/`k' {
		local x: word `i' of `xs'
		if "`x'"!="_cons" {
			local fmt : format `x'
			if substr("`fmt'",-1,1)=="f" {
				local fmt="%8."+substr("`fmt'",-2,2)
			}
			else if substr("`fmt'",-2,2)=="fc" {
				local fmt="%8."+substr("`fmt'",-3,3)
			}
			else local fmt "%8.0g"
			local fmt`i' `fmt'
		}
		else local fmt "%8.0g"
	        scalar `df' =`nu'[1,`i']
	        scalar `mn' = `Q'[1,`i']
	        scalar `se' = sqrt(`V'[`i',`i'])
	        scalar `t' = `mn'/`se'
	        scalar `p' = 2* ttail(`df', abs(`t'))
	        scalar `invt' = invttail(`df', (1-$S_level/100)/2)
	        scalar `l' = `mn' - `invt'*`se'
	        scalar `u' = `mn' + `invt'*`se'
	        if `"`e(eform)'"'!="" {
	        	scalar `mn' = exp(`mn')
	        	scalar `se' = `mn'*`se'
	        	scalar `l' = exp(`l')
	        	scalar `u' = exp(`u')
	        }
		if `df'>99999 {
			local fmtdf %9.2e
		}
		else local fmtdf %9.2f
		di as text /*
			*/  %12s abbrev("`x'",12)  _col(14) "{c |}" /*
			*/ _col(17)  as res `fmt'   `mn'	  /*
			*/ _col(27)  `fmt'  `se' /*
			*/ _col(36)   %7.2f	`t'  /*
			*/ _col(42)   %7.3f	`p'  /*
			*/ _col(52)  `fmt'  `l'  /*
			*/ _col(61)  `fmt'  `u'  /*
			*/ _col(70)  `fmtdf'   `df'
	}
	di as text "{hline 13}{c BT}{hline 64}"
end

program define chkrowid, sclass
local I: char _dta[mi_id]
if "`I'"=="" {
	di as error "no row-identifier variable found - data may have incorrect format"
	exit 198
}
cap confirm var `I'
local rc=_rc
if `rc' {
	di as error "row-identifier variable `I' not found"
	exit `rc'
}
sret local I `I'
end
