*! rii Version 1.0.1 dan_blanchette@unc.edu 09Oct2009
*! the carolina population center, unc-ch
** Center for Entrepreneurship and Innovation Duke University's Fuqua School of Business
* - made -rii- Stata 11 compatible
*  rii Version 1.0.0 dan.blanchette@duke.edu  27Apr2009
/**************************************************************************
This program is based on the paper:
Montalto, Catherine Phillips & Sung, Jaimie. (1996). Multiple imputation in the 1992
Survey of Consumer Finances.  Financial Counseling and Planning, Vol. 7, pp. 133-46.

Tested on commands: probit, tobit, cnreg, and regress
**************************************************************************/
program rii, eclass
version 9.2
local version : di "version " string(_caller()) ":"
capture _on_colon_parse `0'
if c(rc) | `"`s(after)'"' == "" {
  if !c(rc) {
    local 0 `"`s(before)'"'
  }
  if replay() {
    if "`e(prefix)'" != "rii" {
      error 301  // last estimates not found error message
      // error command exits
    }
    else {
      // just re-display e()
      estimates replay
      exit
    }
  }
}

Rii `0'
end

program Rii, eclass
version 9.2

local cmdline `"rii `0'"'
capture _on_colon_parse `0'

// reset 0 before -syntax- so that options of the command submitted to -rii- don't create an invalid option message
local 0 `"`s(before)'"'

syntax [if] [in] , IMPvar(varname numeric) [ r_test their_var ]

local command `"`s(after)'"'
tokenize `"`command'"'
local cmd `1'
//unabreviate command
unabcmd `cmd'
local cmd "`r(cmd)'"
if ! inlist("`cmd'","probit","tobit","cnreg","regress") {
  if "`cmd'" == "dprobit" {
    di as err "{help dprobit:dprobit} cannot be used. Try {help probit:probit} instead"
  }
  else {
    di as err "This program has never been tested on the command {help `cmd':`cmd'}.  BE WARNED!!"
  }
}

//remove `cmd' from `command'
local R_esample : subinstr local command `"`cmd'"' " "
// extract the if and in from `command'
R_esample `R_esample'
if `"`r(if)'"' != "" | `"`r(in)'"' != "" {
  di as err "options {cmd:if} and {cmd:in} are not allowed in the command submitted to {help rii:rii}"
  di as err "since {help rii:rii} subsets the data for each value of the {cmd:imp_var}"
  di as err "{help rii:rii} has {cmd:if} and {cmd:in} options "
  exit 198
}


tempname imp_row
//`impvar' can be any value since the forval loop process the values of the `imp_row' matrix
quietly tabulate `impvar', matrow(`imp_row')
//number of imputations
local imps = r(r)
// perform the relevant statistical calculation...
quietly {
  local nobs = 0
  tempname imp_mat
  local colnames
  forval imp_rv = 1/`imps' {
    preserve
    if `"`if'"' != "" | `"`in'"' != "" {
      keep `if' `in'
    }

    keep if `impvar' == `imp_row'[`imp_rv',1]
    //run command submitted to -rii-
    `command'
    restore

    if `imp_rv' == 1  {
      matrix `imp_mat'_N = J(1,`imps',.)
      matrix rownames `imp_mat'_N = N
      local depvar = "`e(depvar)'"
    }
    if !missing(`"`e(version)'"') {
      local ereturn_version = `e(version)'
    }
    matrix `imp_mat'_b`imp_rv' = e(b)
    matrix `imp_mat'_V`imp_rv' = e(V)
    matrix `imp_mat'_N[1,`imp_rv'] = `e(N)'
    local nobs = `nobs' + `e(N)'
    // put double quotes around column names since a name will be like: imputation=3
    local colnames `"`colnames' "`impvar'=`=`imp_row'[`imp_rv',1]'" "'

  }  // end of forval
  matrix colnames `imp_mat'_N = `colnames'

  //construct a missing() out of all vars used in `cmd'
  // extract the varlist and possible if, in, and weight var from `command'
  R_esample `R_esample'
  local esample_missing
  local count = 0
  foreach var of varlist `impvar' `r(varlist)' `r(weight)' {
    local count = `count' + 1
    if `count' == 1 {
      local esample_missing `"`var'"'
    }
    else {
      local esample_missing `"`esample_missing',`var'"'
    }
  }
  tempvar esample
  quietly gen `esample' = 0
  if `"`if'"' != "" | `"`in'"' != "" {
    replace `esample' = 1 `if' `in'
    replace `esample' = 0 if missing(`esample_missing')
  }
  else {
    replace `esample' = 1
    replace `esample' = 0 if missing(`esample_missing')
  }
} // end quietly

