program define mvdcmp
*! version 3.0 10jul2023 Dan Powers
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 15sep23 allow for two formats of sampling weights in svy design and appropriate subpopulation processing
// 15sep23 nbreg/svynbreg use current Stata versions
// 10jul23 logit, svylogit, probit, svyprobit implemented in glm to handle fractional response
// 30jun23 added support for svy models
// 20jun23 default difference = higher value outcome - lower value outcome
// 26may23 added conformability for postestimation commands like -estout- and r(table)
// 27jan22 added error message to flag non-binary coded (0/1) grouping variable
//  -mvdcmpgroup- (works in version 15+)
// 19Jun19 nbreg? (revert to version 12)
// 19Jun19 fixed: parameter name problem in nbreg resulting in Stata version changes
// broke: the norm option (devcon) OK in Stata version 15+
// solution: force version 12 in nbreg
// fixed output format 12feb2019
// reformated output table for long variable names 08aug2018
// iweights implemented 07apr2018
// cluster and robust options 25apr2017
// major update 17sept2010
// added new PDFs(x1,b1,wv1) for logit, probit, poisson, nbreg and cll
// changed ereturns e(Var) to e(V) and e(Coef) to e(b)
// version 10 added 17sept2010
// e(sample) added  06apr2010
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
version 16.0
gettoken mvdcmp_cmd model:0, parse(":")
gettoken grp 1:mvdcmp_cmd, parse(",")
gettoken 1 options:1
gettoken colon model:model
gettoken cmd model:model
gettoken model moptions:model, parse(",")
gettoken moptions moptions:moptions, parse(",")
nobreak {
	global mvdcmp_grp `grp'
	local 0 `model', by(`grp') `options' `moptions'

	if ("`cmd'"=="logit"){
	logitDecomp `0'
}
	else if ("`cmd'"=="poisson"){
	PoissonDecomp `0'
}
	else if ("`cmd'"=="probit"){
	probitDecomp `0'
}
	else if ("`cmd'"=="nbreg"){
	nbregDecomp `0'
}
	else if ("`cmd'"=="cloglog"){
	CLLDecomp `0'
}
	else if substr("`cmd'",1,3)=="reg" {
	linearDecomp `0'
}

// add calls for svy-weighted data

	else if ("`cmd'"=="svylogit"){
	svylogitDecomp `0'
}
	else if ("`cmd'"=="svyprobit"){
	svyprobitDecomp `0'
}
	else if ("`cmd'"=="svypoisson"){
	svyPoissonDecomp `0'
}
	else if ("`cmd'"=="svyregress"){
	svylinearDecomp `0'
}
	else if ("`cmd'"=="svynbreg"){
	svynbregDecomp `0'
}
	else if ("`cmd'"=="svycloglog"){
	svyCLLDecomp `0'
}

else{
	di as error "mvdcmp only accepts regress, svyregress, logit, svylogit, probit, svyprobit, poisson, svypoisson, nbreg, svynbreg, cloglog and svycloglog commands"
	macro drop mvdcmp_*
 }
}
end

program linearDecomp, eclass
syntax anything(id="varlist") [fw pw aw iw] , BY(varname) ///
    [REVerse NORmal(string) Scale(integer 1) CLUSter(varname) ROBust]

tempname matrix
// check if 2 x 1 matrix is returned
capture tab `by', matrow(`matrix')
if _rc==0 & r(r)!=2 {
  di as error "group variable (i.e., `by') must have only two categories coded 0 and 1"
macro drop mvdcmp_*
  }
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
  }
