*!   attregtest v2.0.0  GHO13Nov2023


program attregtest, rclass
	version    13
	syntax     varlist(min=1 numeric) [if] [in], treatvar(varlist numeric max=1) respvar(varlist numeric  max=1)  [ vce(passthru) stratavar(varlist numeric max=1) timevar(varlist numeric fv max=1) export(string)]

	marksample touse, novarlist
	local      res   p_IVP  p_IVR  pIVR1 pIVP1 pIVR2 pIVP2
	tempname   `res'


* ##########################
*		WARNINGS
* ##########################

	local nbasevars: word count `varlist'
	local nrespvars: word count `respvar'

	if  `nrespvars' > 1 {
		display in red "Error: the number of response variables must be equal to one"
		exit
	}


	qui: count if `treatvar'==0
		if `r(N)'==0 {
			display in red "Error: the control group must take the value of zero"
			exit
		}


	qui: count if `respvar'==0
	if `r(N)'==0 {
		display in red "Error: response variable `var' must take the value of zero for attritors"
		exit
	}


	cap: ds response
	local nwords :  word count `r(varlist)'
		if `nwords'>0 {
			display in red "Error: none of the variables in the dataset can be named response"
			exit
		}

	forvalues i=1/`nbasevars' {
		local varname: word `i' of `varlist'
		qui: count if missing(`varname')
		if  `r(N)' > 0 {
			display in red "Error: none of the variables in `varlist' should have missing values"
		}
	}

* ##########################################
*  COMPLETELY OR CLUSTER RANDOMIZED TRIALS
* ##########################################