// Equation 1 and 2
// create average for estimates and variances
forval imp_rv=1/`imps' {
  if `imp_rv' == 1  {
    matrix `imp_mat'_b_avg = `imp_mat'_b1
    matrix `imp_mat'_V_avg = `imp_mat'_V1
  }
  else {
    matrix `imp_mat'_b_avg = `imp_mat'_b_avg + `imp_mat'_b`imp_rv'
    matrix `imp_mat'_V_avg = `imp_mat'_V_avg + `imp_mat'_V`imp_rv'
  }
  matrix drop `imp_mat'_V`imp_rv'
} // end of forval
// End of Equation 1
matrix `imp_mat'_b_avg = `imp_mat'_b_avg / `imps'
// End of Equation 2
matrix `imp_mat'_V_avg = `imp_mat'_V_avg / `imps'


//subtract estimate average
forval imp_rv=1/`imps' {
  //create one matrix per imputation
  matrix `imp_mat'_bm`imp_rv' = `imp_mat'_b`imp_rv' - `imp_mat'_b_avg
  matrix drop `imp_mat'_b`imp_rv'
} // end of forval


// Equation 3
// now square the bm matrices
forval imp_rv=1/`imps' {
  matrix `imp_mat'_bm`imp_rv' = `imp_mat'_bm`imp_rv'' * `imp_mat'_bm`imp_rv'
  // now sum them up
  if `imp_rv' == 1 {
    matrix `imp_mat'_bm = `imp_mat'_bm`imp_rv'
  }
  else {
    matrix `imp_mat'_bm = `imp_mat'_bm + `imp_mat'_bm`imp_rv'
  }
  matrix drop `imp_mat'_bm`imp_rv'
}

// divide it by: (m-1)
matrix `imp_mat'_bm = `imp_mat'_bm / (`imps' - 1)

// Equation 4
// multiply it by: 1 + (1/m)
matrix `imp_mat'_tm = `imp_mat'_bm * (1 + 1/`imps')

matrix `imp_mat'_tm = `imp_mat'_V_avg + `imp_mat'_tm

matrix drop `imp_mat'_V_avg

ereturn post `imp_mat'_b_avg `imp_mat'_tm , obs(`nobs') esample(`esample')
ereturn matrix obs_per_imp `imp_mat'_N
ereturn local cmd "`cmd'"
ereturn local cmdname "`cmd'"
if !missing(`"`ereturn_version'"') {
  ereturn scalar version = `ereturn_version'
}
ereturn local cmdline `"`cmdline'"'
ereturn local command "`command'"
ereturn local prefix "rii"
ereturn local depvar "`depvar'"
ereturn scalar N_imps = `imps'


/*************************
   ereturn notes:
     ereturn post mat1  // creates e(b) by moving mat1 to e(b) (no copy option)
     ereturn post mat1 mat2 //  creates e(b) e(V) by moving mat1 to e(b) and mat2 to e(V) (no copy option)
                            //   the e(V) matrix has to be symetrical or you get "conformability" error message
     ereturn matrix some_name mat1  // creates e(some_name) by moving mat1 to e(some_name)
     ereturn matrix some_name mat1, copy  // creates e(some_name) by copying mat1 to e(some_name)
     ereturn repost b=mat1  //  replaces e(b) by moving mat1 to e(b) (no copy option)
     ereturn repost V=mat2  //  replaces e(V) by moving mat2 to e(V) (no copy option)
                            //   but not possible after -reg- and some other commands (noted on Statalist)
     // repost requires that the matrices be the same size as the one that is being replaced.

*************************/

estimates replay
end


program R_esample, rclass
version 9.2
syntax varlist [fweight pweight iweight/] [if] [in] [, *]
return local varlist `"`varlist'"'
return local if `"`if'"'
return local in `"`in'"'

capture confirm var `exp'

if _rc == 0 {
  return local weight `"`exp'"'
}
end