else {

	gettoken cmd newvarlist:newvarlist
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything
	local weight [`weight'`exp']

	if substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" | ///
	   substr("`weight'",2,2)=="aw" | substr("`weight'",2,2)=="iw" {
		gettoken depvar varlist:anything
		local tempweight [`weight'`exp']
		gettoken w1 wv: tempweight, parse("=")
		gettoken wv wv: wv
		gettoken wv test: wv, parse("]")
		}
	else {
		tempvar wv
		gen `wv' = 1
	}


// Empirical means: determining high-low response outcome

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata: wv`row'=0
	mata: st_view(wv`row', ., (tokens("`wv'")), "`touse'")
	mata: dv`row'=0
	mata: st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
	    tempvar t_dep`row'
       	qui egen `t_dep`row'' = total(`depvar' * `wv') if `by' == `val'
        tempvar t_exp`row'
        qui egen `t_exp`row'' = total(`wv') if `by' == `val'
        tempvar rate`row'
        qui gen `rate`row'' = `t_dep`row''/`t_exp`row''
	  	sum `rate`row'' if `by'==`val', meanonly
		local m`row' = r(mean)
    }


if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

//handle model options robust and cluster

if ("`robust'"!="")  {
  local ropt = "robust"
	}
  else {
  local ropt = ""
	}

if ("`cluster'"!="") {
  local copt = "cluster(`cluster')"
	}
  else {
  local copt = ""
	}

//estimation by group

forval i = 0/1 {
qui regress `depvar' `varlist' `weight' if `by'==`val`i'' , `ropt' `copt'

local normal`i' `normal'
if "`normal`i''"!=""{
	local j 0
	local k 0
	while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
			}
        local nnormal `++k'
         }
	}
global mvdcmp_lab`i' "`by'==`val`i''"

local df`i' = e(df_m)

tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''

mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
//
if substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" | ///
   substr("`weight'",2,2)=="iw" | substr("`weight'",2,2)=="aw" {
		gettoken temp wv : weight, parse("=")
		gettoken temp wv : wv
		gettoken tempwv wv : wv, parse("]")
		mata: wv`i'=0
		mata: st_view(wv`i', ., (tokens("`tempwv'")), "`touse'")
	}
else{
	tempvar tempwv
	gen `tempwv' = 1
	mata: wv`i'=0
	mata: st_view(wv`i', ., (tokens("`tempwv'")), "`touse'")
	}
mata: xMean`i'=mean(x`i', wv`i')
}

if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        exit
	}

// global mean return: default: differece = higher-outcome - lower-outcome 20230620
// empirical means (unscaled)

global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'


nobreak {
mata:Wdx=Wdx_F(xMean0, xMean1, b0)
mata:Wdb=Wdb_F(b0, b1, xMean1)
mata:wbA=dwA_F(b0, b1, xMean1)
mata:wbB=dwB_F(b0, b1, xMean1)
mata:dWx=dW_F(b0, xMean0, xMean1)
mata:E=mean(CDF_Linear(x0, b0, wv0))/mean(wv0) - mean(CDF_Linear(x1, b0, wv1))/mean(wv1)
mata:C=mean(CDF_Linear(x1, b0, wv1))/mean(wv1) - mean(CDF_Linear(x1, b1, wv1))/mean(wv1)
mata:PDF0=PDF_Linear(wv0)
mata:PDF1=PDF_Linear(wv1)
mata:dCdb1=dCdb1(x1, Wdb, wbA, wv1, PDF1, C)
mata:dCdb2=dCdb2(x1, Wdb, wbB, wv1, PDF1, C)
mata:dEdb=dEdb(x0, x1, Wdx, dWx, E, wv0, wv1, PDF0, PDF1)
mata:Var_E_k=varcomp(dEdb, varb0)
mata:seWdx=colsum(sqrt(diag(Var_E_k)))
mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
mata:seWdb=colsum(sqrt(diag(Var_C_k)))
mata:dCdb0A=dCdbA(x1, wv1, PDF1)
mata:dCdb0B=dCdbA(x1, wv1, PDF1)
mata:dEdb0=dEdb0(x0,x1,wv0,wv1, PDF0, PDF1)
mata:sE0=sqrt(varE(dEdb0, varb0))
mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
mata:temp=J(cols(dEdb),cols(dEdb),0)
mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
 }
}
end

// svy R E G R E S S

program svylinearDecomp, eclass
syntax anything(id="varlist")  , BY(varname) [REVerse NORmal(string) Scale(integer 1)]

tempname matrix
// check if 2 x 1 matrix is returned
capture tab `by', matrow(`matrix')
if _rc==0 & r(r)!=2 {
  di as error "group variable (i.e., `by') must have only two categories coded 0 and 1"
macro drop mvdcmp_*
  }
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
  }
else {

	gettoken cmd newvarlist:newvarlist
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything

// Empirical means: determining high-low value response

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata: dv`row'=0
	mata: st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
// svy
        tempvar rate`row'
        qui gen `rate`row'' = `depvar' if `by' == `val'
	  	qui svy: mean `rate`row'' if `by'==`val'
		local m`row' = e(b)[1,1]
    }


if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

//estimation by group
//
di "               "
di "svy information"
svyset

// descriptives outcome
forval i = 0/1 {
	tempvar sp
    gen `sp' = cond(`by' == `val`i'', 1, 0)
	svy, subpop(`sp') : mean `depvar'
	qui svy, subpop(`sp') : regress `depvar' `varlist' if `by'==`val`i''
// ruling out more complex designs
local wv = e(wvar)            // under: svyset psuid [pw=weightvar], strata(strataid)
  if ("`wv'" == ".") {
  	 local wv = e(weight1)    // under: svyset psuid, weight(weightvar) strata(strataid)
  }

local normal`i' `normal'
if "`normal`i''"!=""{
	local j 0
	local k 0
	while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
			}
        local nnormal `++k'
         }
	}
global mvdcmp_lab`i' "`by'==`val`i''"

local df`i' = e(df_m)

tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''

mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: wv`i'= 0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")  // wv0 & wv1 -> to subroutines
local vlist "`modvarlist2' `_cons'"
qui svy: mean `vlist' if `by' == `val`i''
mata: xMean`i' = st_matrix("e(b)")
}


if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        exit
	}

// global mean return: default: differece = higher-outcome - lower-outcome 20230620
// empirical means (unscaled)

global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'


nobreak {
mata:Wdx=Wdx_F(xMean0, xMean1, b0)
mata:Wdb=Wdb_F(b0, b1, xMean1)
mata:wbA=dwA_F(b0, b1, xMean1)
mata:wbB=dwB_F(b0, b1, xMean1)
mata:dWx=dW_F(b0, xMean0, xMean1)
mata:E=mean(CDF_Linear(x0, b0, wv0))/mean(wv0) - mean(CDF_Linear(x1, b0, wv1))/mean(wv1)
mata:C=mean(CDF_Linear(x1, b0, wv1))/mean(wv1) - mean(CDF_Linear(x1, b1, wv1))/mean(wv1)
mata:PDF0=PDF_Linear(wv0)
mata:PDF1=PDF_Linear(wv1)
mata:dCdb1=dCdb1(x1, Wdb, wbA, wv1, PDF1, C)
mata:dCdb2=dCdb2(x1, Wdb, wbB, wv1, PDF1, C)
mata:dEdb=dEdb(x0, x1, Wdx, dWx, E, wv0, wv1, PDF0, PDF1)
mata:Var_E_k=varcomp(dEdb, varb0)
mata:seWdx=colsum(sqrt(diag(Var_E_k)))
mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
mata:seWdb=colsum(sqrt(diag(Var_C_k)))
mata:dCdb0A=dCdbA(x1, wv1, PDF1)
mata:dCdb0B=dCdbA(x1, wv1, PDF1)
mata:dEdb0=dEdb0(x0,x1,wv0,wv1, PDF0, PDF1)
mata:sE0=sqrt(varE(dEdb0, varb0))
mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
mata:temp=J(cols(dEdb),cols(dEdb),0)
mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
 }
}
end

// now implemented as glm (for fractional regression)

program logitDecomp, eclass
syntax anything(id="varlist") [fw pw iw aw], BY(varname) ///
[REVerse NORmal(string) Scale(integer 1) CLUster(varname) ROBust]

tempname matrix
capture tab `by', matrow(`matrix')
// check if returned matrix and rows=2
if _rc==0 & r(r) != 2  {
  di as error "group variable (i.e., `by') must have exactly two categories coded 0 and 1"
	macro drop mvdcmp_*
	}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
	}

else {
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything
	local weight [`weight'`exp']
	if  substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" |  ///
		substr("`weight'",2,2)=="iw" | substr("`weight'",2,2)=="aw" {
	gettoken depvar varlist:anything
	local tempweight [`weight'`exp']
	gettoken w1 wv: tempweight, parse("=")
	gettoken wv wv: wv
	gettoken wv test: wv, parse("]")
		}
else{
	tempvar wv
	gen `wv' = 1
	}
forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:wv`row'=0
	mata:st_view(wv`row', ., (tokens("`wv'")), "`touse'")
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
		tempvar t_dep`row'
       	qui egen `t_dep`row'' = total(`depvar' * `wv') if `by' == `val'
        tempvar t_exp`row'
        qui egen `t_exp`row'' =  total(`wv')  if `by' == `val'
        tempvar rate`row'
        qui gen `rate`row'' = `t_dep`row''/`t_exp`row'' if `by' == `val'
	  	sum `rate`row'' if `by'==`val', meanonly
		local m`row' = r(mean)
    }

if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

// handle model options robust and cluster

if ("`robust'"!="")  {
  local ropt = "robust"
  }
  else {
  local ropt = ""
  }

if ("`cluster'"!="") {
  local copt = "cluster(`cluster')"
  }
  else {
  local copt = ""
 }

// estimation by group (changed to glm)

forval i = 0/1 {
  qui glm `depvar' `varlist' `weight' if `by'==`val`i'' , `ropt' `copt' family(b) link(logit)
local normal`i' `normal'
if "`normal`i''"!=""{
local j 0
local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        qui devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
     }
}
global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)
tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''
mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: wv`i'=0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")
mata: xMean`i' = mean(x`i',wv`i')
}

//check if the number of independent variables
//included in each model is identical

if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvdcmp_*
        exit
}

// global mean return: default difference  = higher outcome - lower outcome 20230620
// empirical means (unscaled)

global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak {
mata:Wdx=Wdx_F(xMean0, xMean1, b0)
mata:Wdb=Wdb_F(b0, b1, xMean1)
mata:wbA=dwA_F(b0, b1, xMean1)
mata:wbB=dwB_F(b0, b1, xMean1)
mata:dWx=dW_F(b0, xMean0, xMean1)
//
mata:E=mean(CDF_lgt(x0, b0, wv0))/mean(wv0) - mean(CDF_lgt(x1, b0, wv1))/mean(wv1)
mata:C=mean(CDF_lgt(x1, b0, wv1))/mean(wv1) - mean(CDF_lgt(x1, b1, wv1))/mean(wv1)
mata:PDF00=PDF_lgt(x0, b0, wv0)
mata:PDF10=PDF_lgt(x1, b0, wv1)
mata:PDF11=PDF_lgt(x1, b1, wv1)
mata:dCdb1=dCdb1(x1, Wdb, wbA, wv1, PDF10, C) //
mata:dCdb2=dCdb2(x1, Wdb, wbB, wv1, PDF11, C) //
mata:dEdb=dEdb(x0, x1, Wdx, dWx, E, wv0, wv1, PDF00, PDF10) //
//
mata:Var_E_k=varcomp(dEdb, varb0)
mata:seWdx=colsum(sqrt(diag(Var_E_k)))
mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
mata:seWdb=colsum(sqrt(diag(Var_C_k)))
//
mata:dCdb0A=dCdbA(x1, wv1, PDF10) //
mata:dCdb0B=dCdbA(x1, wv1, PDF11) //
mata:dEdb0=dEdb0(x0,x1,wv0,wv1, PDF00, PDF10)
//
mata:sE0=sqrt(varE(dEdb0, varb0))
mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
mata:temp=J(cols(dEdb),cols(dEdb),0)
mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
  }
 }
end

// svy L O G I T

program svylogitDecomp, eclass
syntax anything(id="varlist"), BY(varname) [REVerse NORmal(string) Scale(integer 1)]

tempname matrix
capture tab `by', matrow(`matrix')
// check if returned matrix and rows=2
if _rc==0 & r(r) != 2  {
  di as error "group variable (i.e., `by') must have exactly two categories coded 0 and 1"
	macro drop mvdcmp_*
	}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
	}

else {
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything

forvalue row = 1/2 {

	local val =  `matrix'[`row',1]
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
 	 qui svy: mean `depvar' if `by'==`val'
	 local m`row' = e(b)[1,1]
    }

if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

// estimation by group
di "               "
di "svy information"
svyset

forval i = 0/1 {
// descriptives outcome
// the appropriate way is to use subpop arg. (for correct std. errors)
//
tempvar sp
    gen `sp' = cond(`by' == `val`i'', 1, 0)
	svy, subpop(`sp') : mean `depvar'
	qui svy, subpop(`sp') : glm `depvar' `varlist' , family(b) link(logit)

// two ways to specify sampling weights in -svyset- that give identical results in single stage design
// ruling out more complex designs

local wv = e(wvar)            // under: svyset psuid [pw=weightvar], strata(strataid)
  if ("`wv'" == ".") {
  	 local wv = e(weight1)    // under: svyset psuid, weight(weightvar) strata(strataid)
  }


local normal`i' `normal'
if "`normal`i''"!=""{
local j 0
local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        qui devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
     }
}
global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)
tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''
mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
mata: wv`i'= 0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
local vlist "`modvarlist2' `_cons'"
qui svy: mean `vlist' if `by' == `val`i''
mata: xMean`i' = st_matrix("e(b)")
}

//check if the number of independent variables
//included in each model is identical

if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvdcmp_*
        exit
}

// global mean return: default difference  = higher outcome - lower outcome 20230620
// empirical means (unscaled)

global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak {
mata:Wdx=Wdx_F(xMean0, xMean1, b0)
mata:Wdb=Wdb_F(b0, b1, xMean1)
mata:wbA=dwA_F(b0, b1, xMean1)
mata:wbB=dwB_F(b0, b1, xMean1)
mata:dWx=dW_F(b0, xMean0, xMean1)
// svy:
mata:E=mean(CDF_lgt(x0, b0, wv0))/mean(wv0) - mean(CDF_lgt(x1, b0, wv1))/mean(wv1)
mata:C=mean(CDF_lgt(x1, b0, wv1))/mean(wv1) - mean(CDF_lgt(x1, b1, wv1))/mean(wv1)
mata:PDF00=PDF_lgt(x0, b0, wv0)  //
mata:PDF10=PDF_lgt(x1, b0, wv1)  //
mata:PDF11=PDF_lgt(x1, b1, wv1)  //
mata:dCdb1=dCdb1(x1, Wdb, wbA, wv1, PDF10, C) //
mata:dCdb2=dCdb2(x1, Wdb, wbB, wv1, PDF11, C) //
mata:dEdb=dEdb(x0, x1, Wdx, dWx, E, wv0, wv1, PDF00, PDF10) //
mata:Var_E_k=varcomp(dEdb, varb0)
mata:seWdx=colsum(sqrt(diag(Var_E_k)))
mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
mata:seWdb=colsum(sqrt(diag(Var_C_k)))
mata:dCdb0A=dCdbA(x1, wv1, PDF10) //
mata:dCdb0B=dCdbA(x1, wv1, PDF11) //
mata:dEdb0=dEdb0(x0,x1,wv0,wv1, PDF00, PDF10) //
mata:sE0=sqrt(varE(dEdb0, varb0))
mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
mata:temp=J(cols(dEdb),cols(dEdb),0)
mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
  }
 }
end


program probitDecomp, eclass
syntax anything(id="varlist") [fw pw iw aw], BY(varname) ///
[,REVerse NORmal(string) Scale(integer 1) CLUSter(varname) ROBust]
tempname matrix
capture tab `by', matrow(`matrix')
// check if matrix is 2 x 1
if _rc==0 & r(r)!=2  {
  di as error "group variable (i.e., `by') must have exactly two categories coded 0 and 1"
macro drop mvdcmp_*
 }

// check if matrix elements are each 0 or 1

if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
}

else{
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything
	local weight [`weight'`exp']
	if substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" ///
	 | substr("`weight'",2,2)=="iw" | substr("`weight'",2,2)=="aw" {
	gettoken depvar varlist:anything
	local tempweight [`weight'`exp']
	gettoken w1 wv: tempweight, parse("=")
	gettoken wv wv: wv
	gettoken wv test: wv, parse("]")
	}
	else{
		tempvar wv
		gen `wv' = 1
	}

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:wv`row'=0
	mata:st_view(wv`row', ., (tokens("`wv'")), "`touse'")
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
	tempvar t_dep`row'
       	qui egen `t_dep`row'' = total(`depvar' * `wv') if `by' == `val'
        tempvar t_exp`row'
        qui egen `t_exp`row'' = total(`wv') if `by' == `val'
        tempvar rate`row'
        qui gen `rate`row'' = `t_dep`row''/`t_exp`row''
	  	sum `rate`row'' if `by'==`val', meanonly
		local m`row' = r(mean)
    }

if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

// handle model options robust and cluster

if ("`robust'"!="")  {
  local ropt = "robust"
  }
  else {
  local ropt = ""
  }

if ("`cluster'"!="") {
  local copt = "cluster(`cluster')"
  }
  else {
  local copt = ""
 }

// estimation by group (implemented in glm)

forval i = 0/1 {
 qui glm `depvar' `varlist' `weight' if `by'==`val`i'' , `ropt' `copt' family(b) link(probit)
local normal`i' `normal'
if "`normal`i''"!=""{
local j 0
local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        qui devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
        }
}

global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)
tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''
mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: wv`i'=0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")
mata: xMean`i' = mean(x`i', wv`i')
}
//check if the number of independent variables
//included in each model is identical
if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvdcmp_*
        exit
}

// global mean return: default difference  = higher outcome - lower outcome 20230620
// empirical means (unscaled)
global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak{
	mata:Wdx=Wdx_F(xMean0, xMean1, b0)
	mata:Wdb=Wdb_F(b0, b1, xMean1)
	mata:wbA=dwA_F(b0, b1, xMean1)
	mata:wbB=dwB_F(b0, b1, xMean1)
	mata:dWx=dW_F(b0, xMean0, xMean1)
	mata:E=mean(CDF_probit(x0, b0, wv0))/mean(wv0) - mean(CDF_probit(x1, b0, wv1))/mean(wv1)
	mata:C=mean(CDF_probit(x1, b0, wv1))/mean(wv1) - mean(CDF_probit(x1, b1, wv1))/mean(wv1)
	mata:PDF00=PDF_probit(x0, b0, wv0)  //
	mata:PDF10=PDF_probit(x1, b0, wv1)  //
	mata:PDF11=PDF_probit(x1, b1, wv1)  //
	mata:dCdb1=dCdb1(x1, Wdb, wbA, wv1, PDF10, C) //
	mata:dCdb2=dCdb2(x1, Wdb, wbB, wv1, PDF11, C) //
	mata:dEdb=dEdb(x0, x1, Wdx, dWx, E, wv0, wv1, PDF00, PDF10) //
	mata:Var_E_k=varcomp(dEdb, varb0)
	mata:seWdx=colsum(sqrt(diag(Var_E_k)))
	mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
	mata:seWdb=colsum(sqrt(diag(Var_C_k)))
	mata:dCdb0A=dCdbA(x1, wv1, PDF10) //
	mata:dCdb0B=dCdbA(x1, wv1, PDF11) //
	mata:dEdb0=dEdb0(x0, x1, wv0, wv1, PDF00, PDF10) //
	mata:sE0=sqrt(varE(dEdb0, varb0))
	mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
	mata:temp=J(cols(dEdb),cols(dEdb),0)
	mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
	mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
  }
}
end

// svy P R O B I T

program svyprobitDecomp, eclass
syntax anything(id="varlist"), BY(varname) [REVerse NORmal(string) Scale(integer 1)]

// svy-weighted results for response and means
tempname matrix
capture tab `by', matrow(`matrix')
// check if returned matrix and rows=2
if _rc==0 & r(r) != 2  {
  di as error "group variable (i.e., `by') must have exactly two categories coded 0 and 1"
	macro drop mvdcmp_*
	}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
	}

else {
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
        tempvar rate`row'
        qui gen `rate`row'' = `depvar' if `by' == `val'
	  	qui svy: mean `rate`row'' if `by'==`val'
		local m`row' = e(b)[1,1]
    }


if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
      }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
      }

// estimation by group
di "               "
di "svy information"
svyset

forval i = 0/1 {
// descriptives outcome
// the appropriate way is to use subpop arg. (for correct std. errors)
//
tempvar sp
    gen `sp' = cond(`by' == `val`i'', 1, 0)
	svy, subpop(`sp') : mean `depvar'
	qui svy, subpop(`sp') : glm `depvar' `varlist' , family(b) link(probit)
//
// two ways to specify sampling weights in -svyset- that give identical results in single stage design
// ruling out more complex designs
local wv = e(wvar)            // under: svyset psuid [pw=weightvar], strata(strataid)
  if ("`wv'" == ".") {
  	 local wv = e(weight1)    // under: svyset psuid, weight(weightvar) strata(strataid)
  }


local normal`i' `normal'
if "`normal`i''"!=""{
local j 0
local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        qui devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
     }
}
global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)
tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''
mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: wv`i'= 0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")
local vlist "`modvarlist2' `_cons'"
 qui svy: mean `vlist' if `by' == `val`i''
mata: xMean`i' = st_matrix("e(b)")
}

//check if the number of independent variables
//included in each model is identical

if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvdcmp_*
        exit
}

// global mean return: default difference  = higher outcome - lower outcome 20230620
// empirical means (unscaled)

global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

// svy:
nobreak{
	mata:Wdx=Wdx_F(xMean0, xMean1, b0)
	mata:Wdb=Wdb_F(b0, b1, xMean1)
	mata:wbA=dwA_F(b0, b1, xMean1)
	mata:wbB=dwB_F(b0, b1, xMean1)
	mata:dWx=dW_F(b0, xMean0, xMean1)
	mata:E=mean(CDF_probit(x0, b0, wv0))/mean(wv0) - mean(CDF_probit(x1, b0, wv1))/mean(wv1)
	mata:C=mean(CDF_probit(x1, b0, wv1))/mean(wv1) - mean(CDF_probit(x1, b1, wv1))/mean(wv1)
	mata:PDF00=PDF_probit(x0, b0, wv0)  //
	mata:PDF10=PDF_probit(x1, b0, wv1)  //
	mata:PDF11=PDF_probit(x1, b1, wv1)  //
	mata:dCdb1=dCdb1(x1, Wdb, wbA, wv1, PDF10, C) //
	mata:dCdb2=dCdb2(x1, Wdb, wbB, wv1, PDF11, C) //
	mata:dEdb=dEdb(x0, x1, Wdx, dWx, E, wv0, wv1, PDF00, PDF10) //
	mata:Var_E_k=varcomp(dEdb, varb0)
	mata:seWdx=colsum(sqrt(diag(Var_E_k)))
	mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
	mata:seWdb=colsum(sqrt(diag(Var_C_k)))
	mata:dCdb0A=dCdbA(x1, wv1, PDF10) //
	mata:dCdb0B=dCdbA(x1, wv1, PDF11) //
	mata:dEdb0=dEdb0(x0,x1,wv0,wv1, PDF00, PDF10) //
	mata:sE0=sqrt(varE(dEdb0, varb0))
	mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
	mata:temp=J(cols(dEdb),cols(dEdb),0)
	mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
	mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
  }
}
end

// Poisson

program PoissonDecomp, eclass
syntax anything(id="varlist") [fw pw iw], BY(varname) [OFFset(varname) ///
 REVerse NORmal(string) Scale(integer 1) CLUSter(varname)  ROBust]
if ("`offset'"==""){
	tempvar offset
	gen `offset'=0
	}
tempname matrix
capture tab `by', matrow(`matrix')
if _rc==0 & r(r)!=2 {
	di as error "group variable (i.e., `by') must take exactly two values coded 0 and 1"
macro drop mvdcmp_*
}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
	di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
}
else{
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything
	local weight [`weight'`exp']
	if substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" | substr("`weight'",2,2)=="iw" {
		local tempweight [`weight'`exp']
		gettoken w1 wv: tempweight, parse("=")
		gettoken wv wv: wv
		gettoken wv test: wv, parse("]")
   }
	else {
	tempvar wv
	gen `wv' = 1
 }

// Empirical means: high and low valued outcomes

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:wv`row'=0
	mata:st_view(wv`row', ., (tokens("`wv'")), "`touse'")
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
	mata:off`row'=0
	mata:st_view(off`row', ., "`offset'", "`touse'")
		tempvar t_dep`row'
       	qui egen `t_dep`row'' = total(`depvar' * `wv') if `by' == `val'
        tempvar t_exp`row'
        qui egen `t_exp`row'' = total(`wv' * exp(`offset')) if `by' == `val'
        tempvar rate`row'
        qui gen `rate`row'' = `t_dep`row''/`t_exp`row''
	  	sum `rate`row'' if `by'==`val', meanonly
		local m`row' = r(mean)
    }


 if substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" | substr("`weight'",2,2)=="iw" {
    gettoken temp wv : weight, parse("=")
    gettoken temp wv : wv
    gettoken tempwv wv : wv, parse("]")
}
	else{
	tempvar tempwv
	gen `tempwv' = 1
	}

// default: higher outcome - lower outcome

if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

// handle model options robust and cluster

if ("`robust'"!="")  {
  local ropt = "robust"
  }
  else {
  local ropt = ""
  }

if ("`cluster'"!="") {
  local copt = "cluster(`cluster')"
  }
  else {
  local copt = ""
 }

// estimation by group

forval i = 0/1 {
 qui poisson `depvar' `varlist' `weight' if `by'==`val`i'' , offset(`offset') `ropt' `copt'
local normal`i' `normal'
if "`normal`i''"!=""{
local j 0
local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        qui devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
        }
}

global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)
tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''
mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: wv`i'=0
mata: st_view(wv`i', ., (tokens("`tempwv'")), "`touse'")
mata: xMean`i'=mean(x`i':*wv`i'):/mean(wv`i')
mata: off`i'=0
mata: st_view(off`i', ., "`offset'", "`touse'")
mata: off`i'=exp(off`i') // exposure
}
//check if the number of independent variables
//included in each model is identical
if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvdcmp_*
        exit
}

