*! eaalogit 1.1.0 02Apr2016
*! author arh

*  1.1.0:	a bug that could affect the estimation results in the case of
*			extreme parameter values during the iterations has been fixed

program eaalogit
	version 12.1
	if replay() {
		if (`"`e(cmd)'"' != "eaalogit") error 301
		Replay `0'
	}
	else	Estimate `0'
end

program Estimate, eclass sortpreserve
	syntax varlist [if] [in] 	///
		[pweight iweight],		///
		GRoup(varname) 			///
		ID(varname) 			///
		Keaa(integer)			///
		EAAspec(string) [		///
		Zvars(varlist)			///
		FRom(string)			///
		SEArch					///
		Level(integer `c(level)')	///
		TRace					///
		GRADient				///
		HESSian					///
		SHOWSTEP				///
		ITERate(passthru)		///
		TOLerance(passthru)		///
		LTOLerance(passthru)	///
		GTOLerance(passthru)	///
		NRTOLerance(passthru)	///
		CONSTraints(passthru)	///
		TECHnique(passthru)		///
		DIFficult				///
		VCE(passthru)			///
		COLL					///
	]

	local mlopts `trace' `gradient' `hessian' `showstep' `iterate' `tolerance' 	///
	`ltolerance' `gtolerance' `nrtolerance' `constraints' `technique' 			///
	`difficult' `vce'

	if ("`search'" != "") {
		local search
		set seed `seed'
	}
	else local search search(off)

	** Check that group and id variables are numeric **
	capture confirm numeric var `group'
	if _rc != 0 {
		di in r "The group variable must be numeric"
		exit 498
	}
	if ("`id'" != "") {
		capture confirm numeric var `id'
		if _rc != 0 {
			di in r "The id variable must be numeric"
			exit 498
		}
	}

	** Create local wgt for use with clogit if weights are specified **
	if ("`weight'" != "") local wgt "[`weight'`exp']"

	** Mark the estimation sample **
	marksample touse
	markout `touse' `group' `id' `zvars'

	gettoken lhs rhs : varlist
	local rhs = trim("`rhs'")

	** Check that starting values are specified with the constraints option **
	if ("`constraints'" != "" & "`from'" == "") {
		di in red "When constraints are specified it is compulsory to supply starting values using the from option"
		exit 498
	}

	** Check that starting values are specified with the coll option **
	if ("`coll'" != "" & "`from'" == "") {
		di in red "When the coll option is specified it is compulsory to supply starting values using the from option"
		exit 498
	}

	** Check for multicollinearity **
	if ("`coll'" == "") {
		qui _rmcoll `rhs'
		if ("`r(varlist)'" != "`rhs'") {
			di in red "Some variables are collinear - if this is intended use the coll option"
			exit 498
		}
	}

	** Estimate conditional logit model - if constraints or the coll option are specified this is simply to set estimation sample **
	if ("`constraints'" == "" & "`coll'" == "") {
		qui clogit `lhs' `rhs' if `touse' `wgt', group(`group')
		local nobs = e(N)
		local ll = e(ll)
		local k  = e(k)
		qui replace `touse' = e(sample)
	}
	else {
		qui clogit `lhs' `rhs' if `touse' `wgt', group(`group')
		local nobs = e(N)
		qui replace `touse' = e(sample)
	}

	** Create matrices representing possible ANA patterns **
	preserve
	clear
	tempname levels
	matrix `levels' = J(1,`keaa',2)
	genfact, levels(`levels')
	foreach var of varlist * {
		qui replace `var' = `var' - 1
	}
	mata: eaa_F = st_data(.,.)
	qui gen one = 1
	mata: eaa_FCOLDUP = st_data(.,tokens(st_local("eaaspec")))
	restore

	** Drop missing data **
	preserve
	qui keep if `touse'

	** Generate dummy for last obs for each decision-maker**
	tempvar last
	bysort `id': gen `last' = cond(_n==_N,1,0)
	qui replace `last' = 0 if `touse' == 0

	** Check that the independent variables vary within groups **
	sort `group'
	foreach var of varlist `rhs' {
		capture by `group': assert `var'==`var'[1]
		if (_rc == 0) {
			di in red "Variable `var' has no within-group variance"
			exit 459
		}
	}

	** Check that the dependent variable only takes values 0-1 **
	capture assert `lhs' == 0 | `lhs' == 1
	if (_rc != 0) {
		di in red "The dependent variable must be a 0-1 variable indicating which alternatives are chosen"
		exit 450
	}

	** Check that each group has only one chosen alternative **
	tempvar chonum
	sort `group'
	qui by `group': egen `chonum' = sum(`lhs')
	capture assert `chonum' == 1
	if (_rc != 0) {
		di in red "At least one group has more than one chosen alternative"
		exit 498
	}

	** Generate individual id **
	tempvar nchoice pid
	sort `group'
	by `group': gen `nchoice' = cond(_n==_N,1,0)
	sort `id'
	by `id': egen `pid' = sum(`nchoice')
	qui duplicates report `id'
	mata: eaa_np = st_numscalar("r(unique_value)")
	mata: eaa_T = st_data(., st_local("pid"))

	** Generate choice occasion id **
	tempvar csid
	sort `group'
	by `group': egen `csid' = sum(1)

	** Sort data **
	sort `id' `group'

	** Set Mata matrices and scalars to be used in optimisation routine **
	local krhs: word count `rhs'
	local kzvs: word count `zvars'

	mata: eaa_X = st_data(., tokens(st_local("rhs")))
	mata: eaa_Y = st_data(., st_local("lhs"))
	mata: eaa_CSID = st_data(., st_local("csid"))
	if ("`zvars'" != "") mata: eaa_Z = st_data(., tokens(st_local("zvars")), st_local("last"))

	mata: eaa_krhs = strtoreal(st_local("krhs"))
	mata: eaa_kzvs = strtoreal(st_local("kzvs"))
	mata: eaa_keaa = strtoreal(st_local("keaa"))

	** Restore data **
	restore

	** Create macro to define equations for optimisation routine **
	local max (Beta: `rhs', noconst)
	forvalues i = 1(1)`keaa' {
		local max `max' (Gamma`i': `zvars')
	}

	** Create matrix of starting values unless specified **
	if ("`from'" == "") {
		tempname from
		if ("`zvars'" == "") {
			matrix `from' = e(b), J(1,`keaa',1)
		}
		else {
			matrix `from' = e(b)
			forvalues i = 1(1)`keaa' {
				matrix `from' = `from', J(1,`kzvs',0), 1
			}
		}
		local copy , copy
	}

	** Sort data **
	sort `id' `group'

	** Run optimisation routine **
	ml model gf0 eaa_gf0()											///
		`max' if `touse' `wgt', group(`id') init(`from' `copy')		///
		`search' `mlopts' `coll' maximize missing nopreserve

	** To be returned as e() **
	ereturn local title "Endogenous attribute attendance model"
	ereturn local indepvars `rhs'
	ereturn local depvar `lhs'
	ereturn local group `group'
	ereturn local id `id'
	if ("`zvars'" != "") ereturn local zvars `zvars'

	ereturn local eaaspec `eaaspec'

	ereturn scalar krhs = `krhs'
	ereturn scalar keaa = `keaa'
	ereturn scalar kzvs = `kzvs'
	if ("`zvars'" == "") ereturn scalar k_aux = `keaa'

	ereturn local cmd "eaalogit"

	Replay , level(`level')
end

program Replay
	syntax [, Level(integer `c(level)')]
	ml display , level(`level')
end

exit