*! version 1.1.2 06dec1999
program define treatreg, eclass
	version 6.0

	if replay() {
		if "`e(cmd)'" != "treatreg" {
			noi di in red "results of treatreg not found"
			exit 301
		}
		if "`e(method)'"== "two-step" {
			Display2 `0'
		}
		else    Display `0'
		exit
	}

	if _caller() < 6.0 {
		di in red "treatreg is for version 6 only"
		exit 198
	}
	Estimate `0'
end

program define Estimate, eclass
	version 6
	gettoken dep 0 : 0 , parse(" =,[")
	unab dep : `dep'
	confirm variable `dep'
	gettoken equals rest : 0, parse(" =")

	if "`equals'" == "=" { local 0 `"`rest'"' }

				/* Primary */
	syntax [varlist(default=none)] [if] [in] [pw fw iw aw]    	/*
		*/ , TReat(string)   [ HAzard(string)			/*
		*/ noConstant FIRst Level(integer $S_level)           /*
		*/ MLOpts(string) noLOG Robust  Cluster(varname)	/*
		*/ TWOstep noSKIP * ]

				/* set up command options */

	local ind `varlist'
	local if0 `if'
	local in0 `in'
	local option0 `options'
	local nc `constant'
	local wtype `weight'
	local wtexp `"`exp'"'
	if "`weight'" != "" { local wgt `"[`weight'`exp']"'  }

	if "`weight'" == "pweight" | "`cluster'" != "" {
		local robust "robust"
	}

	if "`hazard'" != "" { confirm new var `hazard' }
	if "`cluster'" != "" { local clusopt "cluster(`cluster')" }

	if "`log'" == "" {
		local showlog noisily
	}
	else local showlog quietly
        if "`skip'" != "" {
                if "`robust'" != "" {
di in blue "model LR test inappropriate with robust covariance estimates"
			local skip
                }
                if "`constan'" != "" {
di in blue "model LR test inappropriate with noconstant option"
                        local skip
                }
                if "`ind'" == "" {
di in blue "model LR test inappropriate with constant-only model"
                      local skip
                }
                if "`twostep'" != "" {
di in blue "model LR test inappropriate for two-step model"
                       local skip
                }
                if "`skip'" == "" {
                       di in blue "    performing Wald test instead"
		}
	}
				/* Parse ML options */

	mlopts stdopts, `option0'

				/* Process selection equation */
	tokenize `"`treat'"', parse(" =")
	if "`2'" ~= "=" {
		di in red "invalid syntax"
		exit 198
	}
	unab 1 : `1'
	local trtdep `1'
	local 1 " "
	local 2 " "
	local 0 `*'
	syntax [varlist(default=none)] [, noConstant ]

				/* set up selection eq options */
	local trtind `varlist'
	local trtnc `constant'

				/* ensure valid selection eq */
	if "`trtnc'" != "" & "`trtind'" ==""{
		noi di in red "no variables specified for treatment"
		exit 198
	}

				/* ensure valid main eq */
	if "`nc'" != "" & "`ind'" == "" {
		noi di in red "no variables pecified for primary equation"
		exit 198
	}

				/* mark sample */

	tempname touse
	mark `touse' `wgt' `if0' `in0'
	markout `touse' `dep' `ind' `trtdep' `trtind'

				/* ensure trtvar are bivariate 1 0 */
	tempname val1 val2
	qui sum `trtdep' if `touse'
	if r(N) == 0 {
		di in red "no observations for treatment equation"
		exit 198
	}
	scalar `val1' = r(min)
	scalar `val2' = r(max)
	if `val1' == `val2' {
		di in red "treatments does not vary"
		exit 2000
	}

	qui count if  `trtdep' != 1 & `trtdep' != 0 & `touse'
	if r(N) != 0 {
		di in red "invalid treatment values. only 0 and 1 are allowed"
		exit 420
	}

				/* test collinearity */

	_rmcoll `ind' `wgt' if `touse', `nc'
	local ind "`r(varlist)'"

				/* model estimation */

	TwoStep "`dep'" "`ind'" "`nc'" "`trtdep'" "`trtind'" /*
		*/ "`trtnc'" "`wgt'" "`wtype'" "`wtexp'"     /*
		*/ `touse' "`first'" "`hazard'"


	if "`twostep'" == "" {

		tempname b1 athrho lnsigma llreg llprob
		scalar `llprob' =e(ll_p)

				/* initial values */
		mat `b1' = e(b)
		mat `b1'= `b1'[1, 1..colsof(`b1')-1]
		scalar `athrho' = max(min(e(rho), .85), -.85)
		scalar `athrho' = 1/2*ln((1+`athrho')/(1-`athrho'))
		scalar `lnsigma' = ln(e(sigma))
		mat `b1' = `b1', `athrho', `lnsigma'

		local hazard `e(hazard)'
		qui reg `dep' `ind' `trtdep' `wgt' if `touse', `nc'
		scalar `llreg' = e(ll)
		if "`skip'" == "noskip" {
				/* constant only model */

			TwoStep "`dep'" "" "`nc'" "`trtdep'" "" "`trtnc'"   /*
				*/ "`wgt'" "`wtype'" "`wtexp'" `touse'      /*
				*/ "`first'" "`hazard'"

			tempname b0 athrho lnsigma
			mat `b0' = e(b)
			mat `b0'= `b0'[1, 1..colsof(`b0')-1]
			scalar `athrho' = max(min(e(rho), .85), -.85)
			scalar `athrho' = 1/2*ln((1+`athrho')/(1-`athrho'))
			scalar `lnsigma' = ln(e(sigma))
			mat `b0' = `b0', `athrho', `lnsigma'
			local continu "continue"
			est clear
			`showlog' di
			`showlog' di in green "Fitting constant-only model:"
			Mmethod "`dep'" "" "`nc'" "`trtdep'" "" /*
				*/ "`trtnc'" "`wgt'" "`wtype'" "`wtexp'"    /*
				*/ `touse' "`b0'"  "`robust'"   /*
				*/ "`clusopt'" "`log'" "" "`stdopts'"
			`showlog' di
			`showlog' di in green "Fitting full model:"
		}

		Mmethod "`dep'" "`ind'" "`nc'" "`trtdep'" "`trtind'" /*
			*/ "`trtnc'" "`wgt'" "`wtype'" "`wtexp'"    /*
			*/ `touse' "`b1'"  "`robust'"   /*
			*/ "`clusopt'" "`log'" "`continu'" "`stdopts'"

				/* comparison test */

		if "`robust'" != "" {
			est local chi2_ct "Wald"
			qui test [athrho]_b[_cons] = 0
			est scalar chi2_c = r(chi2)
		}
		else {
			est local chi2_ct "LR"
			est scalar chi2_c = 2*(e(ll) - `llreg'- `llprob' )
		}
		est scalar p_c = chiprob(1, e(chi2_c))

		Reparm
		est local title "Treatment effects model -- MLE"
		if "`hazard'" != "" { est local hazard "`hazard'" }
		Display, level(`level')
	}
	else {
		if "`robust'`cluster'`wgt'" != ""{
			di in red "robust, cluster and weights not allowed" /*
				*/ " with the twostep option"
			est clear
			exit 198
		}

		est local title "Treatment effects model -- two-step estimates"
		Display2, level(`level')
		est local depvar `dep' `trtdep'
		est local method "twostep"
		est local ll_p
	}
	est local cmd "treatreg"
	est local predict "treatr_p"
end

program define TwoStep, eclass
	args 		dep	/*
		*/	ind	/*
		*/	nc	/*
		*/	trtdep	/*
		*/	trtind	/*
		*/	trtnc	/*
		*/	wgt	/*
		*/	wtype	/*
		*/	wtexp	/*
		*/	touse	/*
		*/	first   /*
		*/	hazard
	if "`first'" != "" {local first noi }

	tempname bprb vprb bregx vreg breg llprob
	tempvar xbprb lambda tao

				/* Step1 -- probit */
	qui{
		`first' probit `trtdep' `trtind' `wgt' if `touse',  /*
			*/ nolog `trtnc'
		mat `vprb' = get(VCE)
		mat `bprb' = get(_b)
		scalar `llprob' = e(ll)
		predict double `xbprb', xb
		gen double `lambda' = normd(`xbprb')/normprob(`xbprb') /*
			*/ if `trtdep' == 1 & `touse'
		replace  `lambda' = -normd(`xbprb')/(1-normprob(`xbprb')) /*
			*/ if `trtdep' == 0 & `touse'
		if "`hazard'" != "" { gen double `hazard' = `lambda' }
		gen double `tao' = `lambda'*(`lambda' + `xbprb')
	}
				/* Step 2 -- regress */

	qui{
		if "`nc'" =="" {
			tempvar one
			gen byte `one' = 1
		}
		reg `dep' `ind' `trtdep' `one' `lambda' `wgt' if `touse', noc
		mat `breg' = get(_b)
		mat `vreg' = get(VCE)
		local blambda _coef[`lambda']
		sum `tao' `wgt' if `touse'
		local mtao r(mean)
		local sigma =sqrt(e(rss)/e(N) + `mtao'*`blambda'^2)
		local rho = `blambda'/`sigma'
		if `sigma' == 0 { local sigma = .001}
		if `rho' == . { local rho = 0 }
		if abs(`rho') > 1 {
			local rho = `rho'/abs(`rho')
		}
		local rho2= `rho'*`rho'
	}

				/* Cov adjustment */

	tempname  XsI Vbs F Q
	if e(rmse) != 0 {
		matrix `XsI' = `vreg' / (e(rmse)^2)
	}
	else {
		di in red "insufficient information"
		exit 2000
	}

	local fulnam `ind'
	local fulnam "`fulnam' `trtdep'"
	if "`nc'" == ""{
		tempvar one
		gen byte `one' = 1
		local fulnam "`fulnam' _cons"
	}
	local fulnam "`fulnam' lambda"
	local kreg : word count `fulnam'
	local kreg1 = `kreg' + 1
	qui mat accum `F' = `ind' `trtdep' `one' `lambda' `trtind' /*
		*/ [iw = `tao'], `trtnc', if `touse'
	mat `F' = `F'[1.. `kreg', `kreg1' ...]
	mat rowname `F' = `fulnam'
	mat `Q' = `rho2'*`F'*`vprb'*`F''

 	tempvar rho2tao
	qui gen double `rho2tao' = 1 - `rho2'*`tao' if `touse'
	qui mat accum `Vbs' = `ind' `trtdep' `one' `lambda' [iw=`rho2tao'], /*
		*/ nocons, if `touse'
	mat `Vbs' = `sigma'^2 * `XsI' *(`Vbs' + `Q')*`XsI'

				/* Build the eqn names */
	local eqnam
	tokenize `fulnam'
	local i 1
	while `i' < `kreg' {
		local eqnam `eqnam' `dep':``i''
		local i= `i' + 1
	}

	local trtname `trtdep'
	local kprb : word count `trtind'
	local i 1
	tokenize `trtind'
	while `i' <= `kprb' {
		local eqnam `eqnam' `trtname':``i''
		local i = `i' + 1
	}
	if "`trtnc'" =="" {
		local kprb = `kprb' + 1
		local eqnam `eqnam' `trtname':_cons
	}
	local eqnam `eqnam' hazard:lambda

	tempname bfull Vfull zeros Vmills CovMill zeroPrb b0 bmills
	local kreg0 = `kreg' -1
	mat `b0' = `breg'[1, 1..`kreg0']
	mat `bmills' = `breg'[1, `kreg']
	mat `bfull' = `b0', `bprb', `bmills'
	mat `Vmills' = `Vbs'[`kreg', `kreg']
	mat `CovMill' = `Vbs'[1..`kreg0', `kreg']
	mat `Vbs' = `Vbs'[1..`kreg0', 1..`kreg0']
	mat `zeros' = J(`kreg0', `kprb', 0)
	mat `zeroPrb' = J(`kprb', 1, 0)
	mat `Vbs' = /*
		*/ ( `Vbs'	, `zeros'	, `CovMill' \	/*
		*/   `zeros''	, `vprb'	, `zeroPrb'  \  /*
		*/   `CovMill'', `zeroPrb''	, `Vmills' )
	mat colnames `bfull' = `eqnam'
	mat rownames `Vbs' = `eqnam'
	mat colnames `Vbs' = `eqnam'

	qui count if `touse'
	est post `bfull' `Vbs', obs(`r(N)')
	est scalar N = `r(N)'
	capture qui test `ind' `trtdep', min
	if _rc == 0 {
		est scalar chi2 = `r(chi2)'
		est scalar df_m = `r(df)'
		est scalar p    = `r(p)'
	}
	est local chi2type "Wald"
	if "`hazard'" !="" { est local hazard `hazard'}
	est scalar rho= `rho'
	est scalar sigma = `sigma'
	est scalar lambda = [hazard]_b[lambda]
	est scalar selambda = [hazard]_se[lambda]
	est scalar ll_p = `llprob'
end


program define Mmethod, eclass
	args 		dep	/*
		*/	ind	/*
		*/	nc	/*
		*/	trtdep	/*
		*/	trtind	/*
		*/	trtnc	/*
		*/	wgt	/*
		*/	wtype	/*
		*/	wtexp	/*
		*/	touse	/*
		*/	b0 	/*
		*/	robust	/*
		*/	clusopt	/*
		*/      log     /*
		*/ 	continu /*
		*/	stdopts
	ml model lf treat_ll					/*
		*/ (`dep': `dep' = `ind' `trtdep', `nc')	/*
		*/ (`trtdep': `trtdep' = `trtind', `trtnc')	/*
		*/ /athrho /lnsigma 				/*
		*/ if `touse' `wgt',				/*
		*/ `robust' `clusopt'				/*
		*/ collinear missing max nooutput nopreserve	/*
		*/ init(`b0', copy) search(off) `log' `continu' /*
		*/ `stdopts' `mlopts'
	est local method "ml"
end

program define Display2
	syntax [, level(integer $S_level) ]
	#delimit ;
	di in gr _n "`e(title)'" _col(49) "Number of obs"
		in gr _col(68) "="
		in ye _col(70) %9.0g e(N) ;

	local chifmt = cond(e(chi2)<1e+6,"%9.2f","%9.2e") ;
	di in gr _n _col(49) "`e(chi2type)' chi2(" in ye e(df_m) in gr ")"
		in gr _col(68) "="
		in ye _col(70) `chifmt' e(chi2) ;
	di in gr _col(49) "Prob > chi2"
		in gr _col(68) "="
		in ye _col(73) %6.4f chiprob(e(df_m),e(chi2)) _n ;
	#delimit cr
	est display, level(`level')
	di in gr "     rho | " in ye %10.5f e(rho)
	di in gr "   sigma | " in ye %10.0g e(sigma)
	di in gr "  lambda | " in ye %10.0g e(lambda) "  " %9.0g e(selambda)
	di in gr _dup(79) "-"

end

program define Reparm, eclass

			/* somewhat superceded by _diparm, but kept for
			 * lambda and so sigma and rho can be saved in e() */

	tempname b v d tau lns rho sig tmp lambda lamse
	mat `b' = get(_b)
	mat `v' = get(VCE)

	mat `tmp' = `b'[1,"athrho:_cons"]
	scalar `tau' = `tmp'[1,1]
	mat `tmp' = `b'[1,"lnsigma:_cons"]
	scalar `lns' = `tmp'[1,1]

	scalar `rho' = (exp(2*`tau')-1) / (exp(2*`tau')+1)
	scalar `sig' = exp(`lns')
	scalar `lambda' = `rho'*`sig'

	mat `d' =  ( `sig'*4*exp(2*`tau')/(exp(2*`tau')+1)^2 , `lambda' )
	mat `v' =  (`v'["athrho:_cons".."lnsigma:_cons",      /*
		*/   "athrho:_cons".."lnsigma:_cons"]  )
	mat `v' = `d'*`v'*`d''
	scalar `lamse' = sqrt(`v'[1,1])

	est scalar rho    = `rho'
	est scalar sigma  = `sig'
	est scalar lambda = `lambda'
	est scalar selambda  = `lamse'
	/*  Double saves for backward compatibility */
	global S_1 = `rho'
	global S_2 = `sig'
	global S_3 = `lambda'
	global S_4 = `lamse'