// global mean return: default difference  = higher outcome - lower outcome 20230620
// empirical means (unscaled)
global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak{
	mata:Wdx=Wdx_F(xMean0, xMean1, b0)
	mata:Wdb=Wdb_F(b0, b1, xMean1)
	mata:wbA=dwA_F(b0, b1, xMean1)
	mata:wbB=dwB_F(b0, b1, xMean1)
	mata:dWx=dW_F(b0, xMean0, xMean1)
	mata:E=mean(pois(x0, b0, off0, wv0))/mean(wv0:*off0) - mean(pois(x1, b0, off1, wv1))/mean(wv1:*off1)
	mata:C=mean(pois(x1, b0, off1, wv1))/mean(wv1:*off1) - mean(pois(x1, b1, off1, wv1))/mean(wv1:*off1)
	mata:PDF00=pois(x0, b0, off0, wv0) //
	mata:PDF10=pois(x1, b0, off1, wv1)
	mata:PDF11=pois(x1, b1, off1, wv1)
//
mata:dCdb1=dCdb1Pois(x1, Wdb, wbA, wv1, off1, PDF10, C)
mata:dCdb2=dCdb2Pois(x1, Wdb, wbB, wv1, off1, PDF11, C)
mata:dEdb=dEdbPois(x0, x1, Wdx, dWx, E, wv0, wv1, off0, off1, PDF00, PDF10)
//
mata:Var_E_k=varcomp(dEdb, varb0)
mata:seWdx=colsum(sqrt(diag(Var_E_k)))
mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
mata:seWdb=colsum(sqrt(diag(Var_C_k)))
//
mata:dCdb0A=dCdbAPois(x1, wv1, off1, PDF10)
mata:dCdb0B=dCdbAPois(x1, wv1, off1, PDF11)
mata:dEdb0=dEdb0Pois(x0,x1,wv0,wv1,off0, off1, PDF00, PDF10)
//
mata:sE0=sqrt(varE(dEdb0, varb0))
mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
mata:temp=J(cols(dEdb),cols(dEdb),0)
mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
 }
}
end

