#delim ;
prog def invcise, rclass;
version 10.0;
/*
 Input lower and upper confidence limits
 and (optionally) degrees of freedom,
 and generate standard errors
 by the inverse confidence interval method.
*!Author: Roger Newson
*!Date: 05 June 2009
*/

syntax varlist(numeric min=2 max=3) [if] [in] , STDerr(name) [ EFormestimate(varname numeric) Level(numlist max=1 >0 <100) replace float fast ];
/*
The varlist contains input variables containing lower and upper limits
  and (optionally) degrees of freedom.
stderr() specifies the name of a new variable to be generated,
  containing standard errors generated by the inverse confidence interval method.
level() contains the confidence level assumed to apply to the confidence limits.
eformestimate() specifies the name of a variable,
  assumed to be an exponentiated estimate corresponding to the confidence limits,
  and implying that the confidence limits are themselves exponentiated,
  and that the new standard error should be the difference between their logs,
  scaled inversely by 2 z- or t-multipliers
  and directly by the eformestimate() variable.
replace specifies that existing non-input variables
  with the same names as output variables
  will be replaced.
float specifies that the standard errors shall be of type float or lower.
fasr specifies that no action is taken to restore the original dataset
  in the event of failure or if the user presses Break.
*/

*
 Set input variable names
*;
local lb: word 1 of `varlist';
local ub: word 2 of `varlist';
local dof: word 3 of `varlist';

*
 Check for name clashes if replace is set,
 and check that output variables are new otherwise.
*;
if "`replace'"!="" {;
  local invars "`varlist'";
  local outvars "`stderr'";
  local clashes: list invars & outvars;
  if "`clashes'"!="" {;
    disp as error "The following variables are specified as input and output variables:"
      _n as error "`clashes'";
    error 498;
  };
};
else {;
  cap noi conf new var `stderr';
  if _rc!=0 {;
    disp as error "Use option replace to replace old variables with the same name as input variables";
    error _rc;
  };
};

*
 Set confidence level and confidence level source
*;
local levelsource "level()";
if "`level'"=="" {;
  mata:invcise_set_confidence_level("`lb'","`ub'");
};

if "`fast'"=="" {;preserve;};

*
 Set observations to use
*;
marksample touse;

*
 Calculate standard errors
*;
if "`replace'"!="" {;
  cap drop `stderr';
};
if "`eformestimate'"!="" {;
  * eform estimates and confidence limits assumed *;
  qui gene double `stderr'=(log(`ub')-log(`lb'))*`eformestimate' if `touse';
};
else {;
  * Non-eform confidence limits assumed *;
  qui gene double `stderr'=`ub'-`lb' if `touse';
};
if "`dof'"=="" {;
  * Normal distribution assumed *;
  qui replace `stderr'=0.5*`stderr'/invnorm(1-(100-`level')/200) if `touse';
};
else {;
  * t-distribution assumed *;
  qui replace `stderr'=0.5*`stderr'/invttail(`dof',(100-`level')/200) if `touse';
};
if "`float'"!="" {;
  qui recast float `stderr', force;
};
qui compress `stderr';
lab var `stderr' "Inverse SE from `level'% CI";

if "`fast'"=="" {;restore, not;};

*
 Return results
*;
disp as text "Confidence level assumed: " as result "`level'%";
return scalar level=`level';
return local levelsource `"`levelsource'"';
return local eformestimate "`eformestimate'";
return local dof "`dof'";
return local ub "`ub'";
return local lb "`lb'";

end;

#delim cr
version 10.0
mata:

void invcise_set_confidence_level(string scalar lb, string scalar ub)
{
/*
 Extract confidence level
 and place sonfidence level source in local macro levelsource
 and place confidence level in local macro level.
 lb contains name of lower bound variable.
 ub contains name of upper bound variable.
*/
real scalar level;
string scalar levelsource;
/*
 level is the real confidence level (possibly missing).
 levelsource is the string to be returned to local macro levelsource.
*/

levelsource=lb+"[level]";
level=strtoreal(st_global(levelsource));
if(level<=0 | level>=100){
  levelsource=ub+"[level]";
  level=strtoreal(st_global(levelsource));
  if(level<=0 | level>=100){
    levelsource="c(level)";
    level=st_numscalar(levelsource);
  }
}
st_local("levelsource",levelsource);
st_local("level",strofreal(level));

}

end