/*
 *  ======== exactcci ===============================================
 *
 * Special version of cci with additional output.  Cornfield's confidence
 * interval for the odds ratio is calculated both with and without
 * continuity correction.
 *
 * Reference:
 * Dupont, W.D., Plummer, W.D. 1999. SBE31: Exact confidence intervals for odds ratios
 * from case-control studies.  Stata Technical Bulletin 52: 12-16.
 *
 *  Programs defined in this file are:
 *
 *  exactcci		The main exactcci command routine
 *  _xcrnfd		Calculates adjusted Cornfield confidence limits for the odds ratio
 *  _crcrnfd		Calculates unadjusted Cornfield confidence limits for the odds ratio
 *  xcnfint		Calculates exact confidence limits for the odds ratio
 *  finda		Support routine for xcnfint
 *  mkdata		Support routine for xcnfint
 */
version 6.0
program drop _all
program define exactcci, rclass
	version 6
	preserve
	local args="`0'"
/*
 *  Break out a, b, c, and d from the argument list.
 */
	gettoken a 0 : 0, parse(" ,")
	gettoken b 0 : 0, parse(" ,")
	gettoken c 0 : 0, parse(" ,")
	gettoken d 0 : 0, parse(" ,")

	confirm integer number `a'
	confirm integer number `b'
	confirm integer number `c'
	confirm integer number `d'

	if `a'<0 | `b'<0 | `c'<0 | `d'<0 {
		di in red "negative numbers invalid"
		exit 498
	}
/*
 *  Parse the remaining command arguments.
 */
	syntax [, Exact Level(integer $S_level) COL(string) Woolf TB]
/*
 *  Call the standard cci command.
 */
    if `"`woolf'"'~="" | `"`tb'"'~=""{
		cci `args'
	}
	else {
		quiet cci `args'
	}
/*
 *  Make sure cci's returns get returned to the user.
 */
 	local ccior=r(or)
	local ccilb=r(lb_or)
	local cciub=r(ub_or)
	local chi2 = r(chi2)
	local p = r(p)
	local p1_ex = r(p1_exact)
	local p_ex = r(p_exact)
	local afe = r(afe)
	local lb_afe = r(lb_afe)
	local ub_afe = r(ub_afe)
	local afp = r(afp)
	ret scalar chi2 = r(chi2)
	ret scalar p = r(p)
	ret scalar p1_exact = r(p1_exact)
	ret scalar p_exact = r(p_exact)
	ret scalar or = r(or)
	ret scalar lb_or = r(lb_or)
	ret scalar ub_or = r(ub_or)
	ret scalar afe = r(afe)
	ret scalar lb_afe = r(lb_afe)
	ret scalar ub_afe = r(ub_afe)
	ret scalar afp = r(afp)
/*
 *  If user specifies Woolf or TB arguments then return here.
 */
    if `"`woolf'"'~="" | `"`tb'"'~="" {exit}

