* Version 1.5 - 30 Sep 2021
* By J.A.F. Machado and J.M.C. Santos Silva
* Please email jmcss@surrey.ac.uk for help and support


* The software is provided as is, without warranty of any kind, express or implied, including
* but not limited to the warranties of merchantability, fitness for a particular purpose and
* noninfringement. In no event shall the author be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from, out of or in
* connection with the software or the use or other dealings in the software.

prog define xtqreg, eclass
version 14.0
 if replay() {
                _prefix_display
                exit
        }
syntax varlist(numeric min=2 fv) [if] [in] ,  [ Id(string) Quantile(numlist) SAVEfe(string) ls Predict(string)]
marksample touse
markout `touse'
tempname _obsr _ones alpha alphat gammat gamma b be V Ve u up au auhat deltas g xm inprod si k O auhat2 aauhat Qxx Pxx Px XI us s_hat ///
us2 bpost Vpost vp uv av v2 si2 w uw avw w2 Q V_location V_scale  Vmss
gettoken _y _rhs: varlist

fvexpand `_rhs',
local _rhs `r(varlist)'
capture xtset
if ("`id'"=="")&("`r(panelvar)'"!="") local id "`r(panelvar)'"
if ("`id'"=="")&("`r(panelvar)'"=="") {
 di
 di as error "Must specify panelvar; use xtset or the id option"
 exit
 }
if ("`quantile'"=="") {
local quantile .5
 }
foreach x in `quantile'{
if (`x'>=1)|(`x'<=0) {
di as error "quantiles must be between 0 and 1"
exit
}
}
di
di
di
di as txt "                              MM-QR regression results"
qui xtreg `_y' `_rhs' if `touse', fe i(`id') robust
if  e(g_max) < 3 {
 di
 di as error "It is not possible to identify the conditional quantiles with T<3; the estimator is valid only for large T"
 exit
}
qui g `_obsr'=_n
local enne=e(N)
di as txt "Number of obs = "  _continue
di as result   `enne'
if ("`savefe'" != "")|("`predict'" != "") {
qui predict `alpha' , u
qui bysort `id': egen `alphat'=min(`alpha')
qui replace `alpha'=`alphat'+_b[_cons]
}
if ("`ls'" != "") {
di
di as input "                                                           Location parameters"
ereturn display
}
matrix `be'=e(b)
matrix `Ve'=e(V)
matrix `V_location'=e(V)
qui predict double `u' if `touse', e
qui g double `up'=(`u')>=0 if `touse'
su `up' if `touse', meanonly
qui replace `up'=(`up')-r(mean) if `touse'
qui g double `au'=(`u')*(`up')*2  if `touse'
qui xtreg `au' `_rhs' if `touse', fe i(`id') robust
if ("`savefe'" != "")|("`predict'" != "") {
qui predict `gamma' , u
qui bysort `id': egen `gammat'=min(`gamma')
qui replace `gamma'=`gammat'+_b[_cons]
}
if ("`ls'" != "") {
ereturn local depvar = "  "
di as input "                                                              Scale parameters"
ereturn display
di
ereturn local depvar = "`au'"
}
matrix `g'=e(b)
matrix `V_scale'=e(V)
qui predict double `deltas'  , u
qui predict double `auhat' , xbu
qui g `s_hat' = (`auhat')<=0 if `touse'
su `s_hat' if `touse', meanonly
if r(max)==1 di as error "WARNING: " 100*r(mean) "% of the fitted values of the scale function are not positive"
qui g double `us'=(`u')/(`auhat') if `touse'

qui g  byte  `_ones'=1 if `touse'
su `_ones' if `touse', meanonly
qui replace `_ones'=`_ones'/r(sum) if `touse'
mat veca `xm' = `_ones' `_rhs' if `touse'

mat `inprod' = (`xm')*(`g')'
qui g double `si'=(`deltas')+`inprod'[1,1] if `touse'

mat `k' = colsof(`g')
local k=`k'[1,1]-1
mat `be'=`be'[1..1,1..`k']
mat `g'=`g'[1..1,1..`k']
matrix `V_location'=`V_location'[1..`k',1..`k']
matrix `V_scale'=`V_scale'[1..`k',1..`k']

qui g double `auhat2'=(`auhat')^2 if `touse'
qui g double `aauhat'=abs(`auhat') if `touse'


local _regsm " "
foreach x in `_rhs' {
local cnt=`cnt'+1
tempvar nv`cnt'
qui bysort `id': egen `nv`cnt''=mean(`x') if `touse'
qui replace `nv`cnt''=`x'-`nv`cnt'' if `touse'
local _regsm "`_regsm' `nv`cnt''"
}
sort `_obsr'

qui matrix accum `Qxx' = `_regsm' if `touse', noconst
qui matrix opaccum `Pxx' = `_regsm' if `touse', opvar(`aauhat') group(`_obsr') noconst
qui matrix vecaccum `Px' = `auhat2' `_regsm' if `touse', noconst
drop `_regsm'

