*! rd 1.0.4  7june2011 fixed 'touse' to be nonmissing zero when obs are added to dataset
*! rd 1.0.3  15nov2007
*! author Austin Nichols austinnichols@gmail.com
* rd 1.0.3  15nov2007 fixed bug in graph command, made ddens optionally off
* rd 1.0.2  5nov2007 first public release
prog rd_obs, eclass
loc version "1.0.2 5nov2007"
if replay() eret di
else {
 loc lpoly "locpoly"
 loc k "tri"
 loc bw "w"
 if (_caller()<10) version 8.2
 else {
  version 10
  loc lpoly "lpoly"
  loc k "k(tri)"
  loc bw "bw"
  }
 syntax varlist(min=2 max=3) [if] [in] [aw fw pw/] [, s(str) Mult(real 1) GENerate(str) at(str) /*
  */ n(integer 0) GRaph BINgraph binvar(varlist max=1) noSCatter Width(real 0) BWidth(real 0) Kernel(str) /*
  */ defbw Degree(integer 1) mbw(numlist >0 integer) z0(real 0) lwald NOIsily /*
  */ Placebo DDens Tdisc x(varlist numeric) SCOpt(str) LINEopt(str) *]
 tempname beta
 cap `lpoly'
 if _rc==199 {
  cap net from http://www.stata-journal.com/software/sj6-4
  net inst st0053_3
  }
 if "`generate'`at'"!="" {
  di as error "Do not specify " as res "generate " as err "or " as res "at " as err "options."
  di as err "Instead use " as res "s(stubname) " as err "syntax to generate new variables."
  error 198
  }
 if `bwidth'!=0 & `width'!=0 {
  di as error "Cannot specify both " as res "width " as err "and " as res "bwidth " as err "options."
  error 198
  }
 if `bwidth'!=0 loc w=`bwidth'
 else loc w=`width'
 if "`kernel'"!="" & "`k'"=="tri" loc k="`kernel'"
 if "`kernel'"!="" & "`k'"=="k(tri)" loc k="k(`kernel')"
 if "`kernel'"=="" loc kernel="triangle (default)"
 marksample touse
 if "`lpoly'"=="locpoly" & "`exp'"!="" {
  preserve
  tempvar wtvar dropme
  qui {
   gsort -`touse'
   g double `wtvar'=`exp'-`exp'[_n-1] if _n>1 & `touse'
   su `wtvar', meanonly
   replace `wtvar'=`exp'/r(min)
   loc N=_N
   expand `wtvar'
   g byte `dropme'=_n>`N'
   }
  }
 else if "`exp'"!="" loc wt="[aw=`exp']"
 tokenize `varlist'
 loc was2="`2'"
 if "`3'"=="" {
  loc nolwald=1
  loc 3="`2'"
  tempvar 2
  qui g byte `2'=(`3'>=`z0')
  loc was2=""
  di as res "Two variables specified; treatment is "
  di as res "assumed to jump from zero to one at Z=`z0'. "
  di as res _n " Assignment variable Z is `3'"
  di as res " Treatment variable X_T unspecified"
  di as res " Outcome variable y is `1'" _n
  }
 else {
  di as res "Three variables specified; jump in treatment  "
  di as res "at Z=`z0' will be estimated. Local Wald Estimate"
  di as res "is the ratio of jump in outcome to jump in treatment."
  di as res _n " Assignment variable Z is `3'"
  di as res " Treatment variable X_T is `2'"
  di as res " Outcome variable y is `1'" _n
  }
 tempvar z obs close
 di as res "Command used: " as txt "`lpoly'" as res "; Kernel used: " as txt "`kernel'"
 loc was3="`3'"
 if `z0'!=0 {
  tempvar 3
  qui g double `3'=(`was3'-`z0')
  qui compress `3'
  }
 su `3' if `touse', meanonly
 if r(min)>0 | r(max)<0 {
  di as err _n "Assignment variable Z should have cutoff at `z0'"
  di as err "But range of assignment variable Z does not include `z0':"
  if `z0'!=0 su `was3' if `touse'
  else       su `3'    if `touse'
  error 198
  }
 if `n'==0 {
  * calculate steps for 50 pts on the right
  loc step=r(max)/50
  local N=50+floor(-r(min)/(r(max)/50))
  cap set obs `N'
  loc n=50
  }
 else {
  * calculate steps for `n' pts
  loc step=(r(max)-r(min))/(`n'-1)
  cap set obs `n'
  loc N=`n'
  * reset `n' to n pts on the right
  loc n=floor(r(max)/`step')
  }
 if `w'==0 & "`defbw'"=="" {
  sort `3'
  g `close'=sum(`touse'*(`3'>0))
  qui g long `obs'=_n if `touse'
  su `obs' if `close'>0, meanonly
  loc ub=`3'[`=r(min)+30']
  loc lb=`3'[`=r(min)-30']
  loc w=max(`ub',abs(`lb'))
  qui count if (`3'>=0 & `3'<`step'*2) & `touse'
  if r(N)>40 loc w=`step'*2
  qui count if (`3'<0 & `3'>-`step'*2) & `touse'
  if r(N)>40 loc w=`step'*2
  }
 loc w=`mult'*`w'
 if "`mbw'"=="" loc mbw "100 50 200"
 else {
  loc j100 "100"
  loc mbw: list uniq mbw
  loc mbw: list mbw - j100
  loc mbw "100 `mbw'"
  }
 qui {
  g `z'=(_n-1)*`step' in 1/`=`n'+1'
  replace `z'=-(_n-`=`n'+1')*`step' in `=`n'+2'/`N'
  }
 la var `z' "Assignment variable relative to cutoff"
 if "`binvar'"=="" loc binvar="`z'"
 local opt "at(`z') nogr `k' deg(`degree') `options'"
 if "`defbw'"!="" {
   `lpoly' `1' `3' `wt' if `touse', gen(`f0') `opt'
   loc w=`mult'*r(width)
   }