/*
 *  Calculate the Yate's contunity corrected chi2.
 */
	local m1=`a'+`b'
	local m0=`c'+`d'
	local n1=`a'+`c'
	local n0=`b'+`d'
	local T=`n1'+`n0'
	local ae=`n1'*`m1'/`T'
	local be=`n0'*`m1'/`T'
	local ce=`n1'*`m0'/`T'
	local de=`n0'*`m0'/`T'
	local chi_cnt=((abs(`a'*`d'-`b'*`c')-0.5*`T')^2*`T')/(`n1'*`n0'*`m1'*`m0')
	local yatesp = chiprob(1,`chi_cnt')
/*
 *  calulate chi2.
 */
	local xchi2=(abs(`a'-`ae'))^2*(1/`ae'+1/`be'+1/`ce'+1/`de')
	local xp = chiprob(1,`xchi2')
/*
 *  If level is not specified then default to 95% confidence interval.
 */
	if `level'<10 | `level'>99 {
		local level 95
	}
/*
 * ?? Calculate UNADJUSTED Cornfield confidence limits for the odds ratio.
 */
		_crcrnfd `a' `b' `c' `d' `level'
		local ccilb = r(lb)
		local cciub = r(ub)
		local lb_afe=(`ccilb'-1)/`ccilb'
		local ub_afe=(`cciub'-1)/`cciub'
/*
 *  Calculate ADJUSTED Cornfield confidence limits for the odds ratio.
 */
	_xcrnfd `a' `b' `c' `d' `level'
	local adj_lb = r(lb)
	local adj_ub = r(ub)
	ret scalar adj_lb = r(lb)
	ret scalar adj_ub = r(ub)

	local savadlb=`adj_lb'
	local savadub=`adj_ub'
/*
 *  Calculate starting values for iterative estimate of the
 *  exact confidence interval.
 *
 *  If the lower limit<=0 or the upper limit=. then replace the
 *  offending limit with the corresponding woolf limit.
 */
    local flag_lb=0
    if `adj_lb'<=0 {local flag_lb=1}
    local flag_ub=0
    if `adj_ub' == . {local flag_ub=1}
/*
 *  If called for get and display the exact limits.
 */
    if `"`exact'"'~="" {
/*
 *  Calculate UNADJUSTED Cornfield confidence limits for the odds ratio.
 */
		_crcrnfd `a' `b' `c' `d' `level'
		local unad_lb = r(lb)
		local unad_ub = r(ub)

		local savlb=`unad_lb'
		local savub=`unad_ub'
/*
 *  If the lower limit<=0 or the upper limit=. or flag_ub or flag_lb = true
 *  then replace the offending unadjusted limit with the corresponding
 *  woolf limit;  replace the adjusted limit by a multiple of the
 *  unadjusted limit.  This is done to ensure convergence to the exact
 *  limts.
 */
		if `unad_lb'<=0 | `unad_ub'==. | `flag_ub'==1 | `flag_lb'==1 {
			local r=(`a'*`d')/(`b'*`c')
			local iz=invnorm(1-(1-`level'/100)/2)
			local sdlnr=sqrt(1/`a'+1/`b'+1/`c'+1/`d')
			local woolflb = exp(ln(`r')-`iz'*`sdlnr')
			local woolfub = exp(ln(`r')+`iz'*`sdlnr')
			if `unad_lb'<=0 | `flag_lb'==1 {
				local unad_lb=`woolflb'
				local adj_lb=`woolflb'*0.75
			}
			if `unad_ub'==. | `flag_ub'==1 {
				local unad_ub=`woolfub'
				local adj_ub=`woolfub'*1.3
			}
		}
/*
 *  Calculate exact confidence limits for the odds ratio.
 */
		quietly xcnfint `a' `b' `c' `d' `level' `unad_lb' `unad_ub' `adj_lb' `adj_ub'
		local ex_lb = r(ex_lb)
		local ex_ub = r(ex_ub)
	}
/*
 *  Set up to return data.
 */
	ret scalar ex_lb = r(ex_lb)
	ret scalar ex_ub = r(ex_ub)
/*
 *  Produce the table part of the output.
 */
	 _crc4fld `a' `b' `c' `d' `"`col'"' "" Exposed Unexposed Cases Controls "" yes
/*
 *  Set a text field for part of the output.
 */
	if `ccior'>=1 {
		local hdr " Attr. frac."
		local adjfrlb=(`savadlb'-1)/`savadlb'
		local adjfrub=(`savadub'-1)/`savadub'
		if `"`exact'"'~="" {
			local exfrlb=(`ex_lb'-1)/`ex_lb'
			local exfrub=(`ex_ub'-1)/`ex_ub'
		}
	}
	else {
		local hdr " Prev. frac."
		local adjfrlb=1-`savadub'
		local adjfrub=1-`savadlb'
		if `"`exact'"'~="" {
			local exfrlb=1-`ex_ub'
			local exfrub=1-`ex_lb'
		}
	}

	di in gr _col(18) "|" _col(43) "|"
	di in gr _col(18) "|      Point estimate    |  [`level'% Conf. Interval]"
	di in gr _col(18) "|" _dup(24) "-" "+" _dup(22) "-"
	di in gr _col(18) "|" _col(43) "|" " Cornfield's limits"

	di in gr "      Odds ratio | " in ye _col(27) %9.0g `ccior' in gr _col(43) "| " in ye %9.0g `savadlb' "   " %9.0g `savadub' in gr `"  Adjusted"'
	di in gr _col(18) "|" _col(43) "| " in ye %9.0g `ccilb' "   " %9.0g `cciub' in gr `"  Unadjusted"'
	if `"`exact'"'~="" {
		di in gr _col(18) "|" _col(43) "|" " Exact limits"
		di in gr _col(18) "|" _col(43) "| " in ye %9.0g `ex_lb' "   " %9.0g `ex_ub'
		di in gr _col(18) "|" _col(43) "|" " Cornfield's limits"
    }

	di in gr `"`hdr' ex. | "' in ye _col(27) %9.0g `afe' in gr _col(43) "| " in ye %9.0g `adjfrlb' "   " %9.0g `adjfrub' in gr `"  Adjusted"'
	di  in gr _col(18) "|" _col(43) "| " in ye %9.0g `lb_afe' "   " %9.0g `ub_afe' in gr `"  Unadjusted"'
	if `"`exact'"'~="" {
		di in gr _col(18) "|" _col(43) "|" " Exact limits"
		di in gr _col(18) "|" _col(43) "| " in ye %9.0g `exfrlb' "   " %9.0g `exfrub'
    }

	di in gr `"`hdr' pop | "' in ye _col(27) %9.0g `afp' in gr _col(43) "|"

	di in gr _col(18) "+-----------------------------------------------"

	di in gr /*
	*/ _col(19) "           chi2(1) =" in ye %9.2f `xchi2' /*
	*/ in gr "  Pr>chi2 =" in ye %7.4f `xp'
	di in gr /*
	*/"             Yates' adjusted chi2(1) =" in ye %9.2f `chi_cnt' /*
	*/ in gr "  Pr>chi2 =" in ye %7.4f `yatesp'

	if `"`exact'"'~="" {
        di in gr _col(25) "        1-sided Fisher's exact P =" in ye %7.4f `p1_ex'
		di in gr _col(25) "        2-sided Fisher's exact P =" in ye %7.4f `p_ex'
        di in gr _col(25) "2 times 1-sided Fisher's exact P =" in ye %7.4f `p1_ex'*2
	}

end
/*
 *  ======== _xcrnfd =====================================================
 */
program define _xcrnfd, rclass
	version 3.1
	local a `1'
	local b `3' /* sic */
	local c `2' /* sic */
	local d `4'

	tempname iz m1 n1 n2 al alold i

	scalar `iz'=invnorm(1-(1-`5'/100)/2)
	scalar `m1'=`a'+`b'
	scalar `n1'=`a'+`c'
	scalar `n2'=`b'+`d'
	scalar `i' = 0
	scalar `al'= `a'
	scalar `alold'= .
	while abs(`al'-`alold')>.001 & `al'!=. {
		scalar `alold' = `al'
		scalar `al'=`a'- 0.5 -`iz'*1/sqrt(1/`al'+1/(`m1'-`al')+/*
			*/ 1/(`n1'-`al')+ 1/(`n2'-`m1'+`al'))
		if `al'==. {
			scalar `i'=`i'+1
			scalar `al'=`a'-`i'
			if (`al'<0 | (`n2'-`m1'+`al')<0) { scalar `al'= . }
		}
	}
	if `al'==. { scalar `al'= 0 }
	ret scalar lb = `al'*(`n2'-`m1'+`al')/((`m1'-`al')*(`n1'-`al'))
	scalar `al'= `a'
	scalar `alold'= .
	scalar `i'= 0
	while abs(`al'-`alold')>.001 & `al'!=. {
		scalar `alold'= `al'
		scalar `al'=`a'+ 0.5 +`iz'*1/sqrt(1/`al'+1/(`m1'-`al')+/*
			*/ 1/(`n1'-`al')+ 1/(`n2'-`m1'+`al'))
		if `al'==. {
			scalar `i'=`i'+1
			scalar `al'=`a'+`i'
			if (`al'>`n1'|`al'>`m1') { scalar `al' = . }
		}
	}
	ret scalar ub = `al'*(`n2'-`m1'+`al')/((`m1'-`al')*(`n1'-`al'))
end

/*
 *  ======== _crcrnfd =====================================================
 */
program define _crcrnfd, rclass
	version 3.1
	local a `1'
	local b `3' /* sic */
	local c `2' /* sic */
	local d `4'

	tempname iz m1 n1 n2 al alold i

	scalar `iz'=invnorm(1-(1-`5'/100)/2)
	scalar `m1'=`a'+`b'
	scalar `n1'=`a'+`c'
	scalar `n2'=`b'+`d'
	scalar `i' = 0
	scalar `al'= `a'
	scalar `alold'= .
	while abs(`al'-`alold')>.001 & `al'!=. {
		scalar `alold' = `al'
		scalar `al'=`a'-`iz'*1/sqrt(1/`al'+1/(`m1'-`al')+/*
			*/ 1/(`n1'-`al')+ 1/(`n2'-`m1'+`al'))
		if `al'==. {
			scalar `i'=`i'+1
			scalar `al'=`a'-`i'
			if (`al'<0 | (`n2'-`m1'+`al')<0) { scalar `al'= . }
		}
	}
	if `al'==. { scalar `al'= 0 }
	ret scalar lb = `al'*(`n2'-`m1'+`al')/((`m1'-`al')*(`n1'-`al'))
	scalar `al'= `a'
	scalar `alold'= .
	scalar `i'= 0
	while abs(`al'-`alold')>.001 & `al'!=. {
		scalar `alold'= `al'
		scalar `al'=`a'+`iz'*1/sqrt(1/`al'+1/(`m1'-`al')+/*
			*/ 1/(`n1'-`al')+ 1/(`n2'-`m1'+`al'))
		if `al'==. {
			scalar `i'=`i'+1
			scalar `al'=`a'+`i'
			if (`al'>`n1'|`al'>`m1') { scalar `al' = . }
		}
	}
	ret scalar ub = `al'*(`n2'-`m1'+`al')/((`m1'-`al')*(`n1'-`al'))
end

/*
 *  ======== xcnfint =====================================================
 */
/*   (xcnfint.do)
 *
 *  Usage:
 *		. xcnfint a b c d level `unadjlb' `unadjub' `adjlb' adjub'
 *
 *  Calculate the exact level% confidence limits for the contigency table:
 *
 *              exposed|un-exposed
 *             +-------+-------+
 *     cases   |   a   |   b   |
 *             +-------+-------+
 *     controls|   c   |   d   |
 *             +-------+-------+
 *
 *  Returns:
 *		Printed output
 *		r(ex_lb) - exact lower bound
 *		r(ex_ub) - exact upper bound
 */
program define xcnfint, rclass  /* a b c d level */
    version 6
/*
 *  Get the arguments.
 */
	gettoken a 0 : 0, parse(" ,")
	gettoken b 0 : 0, parse(" ,")
	gettoken c 0 : 0, parse(" ,")
	gettoken d 0 : 0, parse(" ,")
	gettoken level 0 : 0, parse(" ,")
	gettoken unadjlb 0 : 0, parse(" ,")
	gettoken unadjub 0 : 0, parse(" ,")
	gettoken adjlb 0 : 0, parse(" ,")
	gettoken adjub 0 : 0, parse(" ,")

	confirm integer number `a'
	confirm integer number `b'
	confirm integer number `c'
	confirm integer number `d'
	confirm number `level'
/*
 *  Calculate the marginals.
 */
    local m1=`a'+`b'
	local m0=`c'+`d'
	local n1=`a'+`c'
	local n0=`b'+`d'
/*
 *  Calculate alpha/2 (needed in a calculation later).
 */
	local alpha=(100-`level')/100
	local ao2=`alpha'/2
/*
 * ---- Calculate the exact lower limit -----------------------------------
 */
/*
 *  Get the un-adjusted (Stata) Cornfield limits.
 */
/*
 *  Extract the un-adjusted lower limit.
 */
    local psi_im1=`unadjlb'
/*
 *  Get the adjusted Cornfield limits.  psi(i) is the lower limit.
 */
/*
 *  Extract the adjusted lower limit as a starting point.
 */
	local psi_i=`adjlb'
/*
 *  If the limits are close enough then we are done and the Cornfield
 *  is the exact lower limit.
 */
	if `psi_i' ~= . & `psi_im1' ~= . & abs(`psi_i'-`psi_im1') >= 0.005*`psi_i' {
/*
 *  Otherwise, call mkdata0 to create a table of all possible a's
 *  (given the marginals)
 */
		mkdata0 `n1' `n0' `m1' `m0'
/*
 *  Call mkdata to derive  the cumulative distribution of a conditioned
 *  on the marginal totals. (un-adjusted)
 */
		mkdata `psi_im1'
/*
 *  Scan the in-memory data set for the row where a is
 *  equal to the a in the 2x2 table.  i points to that row.
 */
		finda `a'
		local aindex=r(index)
/*
 *  Get p(i-1).
 */
		local p_im1=1
		if `aindex' ~= 1 {local p_im1=1-cum[`aindex'-1]}
/*
 *  Call mkdata again using psi_i.
 */
		mkdata `psi_i'
/*
 *  Get p(i).
 */
		local p_i=1
		if `aindex' ~= 1 {local p_i=1-cum[`aindex'-1]}
/*
 *  Loop ...
 */
 		local lcount=0
		while abs(`psi_i'-`psi_im1') >= 0.005*`psi_i' {
/*
 *  Check the number of iterations.  Quit if too many.
 */
			local lcount=`lcount'+1
			if `lcount'==100 {
			    display "Too many iterations:lower"
				exit 19
			}
/*
 *  Calculate the slope.
 */
			local slope=(`p_i'-`p_im1')/(`psi_i'-`psi_im1')
/*
 *  Calculate psi(i+1)
 */
			local psi_ip1=(`ao2'+`slope'*`psi_i'-`p_i')/`slope'
/*
 *  Calculate the cumulative distribution using psi_ip1.
 */
			mkdata `psi_ip1'
/*
 *  Get p(i+1)
 */
 			local p_ip1=1
			if `aindex' ~= 1 {local p_ip1=1-cum[`aindex'-1]}
/*
 *  Reset for next iteration.
 *	 psi(i-1)=psi(i)
 *	 p(i-1=p(i)
 *	 psi(i)=psi(i+1)
 *	 p(i)=p(i+1)
 */
			local psi_im1=`psi_i'
			local p_im1=`p_i'
			local psi_i=`psi_ip1'
			local p_i=`p_ip1'
		}
	}
	local ex_lb=`psi_i'
	return scalar ex_lb=`psi_i'

/*
 * ---- Calculate the exact upper limit -----------------------------------
 */
/*
 *  Get the un-adjusted (Stata) Cornfield limits.  psi(i-1) is the upper limit.
 */
	local psi_im1=`unadjub'
/*
 *  Get the adjusted Cornfield limits.  psi(i) is the upper limit.
 */
	local psi_i=`adjub'
/*
 *  If the limits are close enough then we are done and the adjusted Cornfield
 *  is the exact upper limit.
 */
	if `psi_i' ~= . & `psi_im1' ~= . & abs(`psi_i'-`psi_im1') >= 0.005*`psi_i' {

		mkdata `psi_im1'
		local p_im1=cum[`aindex']

		mkdata `psi_i'
		local p_i=cum[`aindex']

		local lcount=0
		while abs(`psi_i'-`psi_im1') >= 0.005*`psi_i' {
/*
 *  Check the number of iterations.  Quit if too many.
 */
			local lcount=`lcount'+1
			if `lcount'==100 {
			    display "Too many iterations:upper"
				exit 29
			}

			local slope=(`p_i'-`p_im1')/(`psi_i'-`psi_im1')
			local psi_ip1=(`ao2'+`slope'*`psi_i'-`p_i')/`slope'

			mkdata `psi_ip1'

			local p_ip1=cum[`aindex']

			local psi_im1=`psi_i'
			local p_im1=`p_i'
			local psi_i=`psi_ip1'
			local p_i=`p_ip1'
		}
	}
	local ex_ub=`psi_i'
	return scalar ex_ub=`psi_i'
end

/*
 *  ======== finda =====================================================
 */
program define finda, rclass
    version 6
/*
 *  Scan the in-memory data set for the row where a is
 *  equal to the argument to this routine.  Return the index.
 */
    local a=`1'
	local index=1
	while a[`index'] ~= `a' {
		local index=`index'+1
		if `index'>_N {
			display "index out of range"
			exit
		}
	}
	return scalar index = `index'
end

/*
 *  ======== mkdata =====================================================
 */
program define mkdata  /* psi  */
    version 6

	local psi= `1'	/* psi  */
/*
 *  Let g1ao =g1(a,0).  We need to be careful about our
 *  arithmetic to avoid machine overflows in calculating
 *  f(a|psi).
 */
    gen g1a0=a*log(`psi')+fac
    sort g1a0
/*
 *  k1= - max g1(a,0)
 */
    gen k1 = - g1a0[_N]
/*
 *  g2a1 = g2(a,1)
 */
    gen g2a1 = exp(k1 + g1a0)
    gen k2 = sum(g2a1)
/*
 *  Calculate f(a|psi)
 */
    gen fa = g2a1/k2[_N]
/*
 *  Calculate cumulative f(a,K).
 */
    sort a
    replace cum=sum(fa)
    keep a cum fac
/*
 *  We now have 2 relevant variables in the data set:  a and cum.  a contains
 *  all possible values of a and cum contains the cumulative distribution of
 *  a conditioned on the marginal totals.
 */
end
/*
 *  ======== mkdata0 =====================================================
 */
program define mkdata0  /* exposed unexposed cases controls */
    version 6
/*
 *  Set up for data iterations.
 */
    drop _all
	local n1= `1'   /* exposed */
	local n0= `2'   /* unexposed */
	local m1= `3'   /* cases */
	local m0= `4'   /* controls */
/*
 *  Calculate the range of a.  The possible range of a is
 *  max(0,m1-n0)...min(n1,m1).
 */
    local alow=max(0,`m1'-`n0')
	local ahigh=min(`n1',`m1')
/*
 *  Calculate the number of values in the range of a.
 */
	local nobs=`ahigh'-`alow'+1
/*
 *  Set data set to that size...
 */
	set obs `nobs'
/*
 *  Put our fixed values in the data set.  We can remove them later.
 */
	gen n1=`n1'
	gen n0= `n0'
	gen m1= `m1'
	gen m0= `m0'
/*
 *  Put values of a in the table
 */
	gen a=`alow'
	quietly replace a=a[_n-1]+1 if _n ~=1
/*
 *  Define by log factorial terms.
 */
    gen fac = -lnfact(a)-lnfact(n1-a)-lnfact(m1-a)-lnfact(n0-m1+a)
    sort fac
/*
 *  Initialize cum
 */
	generate cum=.
end