*! version 1.0.0  31aug2004
program genbinomial
	version 8.2
	syntax newvarname [if] [in] [, p(string) ///
				       Mu(string) ///
			  	       XBeta(varname numeric) ///
				       Denominator(string) ///
				       N(string) ///
			               Link(string) ]

//  Program to generate random deviates from the binomial distribution
//  with generalized denominator n.  Use option -p/mu()- if directly specifying
//  the probability of a success, or use -xbeta()- and -link()- to jointly
//  specify a linear predictor variable and link function (e.g. logit).

	local x `varlist'
	marksample touse, novarlist

	local k = (`"`mu'"'!="") + (`"`p'"'!="") + (`"`xbeta'"'!="")
 	if `k'==0 {
		di as err "You must specify either p(), mu() or xbeta()"
		exit 198
	}
	if `k' > 1 {
		di as err "You may only specify one of p(), mu() or xbeta()"
		exit 198
	}

	if `"`n'"'!="" & `"`denominator'"'!="" {
		di as err "You may only specify one of n() or denominator()"
		exit 198
	}

	if `"`p'"'!="" {
		local mu `"`p'"'
	}
	if `"`n'"'!="" {
		local denominator `"`n'"'
	}

	tempvar mean nd xp
	if `"`mu'"' == "" {   // xbeta variable specified
		markout `touse' `xbeta'
		qui gen double `mean' = `xbeta' if `touse'
		if `"`link'"'=="" {
			local link logit    // default binomial link
		}

		DoLink `"`link'"' `mean' `touse'
	}
	else {
		if `"`link'"'!="" {
			di as err "link() not allowed with mu()"
			exit 198
		}
		capture confirm number `mu'
		if _rc {
			confirm numeric variable `mu'
			markout `touse' `mu'
		}
		qui gen double `mean' = `mu' if `touse'
	}

	if `"`denominator'"'=="" {
		qui gen double `nd' = 1 if `touse'
	}
	else {
		cap confirm number `denominator'
		if _rc {
			confirm numeric variable `denominator'
			markout `touse' `denominator'
		}
		qui gen double `nd' = `denominator' if `touse'
		cap assert `nd' > 0 if `touse'
		local rc1 = _rc
		cap assert `nd'==int(`nd') if `touse'
		local rc1 = `rc1' + _rc
		if `rc1' {
			di as err "denominator must be positive and integer" _c
			di as err "-valued"
			exit 459
		}
	}

	qui count if `touse' & (`mean'<0 | `mean'>1)
	if `r(N)' {
		di as txt "Note: `r(N)' obs of mu fall outside of [0,1]"
		di as txt "      variable will be set to missing for these " _c
		di as txt "observations"
		qui replace `touse' = `touse' & `mean'>=0 & `mean'<=1
	}

	qui gen double `xp' = .

	plugin call _binom `xp' `nd' `mean' if `touse'

	gen `typlist' `x' = `xp' if `touse'
end

capture program _binom, plugin using("genbinom.plugin")

program DoLink
	args link mu touse

	local k : word count `link'
	if `k'>1 {
		di as err "invalid link()"
		exit 198
	}
	local len = length(`"`link'"')
	if `"`link'"'==substr("identity",1,`len') {
		exit
	}
	else if `"`link'"'=="log" {
		qui replace `mu'=exp(`mu') if `touse'
		exit
	}
	else if `"`link'"'==substr("logit",1,`len') {
		qui replace `mu'=invlogit(`mu') if `touse'
		exit
	}
	else if `"`link'"'==substr("probit",1,`len') {
		qui replace `mu'=norm(`mu') if `touse'
		exit
	}
	else if `"`link'"'==substr("cloglog",1,`len') {
		qui replace `mu'=1-exp(-exp(`mu')) if `touse'
		exit
	}
	else if `"`link'"'==substr("loglog",1,max(`len',4)) {
		qui replace `mu'=exp(-exp(-`mu')) if `touse'
		exit
	}
	else if `"`link'"'=="logc" {
		qui replace `mu'=1-exp(`mu') if `touse'
		exit
	}
	else {
		di as err "invalid link()"
		exit 198
	}
end

exit