mat `O'=J(`k'*2+1,`k'*2+1,0)
mat `XI'=J(`k',`k'*2+1,0)
mat `Ve'=`Ve'[1..`k',1..`k']
su `si' if `touse', meanonly
matrix `XI'[1,`k'*2+1]=(`g')'*(1/r(sum))
matrix `XI'[1,1]=invsym(`Qxx')

qui g double `us2'=(`us')^2 if `touse'
su `us2' if `touse', meanonly
matrix `O'[1,1]=r(mean)*`Pxx'

qui g double `vp'=(`us')>=0 if `touse'
su `vp' if `touse', meanonly
qui replace `vp'=(`vp')-r(mean) if `touse'
qui g double `av'=(`us')*(`vp')*2 if `touse'

qui g double `uv'=(`us')*(`av') if `touse'
su `uv' if `touse', meanonly
matrix `O'[1,`k'+1]=r(mean)*`Pxx'
matrix `O'[`k'+1,1]=r(mean)*`Pxx'

qui g double `v2'=(`av')^2 if `touse'
su `v2' if `touse', meanonly
matrix `O'[`k'+1,`k'+1]==r(mean)*`Pxx'

qui g `si2'=(`si')^2 if `touse'
su `si2' if `touse', meanonly
local msi2=r(mean)

qui g double `w'=.
qui g double `uw'=.
qui g double `avw'=.
qui g double `w2'=.

foreach qu in `quantile' {

qui qreg `us' if `touse', q(`qu') vce(iid) nolog
matrix `Q'=e(b)
local fuq=sqrt(`qu'*(1-`qu'))/(_se[_cons]*sqrt(e(N)))
qui replace `w'=(`qu'-((`us')<=`Q'[1,1]))/(`fuq') - (`us') - `Q'[1,1]*(`av') if `touse'
matrix `b'=`be'+(`g')*`Q'[1,1]
if ("`savefe'" != "") {
local __fe_q=ustrtoname("`savefe'_`qu'")
qui g `__fe_q' = `alpha'+`Q'[1,1]*`gamma'
}
if ("`predict'" != "") {
local __p_q=ustrtoname("`predict'_`qu'")
qui mat score `__p_q'=`b'
qui replace `__p_q'=`__p_q'+`alpha'+`Q'[1,1]*`gamma'
}

qui replace `uw'=(`us')*(`w') if `touse'
su `uw' if `touse', meanonly
mat `O'[`k'*2+1,1]=r(mean)*`Px'
mat `O'[1,`k'*2+1]=r(mean)*(`Px')'

qui replace `avw'=(`av')*(`w') if `touse'
su `avw' if `touse', meanonly
mat  `O'[`k'*2+1,`k'+1]=r(mean)*`Px'
mat  `O'[`k'+1,`k'*2+1]=r(mean)*(`Px')'

qui replace `w2'=(`w')^2 if `touse'
su `w2' if `touse', meanonly
mat `O'[`k'*2+1,`k'*2+1] = r(sum)*(`msi2')

matrix `XI'[1,`k'+1]=invsym(`Qxx')*`Q'[1,1]
matrix `Vmss'=`XI'*`O'*(`XI')'

mat `Ve'[1,1]=`Vmss'
mat `Vpost'=`Ve'
mat `bpost'=`b'

local __b_q=ustrtoname("__b`qu'")
matrix `__b_q' = `b'
local __V_q=ustrtoname("__V`qu'")
matrix `__V_q' = `Ve'
local __Q_q=ustrtoname("__Q`qu'")
matrix `__Q_q' = `Q'

di as txt `qu' " Quantile regression"
ereturn post `bpost' `Vpost'
ereturn display
di
}
mat `Vpost'=`Ve'
mat `bpost'=`b'
ereturn post `bpost' `Vpost', obs(`enne') e(`touse')
ereturn local cmd = "xtqreg"
ereturn local depvar = "`_y'"
ereturn matrix b_location = `be'
ereturn matrix b_scale = `g'
ereturn matrix V_location = `V_location'
ereturn matrix V_scale = `V_scale'
ereturn matrix q = `Q'
local wq : word count `quantile'
if `wq' > 1 foreach qu in `quantile' {
local __b_q=ustrtoname("__b`qu'")
local _b_q=ustrtoname("b`qu'")
ereturn matrix `_b_q' = `__b_q'
local __V_q=ustrtoname("__V`qu'")
local _V_q=ustrtoname("V`qu'")
ereturn matrix `_V_q' = `__V_q'
local __Q_q=ustrtoname("__Q`qu'")
local _Q_q=ustrtoname("q`qu'")
ereturn matrix `_Q_q' = `__Q_q'
}
qui ereturn display
ereturn local cmd xtqreg
ereturn local cmdline xtqreg `0'
end