if 	"`stratavar'"=="" {

	eststo clear


	* =============================
	* LOCALS WITH NAMES AND VALUES
	* =============================

	*Store the values of the treatment variable in local "treatlevels"
	qui:	   levelsof  `treatvar', local(treatlevels)

	*Store the G number of treatment groups (including the control group) in local "ngroups"
	local      ngroups: word count `treatlevels'

	*Store name of baseline variables in local "basevars"
	gettoken    first rest: varlist
	local       basevars "`first' `rest'"


	*==================================
	* GENERATE TREATMENT VARIABLES
	*==================================

	* Generate dummy variables for all treatment groups & store this varlist in  local "treatvars"
	foreach      l in `treatlevels' {
	    qui: gen 	`treatvar'`l'=cond(`treatvar'==`l',1,0)
		qui: replace  `treatvar'`l'=. if `treatvar'==.
		local    treatvars "`treatvars' `treatvar'`l'"
	}

	* Group of all dummy variables for treatment groups,  excluding the first category
	gettoken    first rest: treatvars
	local       treatvars_minus1 "`rest'"

	*============================================================================
	* CONDUCT THE TESTS OF IV-R and IV-P FOR CASE IN WHICH # VARLIST =1
    *               AND SAVE ESTIMATES FOR OUTPUT TABLE
    *============================================================================

    if `nbasevars' == 1 {

	   eststo clear
	   capture macro drop _treatresp


		*------------------------------------------
		* GENERATE TREATMENT/RESPONSE INTERACTIONS
		*-------------------------------------------

		* Store list of interactions in local "treatresp"
		qui: gen response=`respvar'
		foreach      g in `treatvars_minus1' {
			gen		 `g'Xresponse=`g'*response
			local     treatresp "`treatresp' `g'Xresponse"
		}


		*--------------------------------
		* ESTIMATE REGRESSION MODEL
		* Note: estimation with constant
		*--------------------------------

		*If option timevar is not specified

		if "`timevar'"=="" {
			qui: regress	  `basevars'  `treatresp'  `treatvars_minus1' response if `touse' ,  `vce'
			qui: estimates  store model_z1, title("`basevars'")
		}


		*If option timevar is specified

		if "`timevar'"!="" {
			qui xi: regress	  `basevars' `treatresp' `treatvars_minus1' response i.`timevar'  if `touse' ,  `vce'
			qui: estimates  store model_z1, title("`basevars'")
		}

        *--------------------------------
		*   SET UP NULL HYPOTHESES
		*--------------------------------

        *Set up H0 for IV-R
		local     ivr_vars "`treatvars_minus1' `treatresp'"

		foreach 	v in `ivr_vars' {
			local   ivr_null " `ivr_null' = `v'"
		}
		local ivr_null "`ivr_null'=0"
		gettoken   first ivr_null: ivr_null, parse(" ")


		*Set up H0 for IV-P
		local     ivp_vars "`treatvars_minus1' response `treatresp'"

		foreach 	v in `ivp_vars' {
			local   ivp_null " `ivp_null' = `v'"
		}
		local ivp_null "`ivp_null'=0"
		gettoken   first ivp_null: ivp_null, parse(" ")

        *--------------------------------
		*   TEST NULL HYPOTHESES
		*--------------------------------

		*Test of IV-R
		qui: test   `ivr_null'
		qui: estadd scalar    p_IVR=r(p): model_z1
		return scalar p_IVR = r(p)

		*Test of IV-P
		qui: test `ivp_null'
		qui: estadd scalar    p_IVP=r(p): model_z1
		return scalar p_IVP = r(p)

		*-----------------------------------------------------------------
		* CALCULATES THE MEAN BASELINE VARIABLE FOR CONTROL ATTRITORS
		* Note: assumes control group corresponds to first category (value=0)
		*-----------------------------------------------------------------

		qui: levelsof  `treatvar', local(treatlevels)
		qui: gettoken    first rest: treatlevels
		qui: sum `basevars' if `treatvar'==`first' & response==0 & `touse'
		qui: estadd scalar meanCA=r(mean): model_z1
		return scalar meanCA = r(mean)


		cap: drop  `treatresp'  response



    }

    *============================================================================
	* CONDUCT THE TESTS OF IV-R and IV-P FOR CASE IN WHICH # VARLIST > 1
    *               AND SAVE ESTIMATES FOR OUTPUT TABLE
    *============================================================================

    if `nbasevars' > 1 {

        *-------------------------------------------
        * GENERATE TREATMENT/RESPONSE INTERACTIONS
        *-------------------------------------------
        * Store list of interactions in local "treatresp"
        qui: gen response=`respvar'
        foreach      g in `treatvars_minus1' {
			gen		 `g'Xresponse=`g'*response
			local     treatresp "`treatresp' `g'Xresponse"
		}


        local i=0
        eststo clear
        foreach var of local basevars {

            local i=`i'+1

            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            * ESTIMATE REGRESSION WITH `vce' FOR OUTPUT TABLE
            * Note: (i)  estimation with constant
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            * If option timevar is not specified

            if "`timevar'"=="" {
                qui: regress	  `var'  `treatresp'  `treatvars_minus1' response if `touse' ,  `vce'
                qui: estimates  store model_z`i', title("`var'")
            }


            * If option timevar is specified
            if "`timevar'"!="" {
                qui xi: regress	  `var' `treatresp' `treatvars_minus1' response i.`timevar'  if `touse' ,  `vce'
                qui: estimates  store model_z`i', title("`var'")
            }


            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            * ESTIMATE REGRESSION MODELS FOR SUEST
            * Notes: (i)  estimation with constant
            *	     (ii) no `vce' here because suest accounts for it
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            * If option timevar is not specified

            if "`timevar'"=="" {
                qui: regress	  `var'  `treatresp'  `treatvars_minus1' response if `touse'
                qui: estimates  store modelsuest_z`i', title("`var'")
            }


            * If option timevar is specified
            if "`timevar'"!="" {
                qui xi: regress	  `var' `treatresp' `treatvars_minus1' response i.`timevar'  if `touse'
                qui: estimates  store modelsuest_z`i', title("`var'")
            }

            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            *  SET UP NULL HYPOTHESIS IV-R
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


            * Individual H0
            local     ivr_vars "`treatvars_minus1' `treatresp'"

            foreach 	v in `ivr_vars' {
                local   ivr_null_`i' "`ivr_null_`i'' = [modelsuest_z`i'_mean]`v'"
            }


            local ivr_null_`i' "`ivr_null_`i''=0"
            gettoken   first ivr_null_`i': ivr_null_`i', parse(" ")
            local ivr_null_`i' "(`ivr_null_`i'')"

            * Joint H0 across all z variables
            local   ivr_null_multz "`ivr_null_multz'  `ivr_null_`i''"


            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            *  SET UP NULL HYPOTHESIS IV-P
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            * Individual H0

            local     ivp_vars "`treatvars_minus1' response `treatresp' "

            foreach 	v in `ivp_vars' {
                local   ivp_null_`i' " `ivp_null_`i'' = [modelsuest_z`i'_mean]`v'"
            }
            local ivp_null_`i' "`ivp_null_`i''=0"
            gettoken   first ivp_null_`i': ivp_null_`i', parse(" ")
            local ivp_null_`i' "(`ivp_null_`i'')"

            * Joint H0 across all z variables
            local   ivp_null_multz "`ivp_null_multz'  `ivp_null_`i''"


            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		    * CALCULATES THE MEAN BASELINE VARIABLE FOR CONTROL ATTRITORS
		    * Note: assumes control group corresponds to first category (value=0)
		    *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            qui: levelsof  `treatvar', local(treatlevels)
            qui: gettoken    first rest: treatlevels
            qui: sum `var' if `treatvar'==`first' & response==0 & `touse'
            qui: estadd scalar meanCA=r(mean): model_z`i'

        }


        *-----------------------------------------------
        * COMBINE ESTIMATION RESTULTS WITH SUEST
        * Note: standard errors are taken care of here
        *-----------------------------------------------

        forvalues i = 1/`nbasevars' {
            local modelsfor_suest " `modelsfor_suest' modelsuest_z`i'"
        }

        qui: suest  `modelsfor_suest'  , `vce'


        *-----------------------------------------------
        * JOINT TESTS OF IV-R AND IV-P
        *-----------------------------------------------

        * Test of IV-R
        qui: test   `ivr_null_multz'
        qui: estadd scalar    p_IVR=r(p) : model_z`nbasevars'
		return scalar p_IVR = r(p)

        *Test of IV-P
        qui: test `ivp_null_multz'
        qui: estadd scalar    p_IVP=r(p) : model_z`nbasevars'
		return scalar p_IVP = r(p)

        cap: drop  `treatresp'  response


    }


	*========================
	* DROP CREATED VARIABLES
	*========================

	cap:   drop `treatvars'   _est*


	*=======================
	* PRODUCE OUTPUT TABLE
	*=======================

    forvalues i = 1/`nbasevars' {
		local modelsz " `modelsz' model_z`i'"
	}

	if `nbasevars' == 1 {

        if "`vce'"=="" {
            esttab `modelsz' , cells(b(fmt(3)) se(par fmt(3))) ///
            legend label    nostar            ///
            stats(meanCA  N  p_IVR p_IVP , fmt(3 0 3 3) label("Mean value for control attritors" "Observations" "Test of IV-R (p-val)" "Test of IV-P (p-val)" )) ///
            addnotes("The attrition tests correspond to the conditions on the equality of means provided in Eq. (15) in the paper.") ///
			varwidth(32)
        }


	  	if "`vce'"!="" {
			esttab `modelsz',  cells(b(fmt(3)) se(par fmt(3))) ///
			legend label   nostar             ///
			stats(meanCA N p_IVR p_IVP, fmt(3 0 3 3) label("Mean value for control attritors" "Observations" "Test of IV-R (p-val)" "Test of IV-P (p-val)" )) ///
			addnotes("The attrition tests correspond to the conditions on the equality of means provided in Eq. (15) in the paper." ///
					"Standard errors are `vce'.")	///
			varwidth(32)
		}

	}


	if `nbasevars' > 1 {

	  	if "`vce'"=="" {
			esttab `modelsz' , cells(b(fmt(3)) se(par fmt(3))) ///
			legend label    nostar            ///
			stats(meanCA  N p_IVR p_IVP, fmt(3 0 3 3) label("Mean value for control attritors" "Observations" "Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
			addnotes("The attrition tests are conditions on the joint equality of means across all baseline variables (see Eq. (16) in the paper).") ///
			varwidth(32)
		}


	  	if "`vce'"!="" {
			esttab `modelsz',  cells(b(fmt(3)) se(par fmt(3))) ///
			legend label   nostar             ///
			stats(meanCA  N p_IVR p_IVP, fmt(3 0 3 3) label("Mean value for control attritors" "Observations" "Test of IV-R (p-val)" "Test of IV-P (p-val)" )) ///
			addnotes("The attrition tests are conditions on the joint equality of means across all baseline variables (see Eq. (16) in the paper)." ///
					"Standard errors are `vce'.") ///
			varwidth(32)
		}

	}




	*=========================
	* EXPORT OUTPUT TABLE
	*=========================

	if "`export'"!=""{


        if `nbasevars' == 1 {

            if "`vce'"=="" {
                esttab `modelsz' using "`export'", cells(b(fmt(3)) se(par fmt(3))) ///
                legend label    nostar            ///
				stats(meanCA  N  p_IVR p_IVP , fmt(3 0 3 3) label("Mean value for control attritors" "Observations" "Test of IV-R (p-val)" "Test of IV-P (p-val)" )) ///
				addnotes("The attrition tests correspond to the conditions on the equality of means provided in Eq. (15) in the paper.") ///
				varwidth(32)
            }


            if "`vce'"!="" {
                esttab `modelsz' using "`export'",  cells(b(fmt(3)) se(par fmt(3))) ///
                legend label   nostar             ///
				stats(meanCA N p_IVR p_IVP, fmt(3 0 3 3) label("Mean value for control attritors" "Observations" "Test of IV-R (p-val)" "Test of IV-P (p-val)" )) ///
				addnotes("The attrition tests  correspond to the conditions on the equality of means provided in Eq. (15) in the paper." ///
						"Standard errors are `vce'.")	///
				varwidth(32)
            }

        }


        if `nbasevars' > 1 {

            if "`vce'"=="" {
                esttab `modelsz' using "`export'" , cells(b(fmt(3)) se(par fmt(3))) ///
                legend label    nostar            ///
				stats(meanCA  N p_IVR p_IVP, fmt(3 0 3 3) label("Mean value for control attritors" "Observations" "Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
				addnotes("The attrition tests are conditions on the joint equality of means across all baseline variables (see Eq. (16) in the paper.)") ///
				varwidth(32)
            }


            if "`vce'"!="" {
                esttab `modelsz' using "`export'",  cells(b(fmt(3)) se(par fmt(3))) ///
                legend label   nostar             ///
				stats(meanCA  N p_IVR p_IVP, fmt(3 0 3 3) label("Mean value for control attritors" "Observations" "Test of IV-R (p-val)" "Test of IV-P (p-val)" )) ///
				addnotes("The attrition tests are conditions on the joint equality of means across all baseline variables (see Eq. (16) in the paper.)" ///
						"Standard errors are `vce'.") ///
				varwidth(32)
				}

        }
    }

}