// svy P O I S S O N

program svyPoissonDecomp, eclass
syntax anything(id="varlist"), BY(varname) [OFFset(varname) REVerse NORmal(string) Scale(integer 1)]
if ("`offset'"==""){
	tempvar offset
	gen `offset'=0
	}
tempname matrix
capture tab `by', matrow(`matrix')
if _rc==0 & r(r)!=2 {
	di as error "group variable (i.e., `by') must take exactly two values coded 0 and 1"
macro drop mvdcmp_*
}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
	di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
}
else{
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
	mata:off`row'=0
	mata:st_view(off`row', ., "`offset'", "`touse'")
		tempvar t_dep`row'
       	qui gen `t_dep`row'' = `depvar' if `by' == `val'
		qui svy: poisson `depvar' if `by' == `val' , offset("`offset'")
		local m`row' = exp(e(b)[1,1])
    }

// default: higher outcome - lower outcome

if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

// estimation by group
di "               "
di "svy information"
svyset
forval i = 0/1 {
	//
tempvar sp
    gen `sp' = cond(`by' == `val`i'', 1, 0)
	svy, subpop(`sp') : poisson `depvar', offset(`offset') irr
	qui svy, subpop(`sp') : poisson `depvar' `varlist' , offset(`offset')

// two ways to specify sampling weights in -svyset- that give identical results in single stage design
// ruling out more complex designs
local wv = e(wvar)            // under: svyset psuid [pw=weightvar], strata(strataid)
  if ("`wv'" == ".") {
  	 local wv = e(weight1)    // under: svyset psuid, weight(weightvar) strata(strataid)
  }


local normal`i' `normal'
if "`normal`i''"!=""{
local j 0
local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        qui devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
        }
}

global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)
tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''
mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: wv`i'= 0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")
// svy means
local vlist "`modvarlist2' `_cons'"
qui svy: mean `vlist' if `by' == `val`i''
mata: xMean`i' = st_matrix("e(b)")
mata: off`i'=0
mata: st_view(off`i', ., "`offset'", "`touse'")
mata: off`i'=exp(off`i') // exposure
}


//check if the number of independent variables
//included in each model is identical
if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvdcmp_*
        exit
}

// global mean return: default difference  = higher outcome - lower outcome 20230620
// empirical means (unscaled)
global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak{
	mata:Wdx=Wdx_F(xMean0, xMean1, b0)
	mata:Wdb=Wdb_F(b0, b1, xMean1)
	mata:wbA=dwA_F(b0, b1, xMean1)
	mata:wbB=dwB_F(b0, b1, xMean1)
	mata:dWx=dW_F(b0, xMean0, xMean1)
	mata:E=mean(pois(x0, b0, off0, wv0))/mean(wv0:*off0) - mean(pois(x1, b0, off1, wv1))/mean(wv1:*off1)
	mata:C=mean(pois(x1, b0, off1, wv1))/mean(wv1:*off1) - mean(pois(x1, b1, off1, wv1))/mean(wv1:*off1)
	mata:PDF00=pois(x0, b0, off0, wv0) //
	mata:PDF10=pois(x1, b0, off1, wv1)
	mata:PDF11=pois(x1, b1, off1, wv1)
//
mata:dCdb1=dCdb1Pois(x1, Wdb, wbA, wv1, off1, PDF10, C)
mata:dCdb2=dCdb2Pois(x1, Wdb, wbB, wv1, off1, PDF11, C)
mata:dEdb=dEdbPois(x0, x1, Wdx, dWx, E, wv0, wv1, off0, off1, PDF00, PDF10)
//
mata:Var_E_k=varcomp(dEdb, varb0)
mata:seWdx=colsum(sqrt(diag(Var_E_k)))
mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
mata:seWdb=colsum(sqrt(diag(Var_C_k)))
//
mata:dCdb0A=dCdbAPois(x1, wv1, off1, PDF10)
mata:dCdb0B=dCdbAPois(x1, wv1, off1, PDF11)
mata:dEdb0=dEdb0Pois(x0,x1,wv0,wv1,off0, off1, PDF00, PDF10)
//
mata:sE0=sqrt(varE(dEdb0, varb0))
mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
mata:temp=J(cols(dEdb),cols(dEdb),0)
mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
 }
}
end

// nbreg

