* ************************************************************************************* *
*                                                                                       *
*   regoprob_ll                                                                          *
*   Version 1.0.3 - last revised September 05, 2006                                     *
*                                                                                       *
*   Author: Stefan Boes, boes@sts.unizh.ch                                              *
*                                                                                       *
*   Version 1.0    - initial version                                                    *
*   Version 1.0.1  - revision of help file and predict command                          *
*   Version 1.0.2  - score option deleted                                               *
*   Version 1.0.3  - problems in the predicted probabilities fixed                      *
*   Version 1.0.4  - problems when using mfx fixed, revision of help file               *
*                                                                                       *
* ************************************************************************************* *
*                                                                                       *
*                                                                                       *
*   regoprob is a user-written procedure to estimate random effects generalized         *
*   ordered probit models in Stata. It is a rewritten version of goprobit for panel     *
*   data that assumes normally distributed error terms and individually specific        *
*   effects. The likelihood for each unit is approximated by Gauss-Hermite quadrature.  *
*                                                                                       *
*   This is the subroutine providing the log-likelihood function and the score          *
*   for the overall model.                                                              *
*                                                                                       *
* ************************************************************************************* *



program define regoprob_ll
	version 8
	args todo b lnf g


	* Read out the equations from parameter vector ************************************ *
	forval ind = 1/$S_Numeqs {
		tempvar xb`ind'
		mleval `xb`ind'' = `b', eq(`ind')
	}
	tempvar rho
	local Numeqsp = $S_Numeqs + 1
	local Numeqsm = $S_Numeqs - 1
	mleval `rho' = `b', eq(`Numeqsp') scalar

	* Define everything needed for the Gauss-Hermite quadrature *********************** *
	tempvar s2su
	scalar `s2su' = sqrt(2*`rho'/(1 - `rho'))

	tempvar lit prodlit li
	quietly gen double `lit' = .
	quietly gen double `prodlit' = .
	quietly by $S_i: gen double `li' = cond(_n==_N,0,.)

	tempvar lit1 lit2 litr gradb1 gradb2 gradr
	quietly gen double `lit1' = .
	quietly gen double `lit2' = .
	quietly gen double `litr' = .
	quietly gen double `gradb1' = 0
	quietly gen double `gradb2' = 0
	quietly gen double `gradr' = 0

	tempname ab we u


	* Gauss-Hermite quadrature ******************************************************** *
	forval m = 1/$S_quad {

		scalar `ab' = $S_ab[1,`m']
		scalar `we' = $S_we[1,`m']
		scalar `u' = `s2su'*`ab'


		* Calculate individual likelihood contribution ******************************** *
		local fj "cond($ML_y1 == $dv_1, norm(-`xb1'-`u')"

		forval ind = 2/$S_Numeqs {
			local indd = `ind' - 1
			local fj "`fj', cond($ML_y1 == ${dv_`ind'}, norm(-`xb`ind''-`u') - norm(-`xb`indd''-`u')"
		}
		local fj "`fj', 1 - norm(-`xb$S_Numeqs'-`u') )"

		forval ind = 2/$S_Numeqs {
			local fj "`fj')"
		}

		quietly replace `lit' = `fj'
		quietly replace `lit' = 0.00000001 if `lit' == 0
		quietly by $S_i: replace `prodlit' = cond(_n==1, `lit', `lit'*`prodlit'[_n-1])
		quietly replace `li' = `li' + `we'*`prodlit'/sqrt(_pi)


		* The derivatives ************************************************************* *
		local db1 "cond($ML_y1 == $dv_1, 0"
		local db2 "cond($ML_y1 == $dv_1, -normden(-`xb1'-`u')"

		forval ind = 2/$S_Numeqs {
			local indd = `ind' - 1
			local db1 "`db1', cond($ML_y1 == ${dv_`ind'},  normden(-`xb`indd''-`u')"
			local db2 "`db2', cond($ML_y1 == ${dv_`ind'}, -normden(-`xb`ind''-`u')"
		}
		local db1 "`db1', normden(-`xb$S_Numeqs'-`u') ) "
		local db2 "`db2', 0 )"

		forval ind = 2/$S_Numeqs {
			local db1 "`db1')"
			local db2 "`db2')"
		}

		quietly by $S_i: replace `lit1' = `db1'*`prodlit'[_N]/`lit'
		quietly by $S_i: replace `lit2' = `db2'*`prodlit'[_N]/`lit'
		quietly by $S_i: replace `litr' = (`db1'+`db2')*`prodlit'[_N]/`lit'

		quietly replace `gradb1' = `gradb1' + `we'*`lit1'/sqrt(_pi)
		quietly replace `gradb2' = `gradb2' + `we'*`lit2'/sqrt(_pi)
		quietly replace `gradr' = `gradr' + `we'*`u'*`litr'/sqrt(_pi)

	}


	* Calculate the value of the log-likelihood *************************************** *
	mlsum `lnf' = ln(`li') if `li' !=.


	* Indicator for d0/d1 evaluator *************************************************** *
	if `todo' == 0 | `lnf' == . {
		exit
	}


	* Calculate score vector ********************************************************** *
	quietly by $S_i: replace `li' = `li'[_N]

	quietly replace `gradb1' = `gradb1'/`li'
	quietly replace `gradb2' = `gradb2'/`li'

	forval ind = 1/$S_Numeqs {
		tempname g`ind'
		tempname g1`ind'
		tempname g2`ind'
	}

	matrix vecaccum `g11' = `gradb2' $S_x if $ML_y1 == $dv_1
	matrix vecaccum `g21' = `gradb1' $S_x if $ML_y1 == $dv_2
	matrix `g1' = `g11' + `g21'
	matrix `g' = `g1'

	forval ind = 2/$S_Numeqs {
		local indd = `ind' + 1
		matrix vecaccum `g1`ind'' = `gradb2' $S_x if $ML_y1 == ${dv_`ind'}
		matrix vecaccum `g2`ind'' = `gradb1' $S_x if $ML_y1 == ${dv_`indd'}
		matrix `g`ind'' = `g1`ind'' + `g2`ind''
		matrix `g' = `g', `g`ind''
	}

	quietly replace `gradr' = sum(`gradr'/`li')
	tempname gr
	scalar `gr' = `gradr'[_N]/(2*`rho'*(1-`rho'))
	matrix `g' = `g', `gr'

end