end

program define Display
	syntax [, Level(integer $S_level)]

	#delimit ;
	di in gr _n "`e(title)'" _col(49) "Number of obs"
		in gr _col(68) "="
		in ye _col(70) %9.0g e(N) ;

	local chifmt = cond(e(chi2)<1e+6,"%9.2f","%9.2e") ;
	di in gr _n _col(49) "`e(chi2type)' chi2(" in ye e(df_m) in gr ")"
		in gr _col(68) "="
		in ye _col(70) `chifmt' e(chi2) ;
	di in gr "Log likelihood = "e(ll) _col(49) "Prob > chi2"
		in gr _col(68) "="
		in ye _col(73) %6.4f chiprob(e(df_m),e(chi2)) _n ;
	#delimit cr

	est display, level(`level') neq(2) plus
	_diparm athrho, level(`level')
	_diparm lnsigma, level(`level')
	di in gr _dup(9) "-" in gr "+" _dup(69) "-"
	_diparm athrho, level(`level') tanh label("rho")
	_diparm lnsigma, level(`level') exp label("sigma")
	DiLambda `level'
	di in gr _dup(79) "-"
	if "`e(vcetype)'" != "Robust" {
		local testtyp LR
	}
	else local testyp Wald
	di in gr  "`testtyp' test of indep. eqns. (rho = 0):" /*
		*/ _col(38) "chi2(" in ye "1" in gr ") = "   /*
		 */ in ye %8.2f e(chi2_c)                     /*
		 */ _col(59) in gr "Prob > chi2 = " in ye %6.4f e(p_c)
	di in gr _dup(79) "-"
end

program define DiLambda
	args level

	tempname z lb ub

	scalar `z' = invnorm((100 + `level') / 200)
	scalar `lb' = e(lambda) - `z'*e(selambda)
	scalar `ub' = e(lambda) + `z'*e(selambda)

	local llb : di %9.0g `lb'
	if length("`llb'") > 9 {
		local lbfmt "%8.0g"
	}
	else	local lbfmt "%9.0g"

	local uub : di %9.0g `ub'
	if length("`uub'") > 9 {
		local ubfmt "%8.0g"
	}
	else	local ubfmt "%9.0g"

	di in gr _col(3) "lambda |  " /*
		*/  in ye %9.0g e(lambda) "  " %9.0g e(selambda)    /*
		*/  _col(58) `lbfmt' `lb' "   "  `ubfmt' `ub'

end