program nbregDecomp, eclass
//
syntax anything(id="varlist") [fw pw iw], BY(varname) [OFFset(varname) ///
REVerse NORmal(string) Scale(integer 1) CLUSter(varname) ROBust]
	if ("`offset'"==""){
	tempvar offset
	gen `offset'=0
	}
tempname matrix
capture tab `by', matrow(`matrix')
if _rc==0 & r(r)!=2 {
di as error "group variable (i.e., `by') must take exactly two values coded 0 and 1"
macro drop mvdcmp_*
}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
}
else{
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything
	local weight [`weight'`exp']
		if substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" | substr("`weight'",2,2)=="iw" {
		local tempweight [`weight'`exp']
		gettoken w1 wv: tempweight, parse("=")
		gettoken wv wv: wv
		gettoken wv test: wv, parse("]")
	}
	else{
		tempvar wv
		gen `wv' = 1
	}
forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:wv`row'=0
	mata:st_view(wv`row', ., (tokens("`wv'")), "`touse'")
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
	mata:off`row'=0
	mata:st_view(off`row', ., "`offset'", "`touse'")
		tempvar t_dep`row'
       	qui egen `t_dep`row'' = total(`depvar' * `wv') if `by' == `val'
        tempvar t_exp`row'
        qui egen `t_exp`row'' = total(`wv' * exp(`offset')) if `by' == `val'
        tempvar rate`row'
        qui gen `rate`row'' = `t_dep`row''/`t_exp`row''
	  	sum `rate`row'' if `by'==`val', meanonly
		local m`row' = r(mean)
    }

if substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" | substr("`weight'",2,2)=="iw" {
	gettoken temp wv : weight, parse("=")
	gettoken temp wv : wv
	gettoken tempwv wv : wv, parse("]")
}
	else{
		tempvar tempwv
		gen `tempwv' = 1
	}

if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

// handle robust and cluster options

if ("`robust'"!="")  {
  local ropt = "robust"
  }
  else {
  local ropt = ""
  }

if ("`cluster'"!="") {
  local copt = "cluster(`cluster')"
  }
  else {
  local copt = ""
 }

// estimation by group
forval i = 0/1 {
 qui nbreg `depvar' `varlist' `weight' if `by'==`val`i'', offset(`offset') `ropt' `copt'
local normal`i' `normal'
if "`normal`i''"!=""{
local j 0
local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        qui devcon, group(`gvars') equations(1) nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
        }
}

global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)
tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''
mata: x`i'=0
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons /*get rid of the first cons*/
// fix problem due to renaming of scale parameter in Stata 15
// local cons2 _cons
local cons2 "lnalpha"
local modvarlist2: list modvarlist2 - cons2 //  get rid of lnalpha from e(b) //
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: b=st_matrix("e(b)")
mata: b`i'=0
mata: st_subview(b`i', b, 1,((1\cols(b)-1)))
mata: wv`i'=0
mata: st_view(wv`i', ., (tokens("`tempwv'")), "`touse'")
mata: xMean`i'=mean(x`i', wv`i')
mata: varb=st_matrix("e(V)")
mata: varb`i'=0
mata: st_subview(varb`i', varb, (1,rows(varb)-1),((1\cols(varb)-1)))
mata: off`i'=0
mata: st_view(off`i', ., "`offset'", "`touse'")
/// calculating exposure from offset
mata: off`i'= exp(off`i')
///
}

//check if the number of independent variables
//included in each model is identical
if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvcdmp_*
        exit
}

// global mean return
// empirical means (unscaled)
global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak {
mata:Wdx=Wdx_F(xMean0, xMean1, b0)
mata:Wdb=Wdb_F(b0, b1, xMean1)
mata:wbA=dwA_F(b0, b1, xMean1)
mata:wbB=dwB_F(b0, b1, xMean1)
mata:dWx=dW_F(b0, xMean0, xMean1)
mata:E=mean(pois(x0, b0, off0, wv0))/mean(wv0:*off0) - mean(pois(x1, b0, off1, wv1))/mean(wv1:*off1)
mata:C=mean(pois(x1, b0, off1, wv1))/mean(wv1:*off1) - mean(pois(x1, b1, off1, wv1))/mean(wv1:*off1)
mata:PDF00=pois(x0, b0, off0,wv0) //
mata:PDF10=pois(x1, b0, off1,wv1)
mata:PDF11=pois(x1, b1, off1,wv1)
//
mata:dCdb1=dCdb1Pois(x1, Wdb, wbA, wv1, off1, PDF10, C)
mata:dCdb2=dCdb2Pois(x1, Wdb, wbB, wv1, off1, PDF11, C)
mata:dEdb=dEdbPois(x0, x1, Wdx, dWx, E, wv0, wv1, off0, off1, PDF00, PDF10)
mata:Var_E_k=varcomp(dEdb, varb0)
mata:seWdx=colsum(sqrt(diag(Var_E_k)))
mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
mata:seWdb=colsum(sqrt(diag(Var_C_k)))
mata:dCdb0A=dCdbAPois(x1, wv1, off1, PDF10)
mata:dCdb0B=dCdbAPois(x1, wv1, off1, PDF11)
mata:dEdb0=dEdb0Pois(x0, x1, wv0, wv1, off0, off1, PDF00, PDF10)
//
mata:sE0=sqrt(varE(dEdb0, varb0))
mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
mata:temp=J(cols(dEdb),cols(dEdb),0)
mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
//
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
 }
}
end

// svy N B R E G

program svynbregDecomp, eclass
// force version 12 for nbreg
// version 12
//
syntax anything(id="varlist"), BY(varname) [OFFset(varname) REVerse NORmal(string) Scale(integer 1)]
	if ("`offset'"==""){
	tempvar offset
	gen `offset'=0
	}
tempname matrix
capture tab `by', matrow(`matrix')
if _rc==0 & r(r)!=2 {
di as error "group variable (i.e., `by') must take exactly two values coded 0 and 1"
macro drop mvdcmp_*
}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
}
else{
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
	mata:off`row'=0
	mata:st_view(off`row', ., "`offset'", "`touse'")
		tempvar t_dep`row'
       	qui gen `t_dep`row'' = `depvar' if `by' == `val'
		qui svy: nbreg `depvar' if `by' == `val' , offset("`offset'")
		local m`row' = exp(e(b)[1,1])
    }


if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

// estimation by group
di "               "
di "svy information"
svyset
forval i = 0/1 {
//
// the appropriate way is to use subpop arg. (for correct std. errors)
//
tempvar sp
    gen `sp' = cond(`by' == `val`i'', 1, 0)
	svy, subpop(`sp') : nbreg `depvar', offset(`offset') irr
qui svy, subpop(`sp') : nbreg `depvar' `varlist' , offset(`offset')

// two ways to specify sampling weights in -svyset- that give identical results in single stage design
// ruling out more complex designs
local wv = e(wvar)            // under: svyset psuid [pw=weightvar], strata(strataid)
  if ("`wv'" == ".") {
  	 local wv = e(weight1)    // under: svyset psuid, weight(weightvar) strata(strataid)
  }

local normal`i' `normal'
if "`normal`i''"!=""{
local j 0
local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        qui devcon, group(`gvars') equations(1) nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
        }
}

global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)
tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''
mata: x`i'=0
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons /*get rid of the first cons*/
// fix problem due to renaming of scale parameter in Stata 15
//local cons2 _cons
local cons2 "lnalpha"
local modvarlist2: list modvarlist2 - cons2 /*get rid of lnalpha*/
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: b=st_matrix("e(b)")
mata: b`i'=0
mata: st_subview(b`i', b, 1,((1\cols(b)-1)))
mata: varb=st_matrix("e(V)")
mata: varb`i'=0
mata: st_subview(varb`i', varb, (1,rows(varb)-1),((1\cols(varb)-1)))
mata: wv`i'=0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")
// svy means
local vlist "`modvarlist2' `_cons'"
qui svy: mean `vlist' if `by' == `val`i''
mata: xMean`i' = st_matrix("e(b)")
mata: off`i'=0
mata: st_view(off`i', ., "`offset'", "`touse'")
/// calculating exposure from offset
mata: off`i'= exp(off`i')
///
}

//check if the number of independent variables
//included in each model is identical
if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvcdmp_*
        exit
}

// global mean return
// empirical means (unscaled)
global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak {
mata:Wdx=Wdx_F(xMean0, xMean1, b0)
mata:Wdb=Wdb_F(b0, b1, xMean1)
mata:wbA=dwA_F(b0, b1, xMean1)
mata:wbB=dwB_F(b0, b1, xMean1)
mata:dWx=dW_F(b0, xMean0, xMean1)
mata:E=mean(pois(x0, b0, off0, wv0))/mean(wv0:*off0) - mean(pois(x1, b0, off1, wv1))/mean(wv1:*off1)
mata:C=mean(pois(x1, b0, off1, wv1))/mean(wv1:*off1) - mean(pois(x1, b1, off1, wv1))/mean(wv1:*off1)
mata:PDF00=pois(x0, b0, off0,wv0) //
mata:PDF10=pois(x1, b0, off1,wv1)
mata:PDF11=pois(x1, b1, off1,wv1)
//
mata:dCdb1=dCdb1Pois(x1, Wdb, wbA, wv1, off1, PDF10, C)
mata:dCdb2=dCdb2Pois(x1, Wdb, wbB, wv1, off1, PDF11, C)
mata:dEdb=dEdbPois(x0, x1, Wdx, dWx, E, wv0, wv1, off0, off1, PDF00, PDF10)
mata:Var_E_k=varcomp(dEdb, varb0)
mata:seWdx=colsum(sqrt(diag(Var_E_k)))
mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
mata:seWdb=colsum(sqrt(diag(Var_C_k)))
mata:dCdb0A=dCdbAPois(x1, wv1, off1, PDF10)
mata:dCdb0B=dCdbAPois(x1, wv1, off1, PDF11)
mata:dEdb0=dEdb0Pois(x0, x1, wv0, wv1, off0, off1, PDF00, PDF10)
//
mata:sE0=sqrt(varE(dEdb0, varb0))
mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
mata:temp=J(cols(dEdb),cols(dEdb),0)
mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
mata:sR0=sqrt(sum(eV))
eret clear
global mvdcmp_scale `scale'
//
global mvdcmp_varlist `modvarlist2'
global mvdcmp_nvarlist "`modvarlist2' _cons"
global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp_*
 }
}
end

// cloglog

program CLLDecomp, eclass
syntax anything(id="varlist") [fw pw iw], BY(varname) ///
[REVerse  NORmal(string)  Scale(integer 1)  CLUSter(varname)  ROBust]
tempname matrix
capture tab `by', matrow(`matrix')
if _rc==0 & r(r)!=2 {
di as error "group variable (i.e., `by') must take exactly two values coded 0 and 1"
macro drop mvdcmp_*
}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
}
else{
	gettoken cmd newvarlist:newvarlist
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything
	local weight [`weight'`exp']

	if substr("`weight'",2,2)=="pw" | substr("`weight'",2,2)=="fw" | substr("`weight'",2,2)=="iw" {
		gettoken depvar varlist:anything
		local tempweight [`weight'`exp']
		gettoken w1 wv: tempweight, parse("=")
		gettoken wv wv: wv
		gettoken wv test: wv, parse("]")
}
	else{
		tempvar wv
		gen `wv' = 1
	}

// outcome means -- determining high-low order

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:wv`row'=0
	mata:st_view(wv`row', ., (tokens("`wv'")), "`touse'")
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
		tempvar t_dep`row'
       	qui egen `t_dep`row'' = total(`depvar' * `wv') if `by' == `val'
        tempvar t_exp`row'
        qui egen `t_exp`row'' = total(`wv') if `by' == `val'
        tempvar rate`row'
        qui gen `rate`row'' = `t_dep`row''/`t_exp`row''
	  	sum `rate`row'' if `by'==`val', meanonly
		local m`row' = r(mean)
    }
if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }

// handle model options robust and cluster

if ("`robust'"!="")  {
  local ropt = "robust"
  }
  else {
  local ropt = ""
  }

if ("`cluster'"!="") {
  local copt = "cluster(`cluster')"
  }
  else {
  local copt = ""
 }

// estimation by group

forval i = 0/1 {
	qui cloglog `depvar' `varlist' `weight' if `by'==`val`i'' , `ropt' `copt'
local normal`i' `normal'
if "`normal`i''"!=""{
	local j 0
	local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
        }
}

global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)

tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''

mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: wv`i'=0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")
mata: xMean`i'=mean(x`i', wv`i')
}

if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvdcmp_*
        exit
}

// global mean return
// empirical means (unscaled)
global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak{
	mata:Wdx=Wdx_F(xMean0, xMean1, b0)
	mata:Wdb=Wdb_F(b0, b1, xMean1)
	mata:wbA=dwA_F(b0, b1, xMean1)
	mata:wbB=dwB_F(b0, b1, xMean1)
	mata:dWx=dW_F(b0, xMean0, xMean1)
	mata:E=mean(CDF_CLL(x0, b0, wv0))/mean(wv0) - mean(CDF_CLL(x1, b0, wv1))/mean(wv1)
	mata:C=mean(CDF_CLL(x1, b0, wv1))/mean(wv1) - mean(CDF_CLL(x1, b1, wv1))/mean(wv1)
	mata:PDF00=PDF_CLL(x0, b0, wv0) //
	mata:PDF10=PDF_CLL(x1, b0, wv1)
	mata:PDF11=PDF_CLL(x1, b1, wv1)
	mata:dCdb1=dCdb1(x1, Wdb, wbA, wv1, PDF10, C)
	mata:dCdb2=dCdb2(x1, Wdb, wbB, wv1, PDF11, C)
	mata:dEdb=dEdb(x0, x1, Wdx, dWx, E, wv0, wv1, PDF00, PDF10)
	mata:Var_E_k=varcomp(dEdb, varb0)
	mata:seWdx=colsum(sqrt(diag(Var_E_k)))
	mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
	mata:seWdb=colsum(sqrt(diag(Var_C_k)))
	mata:dCdb0A=dCdbA(x1, wv1, PDF10)
	mata:dCdb0B=dCdbA(x1, wv1, PDF11)
	mata:dEdb0=dEdb0(x0,x1,wv0,wv1, PDF00, PDF10)
	mata:sE0=sqrt(varE(dEdb0, varb0))
	mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
	mata:temp=J(cols(dEdb),cols(dEdb),0)
	mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
	mata:sR0=sqrt(sum(eV))
	eret clear
	global mvdcmp_scale `scale'
	global mvdcmp_varlist `modvarlist2'
	global mvdcmp_nvarlist "`modvarlist2' _cons"
	global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp*
	}
}
end

// svy  C L O G L O G

program svyCLLDecomp, eclass
syntax anything(id="varlist"), BY(varname) ///
[REVerse  NORmal(string)  Scale(integer 1)]
tempname matrix
capture tab `by', matrow(`matrix')
if _rc==0 & r(r)!=2 {
di as error "group variable (i.e., `by') must take exactly two values coded 0 and 1"
macro drop mvdcmp_*
}
// check if matrix elements are each 0 or 1
if `matrix'[1,1] ! = 0 & `matrix'[2,1] ! = 1 {
  di as error "group variable (i.e., `by') must be coded 0/1"
macro drop mvdcmp_*
}
else{
	gettoken cmd newvarlist:newvarlist
	tempvar _cons
	gen `_cons'=1
	gettoken depvar varlist:anything

// outcome means -- determining high-low order

forvalue row = 1/2 {
	local val =  `matrix'[`row',1]
	mata:dv`row'=0
	mata:st_view(dv`row', ., (tokens("`depvar'")), "`touse'")
        tempvar rate`row'
        qui gen `rate`row'' = `depvar' if `by' == `val'
	  	qui svy: mean `rate`row'' if `by'==`val'
		local m`row' = e(b)[1,1]
    }

if (`m2'>=`m1' & "`reverse'"=="") | (`m2'<`m1' & "`reverse'"!="") {
        local val0 = `matrix'[2,1]
        local val1 = `matrix'[1,1]
    }
    else {
        local val0 = `matrix'[1,1]
        local val1 = `matrix'[2,1]
        }


di "               "
di "svy information"
svyset
// estimation by group
forval i = 0/1 {
// descriptives outcome
//
// the appropriate way is to use subpop arg. (for correct std. errors)
//
tempvar sp
    gen `sp' = cond(`by' == `val`i'', 1, 0)
	svy, subpop(`sp') : mean `depvar'
 qui svy, subpop(`sp') : cloglog `depvar' `varlist'
//
// two ways to specify sampling weights in -svyset- that give identical results in single stage design
// ruling out more complex designs
local wv = e(wvar)            // under: svyset psuid [pw=weightvar], strata(strataid)
  if ("`wv'" == ".") {
  	 local wv = e(weight1)    // under: svyset psuid, weight(weightvar) strata(strataid)
  }


local normal`i' `normal'
if "`normal`i''"!=""{
	local j 0
	local k 0
while (1) {
        if "`normal`i''" == "" continue, break
        gettoken gvars normal`i': normal`i', parse("|")
        unab gvars: `gvars'
        devcon, group(`gvars') nonoise
        local gvars`++j' `gvars'
        if "`normal`i''"!=""{
        gettoken bar normal`i' : normal`i', parse("|")
        }
        local nnormal `++k'
        }
}

global mvdcmp_lab`i' "`by'==`val`i''"
local df`i' = e(df_m)

tempvar touse
gen `touse'=0
qui replace `touse'=1 if `by'==`val`i''

mata: x`i'=0
mata: b`i'=st_matrix("e(b)")
mata: varb`i'=st_matrix("e(V)")
local modvarlist: colnames e(b)
local cons _cons
local modvarlist2: list modvarlist - cons
mata: st_view(x`i', ., (tokens("`modvarlist2'"), "`_cons'"), "`touse'")
mata: wv`i'=0
mata: st_view(wv`i', ., (tokens("`wv'")), "`touse'")
// svy means
local vlist "`modvarlist2' `_cons'"
qui svy: mean `vlist' if `by' == `val`i''
mata: xMean`i' = st_matrix("e(b)")
}

if `df0'!=`df1' {
        di as error "Number of regressors differs between the groups"
        di as error "Perhaps a variable was dropped in one of the groups defined by `by'"
        macro drop mvdcmp_*
        exit
}

// global mean return
// empirical means (unscaled)
global mvdcmp_mu1 = `val0' * `m1'   +  `val1' * `m2'
global mvdcmp_mu0 = `val1' * `m1'   +  `val0' * `m2'

nobreak{
	mata:Wdx=Wdx_F(xMean0, xMean1, b0)
	mata:Wdb=Wdb_F(b0, b1, xMean1)
	mata:wbA=dwA_F(b0, b1, xMean1)
	mata:wbB=dwB_F(b0, b1, xMean1)
	mata:dWx=dW_F(b0, xMean0, xMean1)
	mata:E=mean(CDF_CLL(x0, b0, wv0))/mean(wv0) - mean(CDF_CLL(x1, b0, wv1))/mean(wv1)
	mata:C=mean(CDF_CLL(x1, b0, wv1))/mean(wv1) - mean(CDF_CLL(x1, b1, wv1))/mean(wv1)
	mata:PDF00=PDF_CLL(x0, b0, wv0) //
	mata:PDF10=PDF_CLL(x1, b0, wv1)
	mata:PDF11=PDF_CLL(x1, b1, wv1)
	mata:dCdb1=dCdb1(x1, Wdb, wbA, wv1, PDF10, C)
	mata:dCdb2=dCdb2(x1, Wdb, wbB, wv1, PDF11, C)
	mata:dEdb=dEdb(x0, x1, Wdx, dWx, E, wv0, wv1, PDF00, PDF10)
	mata:Var_E_k=varcomp(dEdb, varb0)
	mata:seWdx=colsum(sqrt(diag(Var_E_k)))
	mata:Var_C_k=varcoef(dCdb1, dCdb2, varb0, varb1)
	mata:seWdb=colsum(sqrt(diag(Var_C_k)))
	mata:dCdb0A=dCdbA(x1, wv1, PDF10)
	mata:dCdb0B=dCdbA(x1, wv1, PDF11)
	mata:dEdb0=dEdb0(x0,x1,wv0,wv1, PDF00, PDF10)
	mata:sE0=sqrt(varE(dEdb0, varb0))
	mata:sC0=sqrt(varC(varb0, varb1, dCdb0A, dCdb0B))
	mata:temp=J(cols(dEdb),cols(dEdb),0)
	mata:eV=((dEdb,temp)\(dCdb1,dCdb2))*(varb0,temp\temp,varb1)*((dEdb,temp)\(dCdb1,dCdb2))'
	mata:sR0=sqrt(sum(eV))
	eret clear
	global mvdcmp_scale `scale'
	global mvdcmp_varlist `modvarlist2'
	global mvdcmp_nvarlist "`modvarlist2' _cons"
	global mvdcmp_depvar `depvar'
setresult
displayresult
macro drop mvdcmp*
	}
}
end

program setresult, eclass
mata:R=E+C
mata:ZvalueE=E/sE0
mata:ZvalueC=C/sC0
mata:ZvalueR=R/sR0
mata:PctE=100*E/(E+C)
mata:PctC=100*C/(E+C)
mata:DCE=E:*Wdx
mata:ZEWdx=E*Wdx:/seWdx
mata:PCTcom=100*(E*Wdx:/(E+C))
mata:CWdb=C*Wdb
mata:ZCWdb=C*Wdb:/seWdb
mata:PCTcoe=100*(C*Wdb:/(E+C))
mata:El=E-1.96*sE0
mata:Eh=E+1.96*sE0
mata:Cl=C-1.96*sC0
mata:Ch=C+1.96*sC0
mata:Rl=R-1.96*sR0
mata:Rh=R+1.96*sR0
mata:st_matrix("El", El)
mata:st_matrix("Eh", Eh)
mata:st_matrix("Cl", Cl)
mata:st_matrix("Ch", Ch)
mata:st_matrix("Rl", Rl)
mata:st_matrix("Rh", Rh)
mata:st_matrix("E", E)
mata:st_matrix("C", C)
mata:st_matrix("R", R)
mata:st_matrix("VarEk", Var_E_k)
mata:st_matrix("seWdx", seWdx)
mata:st_matrix("seWdb", seWdb)
mata:st_matrix("VarCk", Var_C_k)
mata:st_matrix("sE0", sE0)
mata:st_matrix("sC0", sC0)
mata:st_matrix("sR0", sR0)
mata:st_matrix("ZE", ZvalueE)
mata:st_matrix("ZC", ZvalueC)
mata:st_matrix("ZR", ZvalueR)
mata:st_matrix("PE", PctE)
mata:st_matrix("PC", PctC)
mata:st_matrix("DCE", DCE)
mata:st_matrix("ZEWdx", ZEWdx)
mata:st_matrix("PCTcom", PCTcom)
mata:st_matrix("CWdb", CWdb)
mata:st_matrix("ZCWdb", ZCWdb)
mata:st_matrix("PCTcoe", PCTcoe)
mata: N = rows(x0) + rows(x1)
mata:st_matrix("N", N)
mata: PZE=2*normal(-abs(ZvalueE))
mata: PZC=2*normal(-abs(ZvalueC))
mata: PZR=2*normal(-abs(ZvalueR))
mata:st_matrix("PZE", PZE)
mata:st_matrix("PZC", PZC)
mata:st_matrix("PZR", PZR)
global mvdcmp_N=N[1,1]
global mvdcmp_ZE=ZE[1,1]
global mvdcmp_ZC=ZC[1,1]
global mvdcmp_ZR=ZR[1,1]
global mvdcmp_PE=PE[1,1]
global mvdcmp_PC=PC[1,1]
global mvdcmp_PZE=PZE[1,1]
global mvdcmp_PZC=PZC[1,1]
global mvdcmp_PZR=PZR[1,1]
global mvdcmp_El = El[1,1]*$mvdcmp_scale
global mvdcmp_Eh = Eh[1,1]*$mvdcmp_scale
global mvdcmp_Cl = Cl[1,1]*$mvdcmp_scale
global mvdcmp_Ch = Ch[1,1]*$mvdcmp_scale
global mvdcmp_Rl = Rl[1,1]*$mvdcmp_scale
global mvdcmp_Rh = Rh[1,1]*$mvdcmp_scale
//
global mvdcmp_E = E[1,1]*$mvdcmp_scale
global mvdcmp_C = C[1,1]*$mvdcmp_scale
global mvdcmp_R = R[1,1]*$mvdcmp_scale
global mvdcmp_seE = sE0[1,1]*$mvdcmp_scale
global mvdcmp_seC = sC0[1,1]*$mvdcmp_scale
global mvdcmp_seR = sR0[1,1]*$mvdcmp_scale
//
global mvdcmp_nvar: word count $mvdcmp_nvarlist
global mvdcmp_nvar2 = $mvdcmp_nvar - 1
// output means (weighted & offset)
global mvdcmp_mu0 = $mvdcmp_mu0 * $mvdcmp_scale
global mvdcmp_mu1 = $mvdcmp_mu1 * $mvdcmp_scale
//
forval i = 1/$mvdcmp_nvar {
global mvdcmp_varname`i' : word `i' of $mvdcmp_nvarlist
}
		forval i = 1/$mvdcmp_nvar {
		local cvarlist `cvarlist' E:${mvdcmp_varname`i'}
	}
		forval i = 1/$mvdcmp_nvar {
		local cvarlist `cvarlist' C:${mvdcmp_varname`i'}
	}
local cvarlist `cvarlist' Summary:E Summary:C Summary:R //
mat coln DCE = $mvdcmp_nvarlist
mat rown DCE = estimate
mat coln CWdb = $mvdcmp_nvarlist
mat rown CWdb = estimate
mat coln VarEk = $mvdcmp_nvarlist
mat rown VarEk = $mvdcmp_nvarlist
mat coln VarCk = $mvdcmp_nvarlist
mat rown VarCk = $mvdcmp_nvarlist
mat coln seWdx=$mvdcmp_nvarlist
mat coln seWdb=$mvdcmp_nvarlist
forval i = 1/$mvdcmp_nvar {
	global mvdcmp_DCE`i'=DCE[1,`i']*$mvdcmp_scale
	global mvdcmp_seWdx`i'=seWdx[1,`i']*$mvdcmp_scale
	global mvdcmp_ZEWdx`i'=ZEWdx[1,`i']
	global mvdcmp_PZE`i'= 2*normal(-abs(${mvdcmp_ZEWdx`i'}))
	global mvdcmp_El`i'= (${mvdcmp_DCE`i'} + invnormal(.025)*${mvdcmp_seWdx`i'})
	global mvdcmp_Eh`i'= (${mvdcmp_DCE`i'} + invnormal(.975)*${mvdcmp_seWdx`i'})
	global mvdcmp_PCTcom`i'=PCTcom[1,`i']
	global mvdcmp_CWdb`i'=CWdb[1,`i']*$mvdcmp_scale
	global mvdcmp_seWdb`i'=seWdb[1,`i']*$mvdcmp_scale
	global mvdcmp_ZCWdb`i'=ZCWdb[1,`i']
	global mvdcmp_PZC`i'=2*normal(-abs(${mvdcmp_ZCWdb`i'}))
	global mvdcmp_Cl`i'= (${mvdcmp_CWdb`i'}-1.96*${mvdcmp_seWdb`i'})
	global mvdcmp_Ch`i'= (${mvdcmp_CWdb`i'}+1.96*${mvdcmp_seWdb`i'})
	global mvdcmp_PCTcoe`i'=PCTcoe[1,`i']
	}
