*! version 1.0.0 14may2010 \ Philip M Jones (Copyright), pjones8@uwo.ca
/* ssi: Sample size calculation program including non-inferiority and equivalence */
/* No claims about the accuracy of this program are stated or implied. */

capture program drop ssi
program define ssi, rclass
	version 11

	gettoken m1 0 : 0, parse(" ,")
    gettoken m2 0 : 0, parse(" ,")

    /* error checking */
    confirm number `m1'
    confirm number `m2'

	syntax [, Power(real 0.80) Alpha(real 0.05) SD1(real -1) sd2(real -1) Loss(real 0) c1(real 0) c2(real 0) ///
			n(real 0) NONinferiority EQUivalence]

	if `sd2' == -1 & `sd1' ~= -1 {
		local sd2 = `sd1'
	}

	if (`m1' < 0 | `m2' < 0 | (`sd1' ~= -1 & `sd1' < 0) | (`sd2' ~= -1 & `sd2' < 0) | `power' < 0 | `alpha' < 0) ///
		| (`sd1' == -1) & (`m1' > 1 | `m1' < 0 |`m2' > 1 | `m2' < 0) {
		di as error "If testing means, then sd(#) must be specified."
		di as error "If testing proportions, the proportions must be between 0 and 1."
		di as error "If n(#) is included as part of the command, power is calculated."
		di as error "See {help ssi:help ssi} for details."
		exit
	}

	//determine what sample size the user is wanting to compute
	// if sd1 is -1 then user did not enter a SD and therefore must be computing a sample size for proportions

	local type = 0 			// type identifies whether noninferiority (1) or equivalence (2) or neither (0)
	if "`noninferiority'" ~= "" {
		local type = 1
	}
	else if "`equivalence'" ~= "" {
		local type = 2
	}

	if `sd1' == -1 {
		local proportion = 1		// user did not enter a SD, therefore this is a proportion
		}
	else {
		local proportion = 0		// user entered a SD, therefore this is not a proportion
	}

	di ""							// make some space in the output

	// calculate sample size for proportions
	if `proportion' == 1 {
		if `type' == 0 {					// proportion, normal

			local dalpha = 1 - `alpha'/2
			local func_alpha_beta = ( invnorm(`dalpha') + invnorm(`power')  )^2
			local per_group_size = ceil(`func_alpha_beta' * ( (`m1' * (1 - `m1') + `m2' * (1 - `m2') ) / (`m1' - `m2')^2 ))

			if `n' == 0 {

				display in green "Estimated sample size for two-sample comparison of proportions"
				di ""
				di "Null hypothesis:" _col(25) in yellow " p1 = p2" in green ", where:  p1 is the proportion in population 1"
				di _col(43) "p2 is the proportion in population 2"
				di "Alternative hypothesis: " in yellow "p1 != p2"
				di in green ""
				di "Assumptions:"
				di _col(10) in green "power = " _col(10) in yellow string(`power', "%9.4f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (two-sided)"
				di _col(13) in green "p1 = " _col(10) in yellow string(`m1', "%9.4f")
				di _col(13) in green "p2 = " _col(10) in yellow string(`m2', "%9.4f")
				di _col(10) in green "estimated required sample size (per group) = " _col(10) in yellow string(`per_group_size', "%9.0f")
				di ""
			}

			else {

				local calc_power = normal(sqrt( (`m1' - `m2')^2 * `n' / ( `m1' * (1-`m1') + `m2' * (1-`m2') ))  - invnorm(`dalpha'))
				display in green "Calculated power for a two-sample comparison of proportions."
				di ""
				di "Assumptions:"
				di _col(10) in green "n (per group) = " _col(10) in yellow string(`n', "%9.0f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (two-sided)"
				di _col(10) in green "p1 = " _col(10) in yellow string(`m1', "%9.4f")
				di _col(10) in green "p2 = " _col(10) in yellow string(`m2', "%9.4f")
				di ""
				di in yellow "The power is: " string(`calc_power', "%9.4f")

			}

		}

		else if `type' == 1 {			// proportion, noninferiority

			local dalpha = 1 - `alpha'
			local func_alpha_beta = ( invnorm(`dalpha') + invnorm(`power')  )^2
			local per_group_size = ceil(`func_alpha_beta' * ( (2 * `m1' * (1 - `m1')) / (`m2')^2 ))

			if `n' == 0 {

				display in green "Estimated sample size for two-sample comparison of proportions " in yellow "(non-inferiority)"
				di ""
				di in green "Null hypothesis: " in yellow "p2 - p1 ³ delta" in green " (inferior), where:"
				di _col(32) "pi (entered in command) is the overall proportion of participants"
				di _col(32) "expected to experience the outcome if the treatments"
				di _col(32) "are non-inferior, and delta is the smallest change in"
				di _col(32) "proportions between groups (p2 - p1) which would still"
				di _col(32) "be clinically important."
				di ""
				di "Alternative hypothesis: " in yellow "p2 - p1 < delta" in green " (non-inferior)"
				di in green ""
				di "Note: a non-inferiority analysis is one-sided."
				di ""
				di "Assumptions:"
				di _col(10) in green "power = " _col(10) in yellow string(`power', "%9.4f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (one-sided)"
				di _col(13) in green "pi = " _col(10) in yellow string(`m1', "%9.4f")
				di _col(10) in green "delta = " _col(10) in yellow string(`m2', "%9.4f")
				di _col(10) in green "estimated required sample size (per group) = " _col(10) in yellow string(`per_group_size', "%9.0f")
				di ""
			}

			else {

				local calc_power = normal(sqrt( (`m2')^2 * `n' / ( 2 * `m1' * (1-`m1') ))  - invnorm(`dalpha'))
				display in green "Calculated power for a two-sample comparison of proportions " in yellow "(non-inferiority)."
				di in green ""
				di "Assumptions:"
				di _col(10) in green "n (per group) = " _col(10) in yellow string(`n', "%9.0f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (one-sided)"
				di _col(10) in green "average p = " _col(10) in yellow string(`m1', "%9.4f")
				di _col(10) in green "delta = " _col(10) in yellow string(`m2', "%9.4f")
				di ""
				di in yellow "The power is: " string(`calc_power', "%9.4f")

			}
		}

		else if `type' == 2 {			// proportion, equivalence

			local dalpha = 1 - `alpha'/2
			local dbeta = (1 - `power') / 2
			local func_alpha_beta = ( invnorm(`dalpha') + invnorm(1- `dbeta')  )^2
			local per_group_size = ceil(`func_alpha_beta' * ( (2 * `m1' * (1 - `m1')) / (`m2')^2 ))

			if `n' == 0 {

				display in green "Estimated sample size for two-sample comparison of proportions " in yellow "(equivalence)"
				di ""
				di in green "Null hypothesis: " in yellow "|p2 - p1| ³ delta" in green " (inequivalent), where:"
				di _col(32) "pi (entered in command) is the overall proportion of participants"
				di _col(32) "expected to experience the outcome if the treatments"
				di _col(32) "are equivalent, and delta is the smallest change in"
				di _col(32) "proportions between groups (p2 - p1) which would still"
				di _col(32) "be clinically important."
				di ""
				di "Alternative hypothesis: " in yellow "-delta < (p2 - p1) < +delta" in green " (equivalent)"
				di in green ""
				di "Note: an equivalence analysis is two-sided."
				di ""
				di "Assumptions:"
				di _col(10) in green "power = " _col(10) in yellow string(`power', "%9.4f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (two-sided)"
				di _col(13) in green "pi = " _col(10) in yellow string(`m1', "%9.4f")
				di _col(10) in green "delta = " _col(10) in yellow string(`m2', "%9.4f")
				di _col(10) in green "estimated required sample size (per group) = " _col(10) in yellow string(`per_group_size', "%9.0f")
				di ""
			}

			else {

				local n_sqrtt = sqrt(`n' * `m2'^2 / (2 * `m1' * (1-`m1')))
				local calc_power = 2 * normal(`n_sqrtt' - invnorm(`dalpha')) - 1
				display in green "Calculated power for a two-sample comparison of proportions " in yellow "(equivalence)."
				di in green ""
				di "Assumptions:"
				di _col(10) in green "n (per group) = " _col(10) in yellow string(`n', "%9.0f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (two-sided)"
				di _col(10) in green "average p = " _col(10) in yellow string(`m1', "%9.4f")
				di _col(10) in green "delta = " _col(10) in yellow string(`m2', "%9.4f")
				di ""
				di in yellow "The power is: " string(`calc_power', "%9.4f")

			}
		}
	}

	// calculate sample size for continuous variable
	if `proportion' == 0 {
		if `type' == 0 {					// continuous, normal

			local delta = abs(`m1' - `m2')
			local dalpha = 1 - `alpha'/2
			local func_alpha_beta = ( invnorm(`dalpha') + invnorm(`power')  )^2
			local per_group_size = ceil(`func_alpha_beta' * ((`sd1'^2 + `sd2'^2) / `delta'^2))

			if `n' == 0 {

				display in green "Estimated sample size for two-sample comparison of means"
				di ""
				di in green "Null hypothesis: " in yellow "        m1 = m2" in green ", where: m1 is the mean in population 1"
				di _col(42) "m2 is the mean in population 2"
				di "Alternative hypothesis: " in yellow "m1 != m2"
				di in green ""
				di "Assumptions:"
				di _col(10) in green "power = " _col(18) in yellow string(`power', "%9.4f")
				di _col(10) in green "alpha = " _col(18) in yellow string(`alpha', "%9.4f") in green " (two-sided)"
				di _col(13) in green "m1 = " _col(15) in yellow string(`m1',"%9.4f")
				di _col(13) in green "m2 = " _col(15) in yellow string(`m2',"%9.4f")
				di _col(12) in green "sd1 = " _col(15) in yellow string(`sd1',"%9.4f")
				di _col(12) in green "sd2 = " _col(15) in yellow string(`sd2',"%9.4f")
				di _col(10) in green "estimated required sample size (per group) = " _col(18) in yellow string(`per_group_size', "%9.0f")
				di ""
			}

			else {

				local calc_power = normal(sqrt( `delta'^2 * `n' / (`sd1'^2 + `sd2'^2))  - invnorm(`dalpha'))
				display in green "Calculated power for a two-sample comparison of means."
				di ""
				di "Assumptions:"
				di _col(10) in green "n (per group) = " _col(10) in yellow string(`n', "%9.0f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (two-sided)"
				di _col(10) in green "m1 = " _col(10) in yellow string(`m1', "%9.4f")
				di _col(10) in green "m2 = " _col(10) in yellow string(`m2', "%9.4f")
				di _col(10) in green "difference between means = " _col(10) in yellow string(`delta', "%9.4f")
				di _col(10) in green "observed sd1 = " _col(10) in yellow string(`sd1', "%9.4f")
				di _col(10) in green "observed sd2 = " _col(10) in yellow string(`sd2', "%9.4f")
				di ""
				di in yellow "The power is: " string(`calc_power', "%9.4f")
			}

		}

		else if `type' == 1 {			// continuous, noninferiority

			local delta = abs(`m1' - `m2')
			local dalpha = 1 - `alpha'
			local func_alpha_beta = ( invnorm(`dalpha') + invnorm(`power')  )^2
			local per_group_size = ceil(`func_alpha_beta' * 2 * ((`sd1'^2) / `delta'^2))

			if `n' == 0 {
				display in green "Estimated sample size for two-sample comparison of means {yellow:(non-inferiority)}"
				di ""
				di in green "Null hypothesis: " in yellow "       m2 - m1 ³ delta" in green " (inferior)"
				di in green "Alternative hypothesis: " in yellow "m2 - m1 < delta" in green " (non-inferior)"
				di ""
				di "Note: a non-inferiority analysis is one-sided."
				di ""
				di "Assumptions:"
				di _col(10) in green "power = " _col(10) in yellow string(`power', "%9.4f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (one-sided)"
				di _col(10) in green "delta = " _col(10) in yellow string(`delta', "%9.4f")
				di _col(10) in green "expected standard deviation = " _col(10) in yellow string(`sd1', "%9.4f") in green " (in each group)
				di _col(10) in green "estimated required sample size (per group) = " _col(10) in yellow string(`per_group_size', "%9.0f")
				di ""
			}
			else {
				// power calculation for non-inferiority

				local calc_power = normal(sqrt( `delta'^2 * `n' / (`sd1'^2 * 2))  - invnorm(`dalpha'))
				display in green "Calculated power for a two-sample comparison of means {yellow:(non-inferiority)}"
				di ""
				di "Note: a non-inferiority analysis is one-sided."
				di ""
				di "Assumptions:"
				di _col(10) in green "n (per group) = " _col(10) in yellow string(`n', "%9.0f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (one-sided)"
				di _col(10) in green "delta = " _col(10) in yellow string(`delta', "%9.4f")
				di _col(10) in green "observed standard deviation = " _col(10) in yellow string(`sd1', "%9.4f") in green " (in each group)
				di ""
				di in yellow "The power is: " string(`calc_power', "%9.4f")
			}

		}
		else if `type' == 2 {			// continuous, equivalence

			local delta = abs(`m1' - `m2')
			local dalpha = 1 - `alpha'/2
			local dbeta = (1 - `power') / 2
			local func_alpha_beta = ( invnorm(`dalpha') + invnorm(1 - `dbeta')  )^2
			local per_group_size = ceil(`func_alpha_beta' * 2 * ((`sd1'^2) / `delta'^2))

			if `n' == 0 {

				display in green "Estimated sample size for two-sample comparison of means {yellow:(equivalence)}"
				di ""
				di in green "Null hypothesis: " in yellow "                |m2 - m1| ³ delta" in green "  (inequivalent)"
				di in green "Alternative hypothesis: " in yellow "-delta < (m2 - m1) < +delta" in green " (equivalent)"
				di ""
				di "Note: an equivalence analysis is two-sided."
				di ""
				di "Assumptions:"
				di _col(10) in green "power = " _col(10) in yellow string(`power', "%9.4f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (two-sided)"
				di _col(10) in green "delta = " _col(10) in yellow string(`delta', "%9.4f")
				di _col(10) in green "expected standard deviation = " _col(10) in yellow string(`sd1', "%9.4f") in green " (in each group)
				di _col(10) in green "estimated required sample size (per group) = " _col(10) in yellow string(`per_group_size', "%9.0f")
				di ""
				return scalar power = `power'
				}
			else {

				// power calculation for equivalence

				local calc_power = 1 + (2 * (normal( sqrt( `delta'^2 * `n' / (`sd1'^2 * 2))  - invnorm(`dalpha'))) - 2)
				display in green "Calculated power for a two-sample comparison of means {yellow:(equivalence)}"
				di ""
				di "Note: an equivalence analysis is two-sided."
				di ""
				di "Assumptions:"
				di _col(10) in green "n (per group) = " _col(10) in yellow string(`n', "%9.0f")
				di _col(10) in green "alpha = " _col(10) in yellow string(`alpha', "%9.4f") in green " (two-sided)"
				di _col(10) in green "delta = " _col(10) in yellow string(`delta', "%9.4f")
				di _col(10) in green "observed standard deviation = " _col(10) in yellow string(`sd1', "%9.4f") in green " (in each group)
				di ""
				di in yellow "The power is: " string(`calc_power', "%9.4f")

			}
		}
	}

	if `n' == 0 {

		display in green "The total estimated sample size is " in yellow string(2 * `per_group_size', "%9.0f")

		return scalar ss = 2 * `per_group_size'
		return scalar per_group_size = `per_group_size'

		local adj_ss = 2 * `per_group_size'

		if `c1' ~= 0 {			// some cross over occurred
			local adj_factor = (1 / (1 - `c1'/100 - `c2'/100)^2 )
			local adj_ss = ceil( (2 * `per_group_size' * (`adj_factor')))
			di ""
			di in green "Since " in yellow abs(`c1') "%" in green " of subjects in group 1 and " in yellow abs(`c2') "%"  ///
			in green " of subjects in group 2 crossed over,"
			di "the total sample size is adjusted to " in yellow `adj_ss'
		}

		if `loss' ~= 0 {		// some loss to follow-up has occurred
			local adj_ss = ceil( (`adj_ss' * (1 / (1 - abs(`loss') / 100))))
			di ""
			di in green "Since " in yellow abs(`loss') "%" in green " of subjects are expected to be lost to follow-up,"
			di _col(5) "the total sample size is adjusted to " in yellow `adj_ss'
		}

		return scalar adj_ss = `adj_ss'
		return scalar power = `power'
		}
	else {
		return scalar power = `calc_power'
	}



end