* VERSION 1.29       (SJ2-4: st0026)
* OCTOBER 8, 2002
* LAST REVISOR: SOB
*
*
program define pscore
version 7.0

syntax varlist [if] [in] [fweight iweight pweight], pscore(string) [blockid(string) DETail logit comsup level(real 0.01) numblo(int 5)]
tokenize `varlist'

tempvar touse
g `touse'=0
qui replace `touse'=1 `if' `in'

/* if weights are specified, create local variable */
if "`weight'" != "" {
   tempvar wv
   qui gen double `wv' `exp'
   local w [`weight'=`wv']
   replace `touse'=0 if `wv'==0
}

/* retrieve the treatment indicator */
local T  `1'



di in ye _newline(3) "**************************************************** "
di in ye	     "Algorithm to estimate the propensity score "
di in ye	     "**************************************************** "

di _newline(2) in ye "The treatment is `T'"

tab `T'  if `touse'==1




di _newline(3) "Estimation of the propensity score "

if `"`logit'"' != `""'  {
   capture drop comsup
   logit `varlist' [`weight'`exp'] if `touse'==1
}
else {
   capture drop comsup
   probit `varlist' [`weight'`exp'] if `touse'==1
}

tempvar epscore

qui predict double `epscore' if `touse'==1

capture drop `pscore'
qui gen double `pscore' = `epscore'
label var `pscore' "Estimated propensity score"



/* REGION OF COMMON SUPPORT */
if `"`comsup'"' != `""'  {
   qui sum `pscore' if `T'==1
   tempname mintreat maxtreat
   tempvar COMSUP
   scalar `mintreat'  = r(min)
   scalar `maxtreat'  = r(max)
   di in ye _newline(3)"Note: the common support option has been selected"
   di in ye "The region of common support is [" `mintreat' ", " `maxtreat' "]"

   qui g `COMSUP'=(`pscore'>=`mintreat' & `pscore'<=`maxtreat')
   qui replace `COMSUP'=. if `touse'==0
   qui replace `touse'=0 if `COMSUP'==0
}




di _newline(3) in ye "Description of the estimated propensity score "
if `"`comsup'"' != `""'  {
   di "in region of common support "
}
sum `pscore' if `touse'==1, detail



di _newline(3) "****************************************************** "
di             "Step 1: Identification of the optimal number of blocks "
di             "Use option detail if you want more detailed output "
di             "****************************************************** "