mata:Coef=DCE,CWdb,E,C,R // E, C, R added 20100917
// create new e(V) 20100919 start
mata:VarE=J(${mvdcmp_nvar}*2+3,1,0)
mata:VarE[${mvdcmp_nvar}*2+1,1]=sE0^2
mata:VarC=J(${mvdcmp_nvar}*2+3,1,0)
mata:VarC[${mvdcmp_nvar}*2+2,1]=sC0^2
mata:VarR=J(${mvdcmp_nvar}*2+3,1,0)
mata:VarR[${mvdcmp_nvar}*2+3,1]=sR0^2
mata:temp=J(1,${mvdcmp_nvar}*2,0)
mata:eV=eV\temp\temp\temp
mata:eV=eV,VarE,VarC,VarR
// check missing coefs
mata: mflag = missing(Coef)
mata: if (mflag > 0) display("    --------------------------------------------------------------------------   " \  "      Warning: all predictors have identical values across groups    " \  "    --------------------------------------------------------------------------   " );;
// all missing replaced by 0
mata:Coef=editmissing(Coef,0)
mata:st_matrix("Coef", Coef)
mata:st_matrix("eV", eV)
mat coln Coef = `cvarlist'
mat coln eV = `cvarlist'
mat rown eV = `cvarlist'
// create new e(V) 20100919 end
// new 20100917 start
tempvar touse
gen `touse' = $mvdcmp_grp
tempname b V
matrix `b' = Coef
matrix `V' = eV
eret post `b' `V', esample(`touse')
// new 20100917 end
eret local low $mvdcmp_lab1
eret local high $mvdcmp_lab0
eret local indvar = "$mvdcmp_varlist"
eret local depvar $mvdcmp_depvar
eret scalar scale = $mvdcmp_scale
eret scalar N = $mvdcmp_N
eret local cmd = "mvdcmp"
// 2023/05/26  for convenience/conformability
eret local cvarlist `cvarlist'
//
end

program displayresult, eclass
local format
{

		di
        di %10s as text "Decomposition Results"               as text %55s    "Number of obs =   "   as res %-30.0gc $mvdcmp_N
        di as text "{hline 31}{hline 72}"
		di %30s as text "Reference group  (A):" as res "`e(high)'"  %20s as text "Mean = " as res %-8.4fc $mvdcmp_mu0