* ########################################
*	 STRATIFIED RANDOMIZED TRIALS
* ########################################


if "`stratavar'"!="" {

	eststo clear

	* ================================
	* LOCALS WITH NAMES AND VALUES
	* ================================


	*Store the values of the treatment variable in local "treatlevels"
	qui:	   levelsof  `treatvar', local(treatlevels)

	*Store the G number of treatment groups (including the control group) in local "ngroups"
	local      ngroups: word count `treatlevels'

	*Store name of baseline variables in local "basevars"
	gettoken    first rest: varlist
	local       basevars "`first' `rest'"

	*Store the values of the strata variable in local "stratalevels"
	qui:	   levelsof  `stratavar', local(stratalevels)

	*Store S number of strata groups in local nstrata
	local      sgroups: word count `stratalevels'



	* ===========================================================
	* GENERATE TREATMENT, STRATA, AND TREATMENT STRATA VARIABLES
	* ===========================================================

	* Generate dummy variables for all treatment groups (including control) & store this varlist in  local "treatvars"
	foreach      l in `treatlevels' {
	    qui:     gen 	`treatvar'`l'=cond(`treatvar'==`l',1,0)
		cap:     replace  `treatvar'`l'=. if `treatvar'==.
		local    treatvars "`treatvars' `treatvar'`l'"
	}


	* Generate dummy variables for all strata groups  & store this varlist in  local "stratavars"
	foreach      l in `stratalevels' {
	    qui:    gen 	`stratavar'`l'=cond(`stratavar'==`l',1,0)
		cap:    replace  `stratavar'`l'=. if `stratavar'==.
		local    stratavars "`stratavars' `stratavar'`l'"
	}


	* Group of all dummy variables for treatment groups,  excluding the first category
	gettoken    first rest: treatvars
	local       treatvars_minus1 "`rest'"


	* Group of all dummy variables for strata groups,  excluding the first category
	gettoken    first rest: stratavars
	local       stratavars_minus1 "`rest'"



	*Group treatment/strata interactions:
	foreach      s in `stratavars' {
	foreach      g in `treatvars_minus1' {
		qui:     gen `g'X`s'=`g'*`s'
		local     int_treatstrata`s' "`int_treatstrata`s'' `g'X`s'"
	}
		local     int_treatstrata "`int_treatstrata' `int_treatstrata`s'' "
	}

    *============================================================================
	* CONDUCT THE TESTS OF IV-R and IV-P FOR CASE IN WHICH # VARLIST = 1
    *               AND SAVE ESTIMATES FOR OUTPUT TABLE
    *============================================================================

    if `nbasevars' ==1 {

        *eststo clear
        capture macro drop _int_treatresp _int_respstrata _int_trs  _ivr_vars _ivr_null _ivp_vars _ivp_null _ivr_vars_fe _ivr_null_fe _ivp_vars_fe _ivp_null_fe


		*------------------------------------------
		* GENERATE TREATMENT/RESPONSE INTERACTIONS
		*------------------------------------------

		*Group of interactions: treatment/response
        qui: gen response=`respvar'

		foreach      g in `treatvars_minus1' {
			gen		 `g'Xresponse=`g'*response
			local     int_treatresp "`int_treatresp' `g'Xresponse"
		}

		*Group of interactions: strata/response
		foreach      s in `stratavars' {
			qui: 	 gen	responseX`s'=response*`s'
			local     int_respstrata "`int_respstrata' responseX`s'"
		}


		* Group of interactions:  treatment/respondents/strata
		foreach      s in `stratavars' {
		foreach      g in `treatvars_minus1' {
			gen		 `g'XresponseX`s'=`g'*response*`s'
			local     int_trs`s' "`int_trs`s'' `g'XresponseX`s'"
		}
			local     int_trs "`int_trs' `int_trs`s''"
		}




		*------------------------------------------------------
		* SAVE NULL HYPOTHESES IN LOCALS: FULLY SATURATED MODEL
		*------------------------------------------------------

		* TEST OF IV-R

		local   ivr_vars "`int_treatstrata' `int_trs'"

		foreach 	v in `ivr_vars' {
			local   ivr_null " `ivr_null' = `v'"
		}
		local ivr_null "`ivr_null'=0"
		gettoken   first ivr_null: ivr_null, parse(" ")



		* TEST OF IV-P

		local   ivp_vars " `int_treatstrata' `int_respstrata' `int_trs'"

		foreach 	v in `ivp_vars' {
			local   ivp_null " `ivp_null' = `v'"
		}
		local ivp_null "`ivp_null'=0"
		gettoken   first ivp_null: ivp_null, parse(" ")



		*--------------------------------------------------------
		* SAVE NULL HYPOTHESES IN LOCALS: MODEL W STRATA FE ONLY
		*--------------------------------------------------------


		 *Test of IV-R

        local   ivr_vars_fe "`treatvars_minus1' `int_treatresp'"

        foreach 	v in `ivr_vars_fe' {
            local   ivr_null_fe " `ivr_null_fe' = `v'"
        }
        local ivr_null_fe "`ivr_null_fe'=0"
        gettoken   first ivr_null_fe: ivr_null_fe, parse(" ")




        *Test of IV-P

        local   ivp_vars_fe "`treatvars_minus1' response `int_treatresp'"

        foreach 	v in `ivp_vars_fe' {
            local   ivp_null_fe " `ivp_null_fe' = `v'"
        }
        local ivp_null_fe "`ivp_null_fe'=0"
        gettoken   first ivp_null_fe: ivp_null_fe, parse(" ")



		*----------------------------------------------------------------------
		* REGRESSION TESTS
		* Note: three regressions -- see details in Section B of paper
		*	(1) Strata FE only model: specification for IV-P test
		*	(2) Strata FE only model: specification for IV-R test
        *   (3) Fully saturated model with strata FE and strata-specific coeff
		*----------------------------------------------------------------------


            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            * IF OPTION TIMEVAR IS NOT SPECIFIED
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		    if "`timevar'"=="" {

            * (1) ESTIMATION OF STRATA FE ONLY MODEL: SPECIFICATION OF IV-P TEST

			    qui: regress	  `basevars'  `int_treatresp' `treatvars_minus1' response `stratavars'  if `touse' ,  nocons `vce'
			    qui: estimates  store model_z1, title("`basevars'")

				*Test of IV-P
				qui: test    `ivp_null_fe'
				qui: estadd scalar    pIVP2=r(p) : model_z1
				return scalar pIVP2 = `r(p)'


			* (2) ESTIMATION OF STRATA FE ONLY MODEL: SPECIFICATION OF IV-R TEST
			    // no need to save estimates b/c output table only reports p-val

			    qui: regress	  `basevars'  `int_respstrata' `treatvars_minus1'  `int_treatresp' `stratavars'  if `touse' ,  nocons `vce'


				*Test of IV-R
				qui: test     	`ivr_null_fe'
                qui: estadd scalar    pIVR2=r(p) : model_z1
				return scalar pIVR2 = `r(p)'

            * (3) ESTIMATION OF FULLY SATURATED MODEL
                // no need to save estimates b/c output table only reports p-val

			    qui: regress	  `basevars' `stratavars' `int_respstrata' `int_treatstrata'   `int_trs'   if `touse' , nocons  `vce'


				*Test of IV-R
				qui: test      `ivr_null'
                qui: estadd scalar    pIVR1=r(p) : model_z1
				return scalar pIVR1 = r(p)

				*Test of IV-P
				qui: test       `ivp_null'
                qui: estadd scalar    pIVP1=r(p) : model_z1
				return scalar pIVP1= r(p)

			    qui: estadd local modelfe ""
			    qui: estadd local satmodel ""

			}

            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            * IF OPTION TIMEVAR IS SPECIFIED
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		    if "`timevar'"!="" {


            * (1) ESTIMATION OF STRATA FE ONLY MODEL: SPECIFICATION OF IV-P TEST

			    qui xi: regress	  `basevars'  `int_treatresp' `treatvars_minus1' response `stratavars' i.`timevar' if `touse' ,  nocons `vce'
			    qui: estimates  store model_z1, title("`basevars'")

				*Test of IV-P
				qui: test    `ivp_null_fe'
				qui: estadd scalar    pIVP2=r(p) : model_z1
				return scalar pIVP2 = r(p)


            * (2) ESTIMATION OF STRATA FE ONLY MODEL: SPECIFICATION OF IV-R TEST
                // no need to save estimates b/c output table only reports p-val

			    qui xi: regress	  `basevars'  `int_respstrata' `treatvars_minus1'  `int_treatresp' `stratavars' i.`timevar' if `touse' ,  nocons `vce'


				*Test of IV-R
				qui: test     	`ivr_null_fe'
                qui: estadd scalar    pIVR2=r(p) : model_z1
				return scalar pIVR2 = r(p)


            * (3) ESTIMATION OF FULLY SATURATED MODEL
                // no need to save estimates b/c output table only reports p-val

			    qui xi: regress	  `basevars' `stratavars' `int_respstrata' `int_treatstrata'   `int_trs' i.`timevar'  if `touse' , nocons  `vce'


				*Test of IV-R
				qui: test      `ivr_null'
                qui: estadd scalar    pIVR1=r(p) : model_z1
				return scalar pIVR1 = r(p)

				*Test of IV-P
				qui: test       `ivp_null'
                qui: estadd scalar    pIVP1=r(p) : model_z1
				return scalar pIVP1 = r(p)

			    qui: estadd local modelfe ""
			    qui: estadd local satmodel ""

		    }


		* -------------------------------------------------------------------
		* CALCULATES THE MEAN BASELINE VARIABLE FOR CONTROL ATTRITORS
		* Note: assumes control group corresponds to first category (value=0)
		*--------------------------------------------------------------------
		qui: levelsof  `treatvar', local(treatlevels)
		qui: gettoken    first rest: treatlevels
		qui: sum `basevars' if `treatvar'==`first' & response==0 & `touse'
		qui: estadd scalar meanCA=r(mean): model_z1
		return scalar meanCA = r(mean)

	    cap:   drop  `int_treatresp' `int_respstrata' `int_trs' response

	}


    *============================================================================
	* CONDUCT THE TESTS OF IV-R and IV-P FOR CASE IN WHICH # VARLIST > 1
    *               AND SAVE ESTIMATES FOR OUTPUT TABLE
    *============================================================================

    if `nbasevars' > 1 {


	    eststo clear
        capture macro drop _int_treatresp _int_respstrata _int_trs  _ivr_vars _ivr_null _ivp_vars _ivp_null _ivr_vars_fe _ivr_null_fe _ivp_vars_fe _ivp_null_fe


        *------------------------------------------
		* GENERATE TREATMENT/RESPONSE INTERACTIONS
		*------------------------------------------

        qui: gen response=`respvar'

		*Group of interactions: treatment/response
		foreach      g in `treatvars_minus1' {
			gen		 `g'Xresponse=`g'*response
			local     int_treatresp "`int_treatresp' `g'Xresponse"
		}

		*Group of interactions: strata/response
		foreach      s in `stratavars' {
			qui: 	 gen	responseX`s'=response*`s'
			local     int_respstrata "`int_respstrata' responseX`s'"
		}


		* Group of interactions:  treatment/respondents/strata
		foreach      s in `stratavars' {
		foreach      g in `treatvars_minus1' {
			gen		 `g'XresponseX`s'=`g'*response*`s'
			local     int_trs`s' "`int_trs`s'' `g'XresponseX`s'"
		}
			local     int_trs "`int_trs' `int_trs`s''"
		}


        local i=0
	    foreach var of local basevars {

			local i=`i'+1

	        *------------------------------------------------------
            * SAVE NULL HYPOTHESES IN LOCALS: FULLY STURATED MODEL
            *------------------------------------------------------
                *~~~~~~~~~~~~~~~~~
                *   TEST OF IV-R
                *~~~~~~~~~~~~~~~~

                * Individual H0
                local   ivr_vars "`int_treatstrata' `int_trs'"

                foreach 	v in `ivr_vars' {
                    local   ivr_null_`i' " `ivr_null_`i'' = [mfull_z`i'_mean]`v'"
                }
                local ivr_null_`i' "`ivr_null_`i''=0"
                gettoken   first ivr_null_`i': ivr_null_`i', parse(" ")
                local ivr_null_`i' "(`ivr_null_`i'')"

                * Joint H0 across all z variables
                local   ivr_null_multz_full "`ivr_null_multz_full'  `ivr_null_`i''"


                *~~~~~~~~~~~~~~~~~
                *   TEST OF IV-P
                *~~~~~~~~~~~~~~~~

                * Individual H0
                local   ivp_vars " `int_treatstrata' `int_respstrata' `int_trs'"

                foreach 	v in `ivp_vars' {
                    local   ivp_null_`i' " `ivp_null_`i'' = [mfull_z`i'_mean]`v'"
                 }
                local ivp_null_`i' "`ivp_null_`i''=0"
                gettoken   first ivp_null_`i': ivp_null_`i', parse(" ")
                local ivp_null_`i' "(`ivp_null_`i'')"

                * Joint H0 across all z variables
                local   ivp_null_multz_full "`ivp_null_multz_full'  `ivp_null_`i''"


            *---------------------------------------------------------
            * SAVE NULL HYPOTHESES IN LOCALS: MODEL W STRATA FE ONLY
            *---------------------------------------------------------


                *~~~~~~~~~~~~~~~~~
                *   TEST OF IV-R
                *~~~~~~~~~~~~~~~~

                * Individual H0
                local   ivr_vars_fe "`treatvars_minus1' `int_treatresp'"

                foreach 	v in `ivr_vars_fe' {
                    local   ivr_null_fe_`i' " `ivr_null_fe_`i'' = [mfeivr_z`i'_mean]`v'"
                }
                local ivr_null_fe_`i' "`ivr_null_fe_`i''=0"
                gettoken   first ivr_null_fe_`i': ivr_null_fe_`i', parse(" ")
                local ivr_null_fe_`i' "(`ivr_null_fe_`i'')"

                * Joint H0 across all z variables
                local   ivr_null_multz_fe "`ivr_null_multz_fe'  `ivr_null_fe_`i''"



                *~~~~~~~~~~~~~~~~~
                *   TEST OF IV-P
                *~~~~~~~~~~~~~~~~

                * Individual H0

                local   ivp_vars_fe "`treatvars_minus1' response `int_treatresp'"

                foreach 	v in `ivp_vars_fe' {
                    local   ivp_null_fe_`i' " `ivp_null_fe_`i'' = [mfeivp_z`i'_mean]`v'"
                }


                local ivp_null_fe_`i' "`ivp_null_fe_`i''=0"

                gettoken   first ivp_null_fe_`i': ivp_null_fe_`i', parse(" ")
                local ivp_null_fe_`i' "(`ivp_null_fe_`i'')"

                * Joint H0 across all z variables
                local   ivp_null_multz_fe "`ivp_null_multz_fe'  `ivp_null_fe_`i''"


            *--------------------------------------------------------------------
            * REGRESSION TESTS
            * Note: three regressions -- see details in Section B of paper
            * (1) Strata FE only model: specification for IV-P test
		    * (2) Strata FE only model: specification for IV-R test
            * (3) Fully saturated model with strata FE and strata-specific coeff
            *--------------------------------------------------------------------

                *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                * IF OPTION TIMEVAR IS NOT SPECIFIED
                *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                if "`timevar'"=="" {

                * (1) ESTIMATION OF STRATA FE ONLY MODEL: SPECIFICATION OF IV-P TEST
                    //estimates and pvals are reported in output table

                    *Using `vce'
                    qui: regress	  `var'  `int_treatresp' `treatvars_minus1' response `stratavars'  if `touse' ,  nocons `vce'
                    qui: estimates  store model_z`i', title("`var'")

                    * Without `vce' for suest
                    qui: regress	  `var'  `int_treatresp' `treatvars_minus1' response `stratavars'  if `touse' ,  nocons
                    qui: estimates  store mfeivp_z`i', title("`var'")

                * (2) ESTIMATION OF STRATA FE ONLY MODEL: SPECIFICATION OF IV-R TEST
                    // only pvals are repoted in output table

                    *Without `vce' for suest
                    qui: regress	  `var'  `int_respstrata' `treatvars_minus1'  `int_treatresp' `stratavars'  if `touse' ,  nocons
                    qui: estimates  store mfeivr_z`i', title("`var'")

                * (3) ESTIMATION OF FULLY SATURATED MODEL:
                   // only pvals are repoted in output table

                    * Without `vce' for suest
                    qui: regress	  `var' `stratavars' `int_respstrata' `int_treatstrata'   `int_trs'   if `touse' , nocons
                    qui: estimates  store mfull_z`i', title("`var'")


                qui: estadd local modelfe ""
                qui: estadd local satmodel ""

                }

                *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                * IF OPTION TIMEVAR IS SPECIFIED
                *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                if "`timevar'"!="" {

                 * (1) ESTIMATION OF STRATA FE ONLY MODEL: SPECIFICATION OF IV-P TEST
                    //estimates and pvals are reported in output table

                    *Using `vce'
                    qui xi:: regress	  `var'  `int_treatresp' `treatvars_minus1' response `stratavars'  i.`timevar'  if `touse' ,  nocons `vce'
                    qui: estimates  store model_z`i', title("`var'")

                    * Without `vce' for suest
                    qui xi:: regress	  `var'  `int_treatresp' `treatvars_minus1' response `stratavars'  i.`timevar' if `touse' ,  nocons
                    qui: estimates  store mfeivp_z`i', title("`var'")

                * (2) ESTIMATION OF STRATA FE ONLY MODEL: SPECIFICATION OF IV-R TEST
                    // only pvals are repoted in output table

                    *Without `vce' for suest
                    qui xi:: regress	  `var'  `int_respstrata' `treatvars_minus1'  `int_treatresp' `stratavars'  i.`timevar'  if `touse' ,  nocons
                    qui: estimates  store mfeivr_z`i', title("`var'")

                * (3) ESTIMATION OF FULLY SATURATED MODEL:
                   // only pvals are repoted in output table

                    * Without `vce' for suest
                    qui xi:: regress	  `var' `stratavars' `int_respstrata' `int_treatstrata'   `int_trs'  i.`timevar'   if `touse' , nocons
                    qui: estimates  store mfull_z`i', title("`var'")


                qui: estadd local modelfe ""
                qui: estadd local satmodel ""

                }



		    *---------------------------------------------------------------------
		    * CALCULATES THE MEAN BASELINE VARIABLE FOR CONTROL ATTRITORS
		    * Note: assumes control group corresponds to first category (value=0)
		    *---------------------------------------------------------------------
		    qui: levelsof  `treatvar', local(treatlevels)
		    qui: gettoken    first rest: treatlevels
		    qui: sum `var' if `treatvar'==`first' & response==0 & `touse'
		    qui: estadd scalar meanCA=r(mean): model_z`i'



	    }

        *-----------------------------------------------
        * COMBINE ESTIMATION RESTULTS WITH SUEST &
        *       TEST HYPOTHESES
        * Note: standard errors are taken care of here
        *-----------------------------------------------

            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            *   MODELS WITH STRATA FE - IVP SPECIFICATION
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            * Combine fully saturated models
            forvalues i = 1/`nbasevars' {
                local modelsfe_suest_ivp " `modelsfe_suest_ivp' mfeivp_z`i'"
            }

            qui: suest  `modelsfe_suest_ivp'  , `vce'

            *Test of IV-P
            qui: test `ivp_null_multz_fe'
            qui: estadd scalar    pIVP2=r(p) : model_z`nbasevars'
			return scalar pIVP2= r(p)


            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            *   MODELS WITH STRATA FE - IVR SPECIFICATION
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            * Combine fully saturated models
            forvalues i = 1/`nbasevars' {
                local modelsfe_suest_ivr " `modelsfe_suest_ivr' mfeivr_z`i'"
            }

            qui: suest  `modelsfe_suest_ivr'  , `vce'

            * Test of IV-R
            qui: test   `ivr_null_multz_fe'
            qui: estadd scalar    pIVR2=r(p) : model_z`nbasevars'
			return scalar pIVR2= r(p)


            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            *   FULLY SATURATED MODELS
            *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            * Combine fully saturated models
            forvalues i = 1/`nbasevars' {
                local modelsfull_suest " `modelsfull_suest' mfull_z`i'"
            }

            qui: suest  `modelsfull_suest'  , `vce'

            * Test of IV-R
            qui: test   `ivr_null_multz_full'
            qui: estadd scalar    pIVR1=r(p) : model_z`nbasevars'
            return scalar pIVR1= r(p)

            *Test of IV-P
            qui: test `ivp_null_multz_full'
            qui: estadd scalar    pIVP1=r(p) : model_z`nbasevars'
			return scalar pIVP1= r(p)

        cap:   drop  `int_treatresp' `int_respstrata' `int_trs' response

    }


	*========================
	* DROP CREATED VARIABLES
	*========================
		cap:   drop `treatvars' `stratavars' `int_treatstrata'  _est*



	*=======================
	* PRODUCE OUTPUT TABLE
	*=======================

    forvalues i = 1/`nbasevars' {
		local modelsz " `modelsz' model_z`i'"
	}


    if `nbasevars' == 1 {
        if "`vce'"=="" {
            esttab `modelsz', cells(b(fmt(3)) se(par fmt(3))) drop(`stratavars' ) ///
            legend label   nostar              ///
            stats(meanCA N  satmodel  pIVR1 pIVP1 modelfe pIVR2 pIVP2, fmt(3 0 0 3 3 0 3 3 ) ///
            label("Mean value for control attritors" "Observations"   "TESTABLE RESTRICTIONS(+)"  "Test of IV-R (p-val)" "Test of IV-P (p-val)"  "IMPLICATIONS OF RESTR.(&)" ///
			"Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
            addnotes("(+)These tests are conditions on the equality of means within strata (see Eq. 18 in the paper)." ///
			"(&)These tests are conditions on the equality of means in the model with strata fixed effects (see Eq. 19 in the paper)." ///
			"The reported coefficients correspond to the model in Eq. 19 in the paper." ) ///
			varwidth(32)
        }

        if "`vce'"!="" {
            esttab `modelsz', cells(b( fmt(3)) se(par fmt(3))) drop(`stratavars' ) ///
            legend label   nostar              ///
            stats(meanCA N  satmodel  pIVR1 pIVP1 modelfe pIVR2 pIVP2, fmt(3 0 0 3 3 0 3 3 ) ///
            label("Mean value for control attritors" "Observations"   "TESTABLE RESTRICTIONS(+)"  "Test of IV-R (p-val)" "Test of IV-P (p-val)"  "IMPLICATIONS OF RESTR.(&)" ///
			"Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
            addnotes("(+)These tests are conditions on the equality of means within strata (see Eq. 18 in the paper)." ///
			"(&)These tests are conditions on the equality of means in the model with strata fixed effects (see Eq. 19 in the paper)." ///
			"The reported coefficients correspond to the model in Eq. 19 in the paper." ///
			"Standard errors are `vce'") ///
			varwidth(32)
        }
    }


    if `nbasevars' > 1 {
        if "`vce'"=="" {
            esttab `modelsz', cells(b(fmt(3)) se(par fmt(3))) drop(`stratavars' ) ///
            legend label   nostar              ///
            stats(meanCA N  satmodel  pIVR1 pIVP1 modelfe pIVR2 pIVP2, fmt(3 0 0 3 3 0 3 3 ) ///
            label("Mean value for control attritors" "Observations"   "TESTABLE RESTRICTIONS(+)"  "Test of IV-R (p-val)" "Test of IV-P (p-val)"  "IMPLICATIONS OF RESTR.(&)" ///
			"Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
			addnotes("The attrition tests are conditions on the joint equality of means across all baseline variables." ///
			"(+)These tests are conditions on the equality of means within strata." ///
			"(&)These tests are conditions on the equality of means in a model with strata fixed effects." ///
			"The reported coefficients correspond to the model in Eq. 19 in the paper." ) ///
            varwidth(32)
        }

        if "`vce'"!="" {
            esttab `modelsz', cells(b( fmt(3)) se(par fmt(3))) drop(`stratavars' ) ///
            legend label   nostar              ///
            stats(meanCA N  satmodel  pIVR1 pIVP1 modelfe pIVR2 pIVP2, fmt(3 0 0 3 3 0 3 3 ) ///
            label("Mean value for control attritors" "Observations"   "TESTABLE RESTRICTIONS(+)"  "Test of IV-R (p-val)" "Test of IV-P (p-val)"  "IMPLICATIONS OF RESTR.(&)" ///
			"Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
			addnotes("The attrition tests are conditions on the joint equality of means across all baseline variables." ///
			"(+)These tests are conditions on the equality of means within strata." ///
			"(&)These tests are conditions on the equality of means in a model with strata fixed effects." ///
			"The reported coefficients correspond to the model in Eq. 19 in the paper."  ///
			"Standard errors are `vce'" )  ///
			varwidth(32)
        }
    }


	*========================
	* EXPORT OUTPUT TABLE
	*========================

	if "`export'"!=""{

        if `nbasevars' == 1 {
            if "`vce'"=="" {
                esttab `modelsz' using "`export'", cells(b(fmt(3)) se(par fmt(3))) drop(`stratavars' ) ///
                legend label   nostar              ///
				stats(meanCA N  satmodel  pIVR1 pIVP1 modelfe pIVR2 pIVP2, fmt(3 0 0 3 3 0 3 3 ) ///
				label("Mean value for control attritors" "Observations"   "TESTABLE RESTRICTIONS(+)"  "Test of IV-R (p-val)" "Test of IV-P (p-val)"  "IMPLICATIONS OF RESTR.(&)" ///
				"Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
				addnotes("(+)These tests are conditions on the equality of means within strata (see Eq. 18 in the paper)." ///
				"(&)These tests are conditions on the equality of means in the model with strata fixed effects (see Eq. 19 in the paper)." ///
				"The reported coefficients correspond to the model in Eq. 19 in the paper." ) ///
				varwidth(37)
            }

            if "`vce'"!="" {
                esttab `modelsz' using "`export'", cells(b( fmt(3)) se(par fmt(3))) drop(`stratavars' ) ///
                legend label   nostar              ///
				stats(meanCA N  satmodel  pIVR1 pIVP1 modelfe pIVR2 pIVP2, fmt(3 0 0 3 3 0 3 3 ) ///
				label("Mean value for control attritors" "Observations"   "TESTABLE RESTRICTIONS(+)"  "Test of IV-R (p-val)" "Test of IV-P (p-val)"  "IMPLICATIONS OF RESTR.(&)" ///
				"Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
				addnotes("(+)These tests are conditions on the equality of means within strata (see Eq. 18 in the paper)." ///
				"(&)These tests are conditions on the equality of means in the model with strata fixed effects (see Eq. 19 in the paper)." ///
				"The reported coefficients correspond to the model in Eq. 19 in the paper."  ///
				"Standard errors are `vce'") ///
				varwidth(32)
            }
        }


        if `nbasevars' > 1 {
            if "`vce'"=="" {
                esttab `modelsz' using "`export'", cells(b(fmt(3)) se(par fmt(3))) drop(`stratavars' ) ///
                legend label   nostar              ///
				stats(meanCA N  satmodel  pIVR1 pIVP1 modelfe pIVR2 pIVP2, fmt(3 0 0 3 3 0 3 3 ) ///
				label("Mean value for control attritors" "Observations"   "TESTABLE RESTRICTIONS(+)"  "Test of IV-R (p-val)" "Test of IV-P (p-val)"  "IMPLICATIONS OF RESTR.(&)" ///
				"Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
				addnotes("The attrition tests are conditions on the joint equality of means across all baseline variables." ///
				"(+)These tests are conditions on the equality of means within strata." ///
				"(&)These tests are conditions on the equality of means in a model with strata fixed effects." ///
				"The reported coefficients correspond to the model in Eq. 19 in the paper." ) ///
				varwidth(32)
            }

            if "`vce'"!="" {
                esttab `modelsz' using "`export'", cells(b( fmt(3)) se(par fmt(3))) drop(`stratavars' ) ///
                legend label   nostar              ///
				stats(meanCA N  satmodel  pIVR1 pIVP1 modelfe pIVR2 pIVP2, fmt(3 0 0 3 3 0 3 3 ) ///
				label("Mean value for control attritors" "Observations"   "TESTABLE RESTRICTIONS(+)"  "Test of IV-R (p-val)" "Test of IV-P (p-val)"  "IMPLICATIONS OF RESTR.(&)" ///
				"Test of IV-R (p-val)" "Test of IV-P (p-val)")) ///
				addnotes("The attrition tests are conditions on the joint equality of means across all baseline variables." ///
				"(+)These tests are conditions on the equality of means within strata." ///
				"(&)These tests are conditions on the equality of means in a model with strata fixed effects." ///
				"The reported coefficients correspond to the model in Eq. 19 in the paper."  ///
				"Standard errors are `vce'" )  ///
				varwidth(37)
            }
        }
    }
}

end