local sizblo = 1/`numblo'




tempvar inf sup BLO INFBLO SUPBLO
qui gen `BLO' = 0 if `touse'==1
label var `BLO' "Blocks of the pscore for treatment `T' "
qui gen `INFBLO' = 0  if `touse'==1
label var `INFBLO' "Inferior of block of pscore "
qui gen `SUPBLO' = 0  if `touse'==1
label var `SUPBLO' "Superior of block of pscore "
local iblo = 1
while `iblo' <= `numblo'{
   local linf = 0 + (`iblo'-1)*`sizblo'
   local lsup = 0 + (`iblo')*`sizblo'
   qui replace `BLO'=`iblo' if `linf' <= `pscore' & `pscore'< `lsup' & `touse'==1
   qui replace `INFBLO' = `linf' if `BLO'==`iblo'
   qui replace `SUPBLO' = `lsup' if `BLO'==`iblo'
   local iblo= `iblo' + 1
}




if `"`detail'"' != `""'  {

   di _newline(3) "Distribution of treated and controls across blocks"
   tab `BLO' `T'






   /* BEGINNING OF TEST THAT THE PROPENSITY SCORE IS NOT DIFFERENT */
   di _newline(3) "Test that the mean propensity score is not different for treated and controls"

}

local iblo = 1
while `iblo' <= `numblo' { /* BEGINOFWHILE */


   if `"`detail'"' != `""'  {
      di _newline(3) in ye "Test in block " `iblo'
      di _newline(1) in ye "Observations in block " `iblo'
      count if `BLO' == `iblo'
   }
   else {
      qui count if `BLO' == `iblo'
   }


   if r(N)== 0 { /* CASE WHERE THERE ARE NO OBS IN BLOCK i */


      if `"`detail'"' != `""'  {
         di _newline(2)  "Block " `iblo' " does not have observations "
         di              "Move to next block "
      }


      local iblo= `iblo' + 1
   }

   else if r(N)!= 0 { /* BEGINOFELSE1 */


      if `"`detail'"' != `""'  {
         di _newline(2) "Controls in block " `iblo'
         count if `BLO' == `iblo' & `T' == 0
      }
      else {
         qui count if `BLO' == `iblo' & `T' == 0
      }



      if r(N)== 0 {



         if `"`detail'"' != `""'  {
            di _newline(2) "Block " `iblo' " does not have controls "
            di             "Move to next block "
         }



      local iblo= `iblo' + 1
      }

      else if r(N)!= 0 { /* BEGINOFELSE2 */


         if `"`detail'"' != `""'  {
            di "Treated in block " `iblo'
            count if `BLO' == `iblo' & `T' == 1
         }
         else {
            qui count if `BLO' == `iblo' & `T' == 1
         }


         if r(N)== 0 { /* CASE WHERE THERE ARE NO TREATED IN BLOCK i */


            if `"`detail'"' != `""'  {
               di _newline(2) "Block " `iblo' " does not have treated "
               di             "Move to next block "
            }


         local iblo= `iblo' + 1
         }

         else if r(N)!= 0 { /* BEGINOFELSE3 */


            if `"`detail'"' != `""'  {
               di _newline(2)  "Test for block " `iblo'
               ttest `pscore' if `BLO'==`iblo', by(`T')
               if r(p) < `level' {
                  di _newline(3) "The mean propensity score is different for treated and controls in block " `iblo'
                  di             "Split the block " `iblo' " and retest all blocks "
                  qui replace `BLO' = `BLO' + 1 if `BLO' > `iblo' & `BLO'!=.
                  di _newline(2) "Check that blocks have shifted "
                  tab `BLO' `T'
                  local numblo = `numblo' + 1

                  sum `INFBLO' if `BLO' == `iblo' , meanonly
                  local tmpinf = r(mean)
                  sum `SUPBLO' if `BLO' == `iblo' , meanonly
                  local tmpsup = r(mean)
                  local split = (`tmpinf' + `tmpsup')/2

                  qui replace `BLO' = `BLO' + 1 if `BLO' == `iblo' & `pscore' >= `split' & `pscore'<= `SUPBLO'
                  qui replace `SUPBLO' = `split' if `BLO' == `iblo'   /* replace supremum of lower sub-block */
                  qui replace `INFBLO' = `split' if `BLO' == `iblo'+1 /* replace infimum  of upper sub-block */
               }
               else { /* ELSE OF ttest */
                  if `"`detail'"' != `""'  {
                     di _newline(2) "The mean propensity score is not different for treated and controls in block " `iblo'
                  }
                  local iblo= `iblo' + 1
               }
	    }

            else { /* ELSE OF detail */
               qui ttest `pscore' if `BLO'==`iblo', by(`T')
               if r(p) < `level' {
                  qui replace `BLO' = `BLO' + 1 if `BLO' > `iblo' & `BLO'!=.
                  local numblo = `numblo' + 1
                  qui sum `INFBLO' if `BLO' == `iblo' , meanonly
                  local tmpinf = r(mean)
                  qui sum `SUPBLO' if `BLO' == `iblo' , meanonly
                  local tmpsup = r(mean)
                  local split = (`tmpinf' + `tmpsup')/2
                  qui replace `BLO' = `BLO' + 1 if `BLO' == `iblo' & `pscore' >= `split' & `pscore'<= `SUPBLO'
                  qui replace `SUPBLO' = `split' if `BLO' == `iblo'   /* replace supremum of lower sub-block */
                  qui replace `INFBLO' = `split' if `BLO' == `iblo'+1 /* replace infimum  of upper sub-block */
                }
                else { /* ELSE OF ttest */
		   /*di _newline(2) "The mean propensity score is not different for treated and controls in block " `iblo'*/
		   local iblo= `iblo' + 1
		}
             }


         } /* ENDOFELSE3 */
      } /* ENDOFELSE2 */
   } /* ENDOFELSE1 */
} /* ENDOFWHILE */


qui sum `BLO'
local maxblo = r(max)

di in gr _newline(2) "The final number of blocks is " `maxblo'

di in gr _newline(1) "This number of blocks ensures that the mean propensity score"
di in gr             "is not different for treated and controls in each block"



di in ye _newline(3) "********************************************************** "
di             "Step 2: Test of balancing property of the propensity score "
di             "Use option detail if you want more detailed output "
di             "********************************************************** "


local iblo = 1
local problem = 0
while `iblo' <= `numblo' { /* BEGINOFWHILE */


   if `"`detail'"' != `""'  {
      di _newline (3) "**************************************************** "
      di              "Testing the balancing property in block " `iblo'
      di              "**************************************************** "
      di _newline (1) "Observations in block " `iblo'
      count if `BLO' == `iblo'
      if r(N)== 0 {
         di _newline (1) "Block " `iblo' " does not have observations "
         di              "Move to next block "
         local iblo= `iblo' + 1
      }
      di _newline (1) "Controls in block " `iblo'
      count if `BLO' == `iblo' & `T' == 0
      if r(N)== 0 {
         di _newline (1) "Block " `iblo' " does not have controls "
         di              "I move to next block "
         local iblo= `iblo' + 1
      }
      else if r(N)!= 0 { /* BEGINOFELSE1 */
         di _newline (1) "Treated in block " `iblo'
         count if `BLO' == `iblo' & `T' == 1
         if r(N)== 0 {
            di _newline (1) "Block " `iblo' " does not have treated "
            di              "I move to next block "
            local iblo= `iblo' + 1
         }
         else if r(N)!=0 { /* BEGINOFELSE2 */
            foreach var of local varlist { /* BEGINOFFOREACH */
               if "`var'" == "`T'" { /* DO NOTHING */

               }
               else { /* BEGINOFELSE3 */
                  di _newline (3) "Testing the balancing property for variable `var' in block " `iblo'
                  ttest `var' if `BLO' == `iblo', by(`T')
                  if r(p) < `level' {
                     di _newline (1) "Variable `var' is not balanced  in block " `iblo'
                     local problem = 1
                  }
                  else { /* BEGINOFELSE4 */
                     di _newline (1) "Variable `var' is  balanced  in block " `iblo'
                  } /* ENDOFELSE4 */
               } /* ENDOFELSE3 */
            } /* ENDOFFOREACH */
         } /* ENDOFELSE2 */
      } /* ENDOFELSE1 */
      local iblo = `iblo' + 1
   } /* ENDOF with output */


   else{ /* BEGINOF without output */
      qui count if `BLO' == `iblo'
      if r(N)== 0 {
         local iblo= `iblo' + 1
      }
      qui count if `BLO' == `iblo' & `T' == 0
      if r(N)== 0 {
         local iblo= `iblo' + 1
      }
      else if r(N)!= 0 { /* BEGINOFELSE1 */
         qui count if `BLO' == `iblo' & `T' == 1
         if r(N)== 0 {
            local iblo= `iblo' + 1
         }
         else if r(N)!=0 { /* BEGINOFELSE2 */
            foreach var of local varlist { /* BEGINOFFOREACH */
               if "`var'" == "`T'" { /* DO NOTHING */

               }
               else { /* BEGINOFELSE3 */
                  qui ttest `var' if `BLO' == `iblo', by(`T')
                  if r(p) < `level' {
                     di _newline (1) "Variable `var' is not balanced  in block " `iblo'
                     local problem = 1
                  }
               } /* ENDOFELSE3 */
            } /* ENDOFFOREACH */
         } /* ENDOFELSE2 */
      } /* ENDOFELSE1 */
      local iblo = `iblo' + 1
   } /* ENDOF without output */


} /* ENDOFWHILE */


if `problem' == 0 {

   di in gr _newline(2) "The balancing property is satisfied "
   di in gr _newline(2) "This table shows the inferior bound, the number of treated
   di in gr             "and the number of controls for each block "
   if `"`comsup'"' != "" {
      qui replace `INFBLO' = `mintreat' if `INFBLO'==0
   }
   tab `INFBLO' `T'
   if `"`comsup'"' != "" {
      di in gr "Note: the common support option has been selected"

   }

}
else {

   di _newline(1) in red  "The balancing property is not satisfied "
   di _newline(1) in red  "Try a different specification of the propensity score "
}


if "`blockid'" != "" {
   capture drop `blockid'
   qui g `blockid' = `BLO'
   label var `blockid' "Number of block"
}

if `"`comsup'"' != "" {
   qui g comsup = `COMSUP'
   label var comsup "Dummy for obs. in common support"
}



di in ye _newline(2) "******************************************* "
di             "End of the algorithm to estimate the pscore "
di             "******************************************* "

end