foreach i of local mbw {
 loc lw=`i'/100*`w'
 if "`i'"=="100" loc i
 tempvar i`i'f0 i`i'f1 i`i'g0 i`i'g1
 loc b="`bw'(`lw')"
 local opt "at(`z') nogr `k' `b' deg(`degree') `options'"
 qui {
 if "`ddens'"!="" {
  tempvar df0 df1
  kdensity `3' if `3'>=0 & `touse' `wt', at(`z') nogr `k' `b' gen(`df1')
  replace `df1'=. if `z'<0
  kdensity `3' if `3'<0 & `touse' `wt', at(`z') nogr `k' `b' gen(`df0')
  replace `df0'=. if `z'>0
  su `touse' if `3'>=0  `wt'
  loc sumw1=r(sum_w)
  su `touse' if `3'<0  `wt'
  loc sumw0=r(sum_w)
  replace `df1'=`df1'*`sumw1'/(`sumw1'+`sumw0')
  replace `df0'=`df0'*`sumw0'/(`sumw1'+`sumw0')
  loc dd`i'=`df1'[1]-`df0'[1]
 `noisily' di as txt "Bandwidth: " as res `lw' _c
 `noisily' di as txt "; Jump Estimate for Density: " _c
 `noisily' di as res (`df1'[1]-`df0'[1])
    if "`graph'"!="" {
     tempvar kd
     kdensity `3' if `touse' `wt', at(`z') gen(`kd') nogr
     line `kd' `df1' `df0' `z', sort leg(off) name(ddens`i', replace) ti("Jump in Density of Assignment Variable" "Bandwidth=`lw'")
     }
  }
 foreach lhs in `x' `1' {
    `lpoly' `lhs' `3' `wt' if `3'<0 & `touse', gen(`i`i'f0') `opt'
    replace `i`i'f0'=. if `z'>0
    `lpoly' `lhs' `3' `wt' if `3'>=0 & `touse', gen(`i`i'f1') `opt'
    replace `i`i'f1'=. if `z'<0
    local numerat=`i`i'f1'[1]-`i`i'f0'[1]
     `noisily' di as txt "Bandwidth: " as res `lw' _c
     `noisily' di as txt "; Jump Estimate for `lhs': " _c
     `noisily' di as res (`i`i'f1'[1]-`i`i'f0'[1])
    if "`lhs'"!="`1'" {
     cap loc rown: rownames `beta'
     mat `beta'=nullmat(`beta') \ `numerat'
     mat rownames `beta'= `rown' `lhs'`i'
    }
    if "`graph'"!="" {
     if "`scatter'"=="" {
      if "`bingraph'"!="" {
       tempvar y
       g `y'=.
       levelsof `binvar' if `touse', loc(bins)
       loc binT: word count `bins'
       forv bint=1/`binT' {
        loc lastbin
        loc nextbin
        cap loc lastbin: word `=`bint'-1' of `bins'
        if "`lastbin'"=="" loc lastbin=c(mindouble)
        cap loc nextbin: word `=`bint'+1' of `bins'
        if "`nextbin'"=="" loc nextbin=.
        su `lhs' `wt' if `3'>=`lastbin' & `3'<=`nextbin' &`touse'
        replace `y'=r(mean) if `3'>=`lastbin' & `3'<=`nextbin' &`touse'
       }
      }
      else loc y="`lhs'"
      loc sp "sc `y' `3' if `touse', mc(gs14) `scopt' ||"
      }
     tw `sp' line `i`i'f0' `i`i'f1' `z', lw(thick thick) lp(l -) leg(off) ti("`:var la `lhs''" "Bandwidth `lw'") name(`lhs'`i', replace) `lineopt'
    }
    if "`s'"!="" {
       ren `i`i'f0' `s'`i'`lhs'0
       ren `i`i'f1' `s'`i'`lhs'1
    }
    else drop `i`i'f0' `i`i'f1'
 }
 if "`lwald'"=="" & "`nolwald'"=="" {
    `lpoly' `2' `3' `wt' if `3'<0 & `touse', gen(`i`i'g0') `opt'
    replace `i`i'g0'=. if `z'>0
    `lpoly' `2' `3' `wt' if `3'>=0 & `touse', gen(`i`i'g1') `opt'
    replace `i`i'g1'=. if `z'<0
    if "`graph'"!="" {
     if "`scatter'"=="" {
      if "`bingraph'"!="" {
       tempvar y
       g `y'=.
       levelsof `binvar' if `touse', loc(bins)
       loc binT: word count `bins'
       forv bint=1/`binT' {
        loc lastbin
        loc nextbin
        cap loc lastbin: word `=`bint'-1' of `bins'
        if "`lastbin'"=="" loc lastbin=c(mindouble)
        cap loc nextbin: word `=`bint'+1' of `bins'
        if "`nextbin'"=="" loc nextbin=.
        su `2' `wt' if `3'>=`lastbin' & `3'<=`nextbin' &`touse'
        replace `y'=r(mean) if `3'>=`lastbin' & `3'<=`nextbin' &`touse'
       }
      }
      else loc y="`2'"
      loc sp "sc `y' `3' if `touse', mc(gs14) `scopt' ||"
      }
     tw `sp' line `i`i'g0' `i`i'g1' `z', lw(thick thick) lp(l -) leg(off) ti("`:var la `2''" "Bandwidth `lw'") name(`2'`i', replace) `lineopt'
    }
   loc denomin=`i`i'g1'[1]-`i`i'g0'[1]
   if "`s'"!=""  {
     ren `i`i'g0' `s'`i'`2'0
     ren `i`i'g1' `s'`i'`2'1
    }
 }
  else {
    loc denomin=1
    if "`s'"!="" & "`was2'"!="" {
     g byte `i`i'g0'=0 if `z'<=0
     g byte `i`i'g1'=1 if `z'>=0
     ren `i`i'g0' `s'`i'`was2'0
     ren `i`i'g1' `s'`i'`was2'1
    }
  }
 if "`lwald'"=="" & "`nolwald'"=="" {
 cap loc rown: rownames `beta'
 mat `beta'=nullmat(`beta') \ `numerat'
 mat rownames `beta'= `rown' numer`i'
 cap loc rown: rownames `beta'
 mat `beta'=nullmat(`beta') \ `denomin'
 mat rownames `beta'= `rown' denom`i'
 }
 cap loc rown: rownames `beta'
 mat `beta'=nullmat(`beta') \ `=`numerat'/`denomin''
 mat rownames `beta'= `rown' lwald`i'
 cap loc rown: rownames `beta'
 if "`dd`i''"!="" {
  mat `beta'=nullmat(`beta') \ `dd`i''
  mat rownames `beta'= `rown' ddens`i'
  }
 }
 loc w`i'=`lw'
 di as txt "Bandwidth: " as res `lw' _c
 di as txt "; Local Wald Estimate: " _c
 di as res `numerat'/`denomin'
}
 if "`s'"!="" ren `z' `s'`3'
 cap compress `s'*
 cap drop if `dropme'
 matrix `beta'=`beta''
 qui count if `touse'
 qui replace `touse'=0 if mi(`touse')
 eret post `beta', esample(`touse')
 ereturn scalar N = `=r(N)'
 ereturn local depvar "`1'"
 ereturn local cmd "rd"
 ereturn local version "`version'"
 ereturn local rdversion "`version'"
 foreach i of local mbw {
  if "`i'"=="100" loc i
  ereturn scalar w`i'=`w`i''
 }
 cap drop if `dropme'
}
end