//		di %30s as text "Reference group  (A):" as res $mvdcmp_lab0  %20s as text "Mean = " as res %-8.2fc $mvdcmp_mu0
di %30s as text "Comparison group (B):" as res "`e(low)'"  %20s as text "Mean = " as res %-8.4fc $mvdcmp_mu1
//		di %30s as text "Comparison group (B):" as res $mvdcmp_lab1  %20s as text "Mean = " as res %-8.2fc $mvdcmp_mu1
        di as text "{hline 31}{c TT}{hline 71}"
        di as text %30s "$mvdcmp_depvar", _col(30) as text "{c |}" _col(11) as text %11s "Coef." _col(22) as text %11s "Std. Err." _col(29) as text %8s "z" _col(38) /*
        */ as text %9s "P>|z|" _col(47) as text %24s "[95% Conf. Interval]" _col(71) as text %8s "Pct."
        di as text "{hline 31}{c +}{hline 71}"
        di as text %30s  "E"       , _col(30) as text "{c |}"  as res %11.5f $mvdcmp_E    as res %11.5f $mvdcmp_seE  as res %8.2f $mvdcmp_ZE /*
        */                                                     as res %9.3f $mvdcmp_PZE  as res %11.5f $mvdcmp_El   as res %11.5f $mvdcmp_Eh   as res %10.2f $mvdcmp_PE
        di as text %30s  "C"       , _col(30) as text "{c |}"  as res %11.5f $mvdcmp_C   as res %11.5f $mvdcmp_seC as res %8.2f $mvdcmp_ZC /*
        */                                                     as res %9.3f $mvdcmp_PZC  as res %11.5f $mvdcmp_Cl   as res %11.5f $mvdcmp_Ch   as res %10.2f $mvdcmp_PC
        di as text "{hline 31}{c +}{hline 71}"
        di as text %30s  "R"       , _col(30) as text "{c |}"  as res %11.5f $mvdcmp_R as res %11.5f $mvdcmp_seR as res %8.2f $mvdcmp_ZR /*
        */                                                     as res %9.3f $mvdcmp_PZR as res %11.5f $mvdcmp_Rl   as res %11.5f $mvdcmp_Rh as res %10.2f

        di
        di %~84s as text "Due to Difference in Characteristics (E)"
        di as text "{hline 31}{c TT}{hline 71}"
        di as text %30s "$mvdcmp_depvar", _col(30) as text "{c |}" _col(11) as text %11s "Coef." _col(22) as text %11s "Std. Err." _col(29) as text %8s "z" _col(38) /*
        */ as text %9s "P>|z|" _col(47) as text %24s "[95% Conf. Interval]" _col(71) as text %8s "Pct."
        di as text "{hline 31}{c +}{hline 71}"
forval i = 1/$mvdcmp_nvar2{
        di as text %30s  "${mvdcmp_varname`i'}" , _col(30) as text "{c |}" as res %11.5f ${mvdcmp_DCE`i'}  as res %11.5f ${mvdcmp_seWdx`i'} /*
        */  as res %8.2f ${mvdcmp_ZEWdx`i'} as res %9.3f ${mvdcmp_PZE`i'}  as res %11.5f ${mvdcmp_El`i'}   as res %11.5f ${mvdcmp_Eh`i'}  as res %10.2f ${mvdcmp_PCTcom`i'}
}
        di as text "{hline 31}{c BT}{hline 71}"
        di
        di %~84s as text "Due to Difference in Coefficients (C)"
        di as text "{hline 31}{c TT}{hline 71}"
        di as text %30s "$mvdcmp_depvar", _col(30) as text "{c |}" _col(11) as text %11s "Coef." _col(22) as text %11s "Std. Err." _col(29) as text %8s "z" _col(38) /*
        */ as text %9s "P>|z|" _col(47) as text %24s "[95% Conf. Interval]" _col(71) as text %8s "Pct."
        di as text "{hline 31}{c +}{hline 71}"
forval i = 1/$mvdcmp_nvar {
        di as text %30s  "${mvdcmp_varname`i'}", _col(30) as text "{c |}" as res %11.5f ${mvdcmp_CWdb`i'}  as res %11.5f ${mvdcmp_seWdb`i'} /*
        */ as res %8.2f ${mvdcmp_ZCWdb`i'} as res %9.3f ${mvdcmp_PZC`i'}  as res %11.5f ${mvdcmp_Cl`i'}    as res %11.5f ${mvdcmp_Ch`i'}  as res %10.2f ${mvdcmp_PCTcoe`i'}
}
        di as text "{hline 31}{c BT}{hline 71}"
}
mata: mata drop *
end

******************************
*                            *
*   common mata functions    *
*                            *
******************************

mata:
function Wdx_F(real matrix xMean0, real matrix xMean1, real matrix b0)
		{
			Wdx=J(1, cols(b0), .)
			  A=(xMean0-xMean1)*b0'
				for (i=1; i<=cols(b0); i++){
					Wdx[i]=(xMean0[i]-xMean1[i])*b0[i]':/A
				}
return(Wdx)
	}
end

mata:
function Wdb_F(real matrix b0, real matrix b1, real matrix xMean1)
		{
			Wdb=J(1, cols(xMean1), .)
			  A=xMean1*(b0'-b1')
				for (i=1; i<=cols(b0); i++){
					Wdb[i]=(xMean1[i]*(b0[i]'-b1[i]')):/A
				}
return(Wdb)
	}
end

mata:
function dwA_F(real matrix b0, real matrix b1, real matrix xMean1)
		{
			dwA=J(cols(xMean1), cols(xMean1), .)
			  A=xMean1*(b0'-b1')
				for (i=1; i<=cols(xMean1); i++){
					for (j=1; j<=cols(xMean1); j++){
						if(i==j){
						B = 1
						}
					else{
						B = 0
					}
			dwA[i,j]= B:*xMean1[i]:/A - (xMean1[i]:*xMean1[j]*(b0[i]'-b1[i]')):/A:^2
				}
			}
return (dwA)
	}
end

mata:
function dwB_F(real matrix b0, real matrix b1, real matrix xMean1)
	{
			dwB=J(cols(xMean1), cols(xMean1), .)
			  A=xMean1*(b0'-b1')
				for (i=1; i<=cols(xMean1); i++){
					for (j=1; j<=cols(xMean1); j++){
						if(i==j){
						B = 1
						}
					else{
						B = 0
					}
			dwB[i,j]= (xMean1[i]:*xMean1[j]*(b0[i]'-b1[i]')):/A:^2  - B:*xMean1[i]:/A
				}
			}
return (dwB)
	}
end

mata:
function dW_F(real matrix b0, real matrix xMean0, real matrix xMean1)
	{
			dW=J(cols(xMean1), cols(xMean1), .)
			 A=(xMean0-xMean1)*b0'
				for (i=1; i<=cols(xMean1); i++){
					for (j=1; j<=cols(xMean1); j++){
						if(i==j){
						B = 1
						}
					else{
						B = 0
					}
			dW[i,j]= B:*(xMean0[i]-xMean1[i]):/A - (b0[i]'*(xMean0[i]-xMean1[i]):*(xMean0[j]-xMean1[j])):/A:^2
				}
			}
return (dW)
	}
end

mata:
function dCdb1(real matrix x1, real matrix Wdb, real matrix wbA, real matrix weight, real matrix PDF, real scalar C)
	{
		dCdb1=J(cols(x1), cols(x1), .)
			for (i=1; i<=cols(x1); i++){
				for (j=1; j<=cols(x1); j++){
					dCdb1[i,j]=Wdb[i]:*mean(x1[,j]:*PDF):/mean(weight) :+ wbA[i,j]:*C
				}
			}
return(dCdb1)
	}
end


// fixed Poisson beginning here
mata:
function dCdb1Pois(real matrix x1, real matrix Wdb, real matrix wbA, real matrix weight, real matrix off, real matrix PDF, real scalar C)
	{
			dCdb1=J(cols(x1), cols(x1), .)
				for (i=1; i<=cols(x1); i++){
					for (j=1; j<=cols(x1); j++){
						dCdb1[i,j]=Wdb[i]:*sum(x1[,j]:*PDF):/sum(weight:*off) :+ wbA[i,j]:*C
				}
			}
return(dCdb1)
	}
end

// ending here

mata:
function dCdb2(real matrix x1, real matrix Wdb, real matrix wbB, real matrix weight, real matrix PDF, real scalar C)
	{
			dCdb2=J(cols(x1), cols(x1), .)
				for (i=1; i<=cols(x1); i++){
					for (j=1; j<=cols(x1); j++){
						dCdb2[i,j] = wbB[i,j]:*C - Wdb[i]:*mean(PDF:*x1[,j]):/mean(weight)
				}
			}
return(dCdb2)
	}
end

// fixed Poisson beginning here
mata:
function dCdb2Pois(real matrix x1, real matrix Wdb, real matrix wbB, real matrix weight, real matrix off, real matrix PDF, real scalar C)
	{
			dCdb2=J(cols(x1), cols(x1), .)
				for (i=1; i<=cols(x1); i++){
					for (j=1; j<=cols(x1); j++){
						dCdb2[i,j] = wbB[i,j]:*C - Wdb[i]:*sum(PDF:*x1[,j]):/sum(weight:*off)
				}
			}
return(dCdb2)
	}
end

// ending here

mata:
function dEdb(real matrix x0, real matrix x1, real matrix Wdx,real matrix dWx, real scalar E,
				real matrix w0, real matrix w1, real matrix PDF0, real matrix PDF1)
	{
			dEdb=J(cols(x0), cols(x0), .)
				for (i=1; i<=cols(x0); i++){
					for (j=1; j<=cols(x0); j++){
						dEdb[i,j]= Wdx[i]:*(mean(PDF0:*x0[,j]):/mean(w0)
									:-mean(PDF1:*x1[,j]):/mean(w1)):+dWx[i,j]:*E
				}
			}
return(dEdb)
	}
end

// starting point of Poisson fix
mata:
function dEdbPois(real matrix x0, real matrix x1, real matrix Wdx,real matrix dWx, real scalar E,
					real matrix w0, real matrix w1, real matrix off0, real matrix off1, real matrix PDF0, real matrix PDF1)
	{
			dEdb=J(cols(x0), cols(x0), .)
				for (i=1; i<=cols(x0); i++){
					for (j=1; j<=cols(x0); j++){
						dEdb[i,j]= Wdx[i]:*(sum(PDF0:*x0[,j]):/sum(w0:*off0)
									:-sum(PDF1:*x1[,j]):/sum(w1:*off1)):+dWx[i,j]:*E
				}
			}
return(dEdb)
	}
end

// ending point of Poisson fix

mata:
function varcomp(real matrix dEdb, real matrix varb_beta0)
	{
		Var_E_k= J(cols(dEdb),cols(dEdb),.)
		Var_E_k=dEdb*varb_beta0*dEdb'
return(Var_E_k)
	}
end

mata:
function varcoef(dCdb0, dCdb1, varb0, varb1)
	{
		Var_C_k=J(cols(dCdb1), cols(dCdb1), .)
		Var_C_k = dCdb0*varb0*dCdb0' + dCdb1*varb1*dCdb1'
return(Var_C_k)
	}
end

mata:
function dCdbA(x, weight, PDF) {
		dCdba=J(1, cols(x), .)
			for (i=1; i<=cols(x); i++){
				dCdba[i] = mean(PDF:*x[,i]):/mean(weight)
			}
return(dCdba)
	}
end

mata:
function dCdbAPois(x, weight, off, PDF) {
		dCdba=J(1, cols(x), .)
			for (i=1; i<=cols(x); i++){
				dCdba[i] = sum(PDF:*x[,i]):/sum(weight:*off)
		}
return(dCdba)
	}
end


mata:
function dEdb0(x0, x1, weight0, weight1, PDF0, PDF1)
	{
		dEdb0=J(1,cols(x0), .)
			for (i=1; i<=cols(x0); i++){
				dEdb0[i] = mean(PDF0:*x0[,i])/mean(weight0) - mean(PDF1:*x1[,i]):/mean(weight1)
		}
return(dEdb0)
	}
end


mata:
function dEdb0Pois(x0, x1, weight0, weight1, off0, off1, PDF0, PDF1)
	{
		dEdb0=J(1,cols(x0), .)
			for (i=1; i<=cols(x0); i++){
				dEdb0[i] = sum(PDF0:*x0[,i])/sum(weight0 :*off0) - sum(PDF1:*x1[,i]):/sum(weight1 :*off1)
		}
return(dEdb0)
	}
end


mata:
function varE(real matrix dEdb, real matrix varb0)
	{
		varE0=J(1, cols(dEdb), .)
		varE0=dEdb*varb0*dEdb'
return(varE0)
	}
end

mata:
function varC(varb0, varb1, dCdb0, dCdb1)
	{
		varC0=0
		varC0=dCdb0*varb0*dCdb0' + dCdb1*varb1*dCdb1'
return(varC0)
	}
end

******************************
*                            *
*           PDFs/CDFs        *
*                            *
******************************

//Linear CDF

mata:
function CDF_Linear(real matrix x, real matrix b, real matrix weight)
	{
		F=((x:*weight))*b'
return(F)
	}
end

//Linear pdf

mata:
function PDF_Linear(real matrix weight)
	{
		f=weight
return(f)
	}
end

//Logistic CDF

mata:
function CDF_lgt(real matrix x, real matrix b, real matrix weight)
	{
		xb=x*b'
		F=(exp(xb):/ (1:+exp(xb))):*weight
return(F)
	}
end

//Logistic pdf

mata:
function PDF_lgt(real matrix x, real matrix b, real matrix weight)
	{
		xb=x*b'
		 f=(exp(xb):/(1:+exp(xb)):^2):*weight
return(f)
	}
end

// Poisson/nbreg pdf & CDF

mata:
function pois(real matrix x, real matrix b, real matrix off, real matrix weight)
	{
		xb=x*b'
		 F=exp(xb :+ log(off)):*weight // offset is exposure here...log exposure is offset
return(F)
	}
end

// probit CDF

mata:
function CDF_probit(real matrix x, real matrix b, real matrix weight)
	{
		xb=x*b'
		 F=(normal(xb):*weight)
return(F)
	}
end

// probit pdf

mata:
function PDF_probit(real matrix x, real matrix b, real matrix weight)
	{
		xb=x*b'
		 f=(normalden(xb):*weight)
return(f)
	}
end

// CLL CDF

mata:
function CDF_CLL(real matrix x, real matrix b, real matrix weight)
	{
		xb=x*b'
		F = (1 :- exp(-exp(xb))):*weight
return(F)
	}
end

// CLL pdf

mata:
function PDF_CLL(real matrix x, real matrix b, real matrix weight)
	{
		xb=x*b'
		f = (exp(-exp(xb))):*weight
return(f)
	}
end

//////////////// end subroutines /////////////