*! mlcoint--Johansen's maximum likelihood cointegration test
*! version 2.0     Ken Heinecke     2/9/93     sts9: STB-21
*! v 2.0.1: corrected to work with more than 9 variables (see CFB below)
*!          Will probably fail for >=14 variables
*  C F Baum 0B08 
program define mlcoint
quietly {
	version 3.1
 	local varlist "opt ex"
	local if "opt"
	local in "opt"
	local options "noConstant Lags(int 1) noNormal Regress STANdard Static(str)"
	parse "`*'"	
        local vars : word count `varlist'       /* number of TS vars */
        local normal  = cond("`normal'"=="",1,0)
        local standar  = cond("`standar'"=="",0,1)
        local matrix  = `normal' | `standar'
        if ("`regress'" != "") { local regnoi "noi" }
        capture set matsize 200         /* This can only work in Unix   */
        local lags = `lags'-1           /* # of lags after differencing */
        local dllags "lags(0,`lags')"
/*
        Establish a sample over which the VAR can be run one equation
        at a time.
*/
        tempvar touse
        mark `touse' `if' `in'
        markout `touse' `varlist'
        _crcnuse `touse'
        if $S_2 {
                di in re "gaps in sample"
                exit 98
        }
        local infl "in $S_3/$S_4"
        drop `touse'                    /* save space */
/*
	Create differences and lags of variables and store separate
        lists of the names of the differences and lags.
*/
        parse "`varlist'", parse(" ")
        local j 0
        while `j'<`vars' {
	        local j = `j'+1
	        dif ``j''
                _addop ``j'' D
	        local dlist = "`dlist'"+" $S_1"
	        lag ``j''
                _addop ``j'' L
	        local llist = "`llist'"+" $S_1"
	}
/*
	Create `vars' different lists of differenced RHS variables to be used
        in the individual equations of the VAR.
*/
        parse "`dlist'", parse(" ")
        local j 0
        while `j'<`vars' {
                local j = `j'+1
                local m 0
                while `m'<`vars' {
	                local m = `m'+1
	                if (`j'!=`m') {
	                        local div`j' = "`div`j''" + " ``m''"
                        }
	        }
        }
/*
        Create lists of residuals
*/
        local j 0
        while `j'<`vars' {
                local j = `j' +1
	        local dres = "`dres'" + " d`j'"
	        local lres = "`lres'" + " l`j'"
	}
        tempvar `dres' `lres'   /* each element will be a tempvar */
/*
        Create list for labeling final matrices
*/
        local j 0
        while `j'<`vars' {
	        local j = `j'+1
   	        local vecl = "`vecl'" + " vec`j'"
	}
/*
	Estimate first system of regressions and save the residuals 
        as d1, d2, ..., d`vars'
*/
        parse "`dlist'", parse(" ")
        local i 0
        while `i'<`vars' {
                local i = `i'+1
                if (`lags'==0) {
                        `regnoi' tsfit ``i'' `div`i'' `infl', static(`div`i'' `static') nosamp `constan'
                        predict `d`i'', residual
                }
                else { 
                        if ("`static'" != "") {
	                        `regnoi' tsfit ``i'' `div`i'' `infl', static(`static') l(`lags') nosample `constan'
	                }
                        else {
	                        `regnoi' tsfit ``i'' `div`i'' `infl', l(`lags') nosample `constan'
	                }
                        predict `d`i'', residual
                }
        }
/*
	Estimate second system of regressions and save residuals
	as l1, l2, ..., l`vars'
*/
        parse "`llist'", parse(" ")
        local i 0
        while `i'<`vars' {
        	local i = `i'+1
                if (`lags'==0) {
                        `regnoi' tsfit ``i'' `dlist' `infl', static(`div`i'' `static') nosample `constan'
                        predict `l`i'', residual
                }
                else{ 
                        if ("`static'" != "") {
	                	`regnoi' tsfit ``i'' `dlist' `infl', static(`static') `dllags' nosample `constan'
	        	}
                	else {
	                	`regnoi' tsfit ``i'' `dlist' `infl', `dllags' nosample `constan'
	        	}
                	predict `l`i'', residual
        	}
	}
/*
        The residuals from the VARs are calculated and stored.  Allocate
        temporary names for the matrix calculations.

        Global matrices stored by this routine are:

        S_E_ISDD, S_E_NBET, S_E_SDL, S_E_SLL, S_E_TEVL(TEIGVAL), S_E_TSDL
*/
        tempname A ALPHA CHOLD DIF EIGVALS EVECT EVMAX EVTRACE FINMAT
        tempname ICHOLD LDIF ONE SALPHA SBETAP SDD SLDIF STALPHA 
        tempname TALPHA TEVECT TICHOLD Z1 Z2 Z3 df idf 
/*
        Store degrees of freedom
*/
        scalar `df' = $S_E_N 
        scalar `idf' = 1/`df'
/*
	set up product moment matrices
*/
        parse "`dres'", parse(" ")
        local i 0
        while `i'<`vars' {
                local i = `i'+1
* CFB corr      local dr = "`dr'" + " ```i'''"
				local dr "`dr' ```i'''"
        }
        parse "`lres'", parse(" ")
        local i 0
        while `i'<`vars' {
                local i = `i'+1
* CFB corr      local lr = "`lr'" + " ```i'''"
				local lr "`lr' ```i'''"
        }
        mat accum `A' =  `dr' `lr' `infl', noconstant
        mat `SDD' = `A'[1..`vars',1..`vars']
        local r = `vars'+1
        mat S_E_SLL = `A'[`r'...,`r'...]
        mat S_E_SDL = `A'[1..`vars',`r'...]
        mat drop `A'
/*
        Scale matrices by degrees of freedom
*/
        mat `SDD' =  `idf'*`SDD'
        mat S_E_SLL = `idf'*S_E_SLL
        mat S_E_SDL = `idf'*S_E_SDL
/*
        Set up likelihood function matrices
*/
        mat `CHOLD' = cholesky(S_E_SLL)
        mat `ICHOLD' = inv(`CHOLD')
        mat S_E_TSDL = S_E_SDL'
        mat S_E_ISDD = syminv(`SDD')
        mat `TICHOLD' = `ICHOLD''
        mat `Z1' = `ICHOLD'*S_E_TSDL
        mat `Z2' = `Z1'*S_E_ISDD
        mat `Z3' = `Z2'*S_E_SDL
        mat `FINMAT' = `Z3'*`TICHOLD'
/*
        Calculate eigenvalues and eigenvectors
*/
        mat symeigen `EVECT' `EIGVALS' = `FINMAT'
        mat S_E_TEVL = `EIGVALS''
/*
        Calculate lambda max stats
*/
        mat `ONE' = J(`vars',1,1)
        mat `DIF' = `ONE'-S_E_TEVL
        mat `LDIF' = J(`vars',1,0)
        local i 0
        while `i'<`vars' {
        	local i = `i' + 1
        	mat `LDIF'[`i',1] = log(`DIF'[`i',1])
	}
        mat `SLDIF' =  `df'*`LDIF'
        mat `EVMAX' = -1*`SLDIF'
/*
        Calculate trace stats 
*/
        mat `EVTRACE' = J(`vars',1,0)
        local sevmax = 0
        local n 0
        local i 0    
        while `i'<`vars' {
        	local i = `i'+1
        	local n = `vars'+1-`i'
        	local sevmax = `sevmax'+`EVMAX'[`n',1] 
        	mat `EVTRACE'[`n',1] = `sevmax'
	} 
/*
	Display the eigenvalues, maximal eigenvalue statistics,
	and the trace statistics.
*/
	noi di in gr _col(16) "Maximal" _new _col(14) "eigenvalue    Trace" _new "Eigenvalues  statistics  statistics"
	noi di in gr "-----------------------------------"
	local i 0
	while `i'<`vars' {
		local i = `i' + 1
		noi di in ye %10.0g = S_E_TEVL[`i',1] _skip(3) %10.0g = `EVMAX'[`i',1] _skip(3) = `EVTRACE'[`i',1]
	}
/* 
  	Calculate normalized and standardized eigenvectors and their 
        corresponding weight matrices, i.e., alpha and beta-prime.

        First calculate the normalized matrices.
*/
        mat `TEVECT' = `EVECT''
        mat S_E_NBET = `TEVECT'*`ICHOLD'
        mat rownames S_E_NBET = `vecl'
        mat colnames S_E_NBET = `varlist'
/*
        Remaining matrix calculations are not stored.  Calculate only
        if the `matrix' option is specified.
*/
        if `matrix' { 
	        mat `TALPHA' = S_E_NBET*S_E_TSDL
       		mat `ALPHA' = `TALPHA''
	        mat rownames `ALPHA' = `varlist'
       		mat colnames `ALPHA' = `vecl'
		if `normal' {
	        	noi di _new in gr "Normalized Beta'"
	       		noi mat l S_E_NBET, nob noh
                	noi di _new in gr "Normalized Alpha"
                	noi mat l `ALPHA', nob noh
		}	/* end normalized matrices */
/*
        Now calculate the standardized matrices.
*/
		if `standar' {
	       	        mat `SBETAP' = J(`vars',`vars',0)
	       	        local i 0
		        while `i'<`vars' {
       	                	local i = `i'+1
	                	local j 1
       	                	while `j'<=`vars' {
	                		mat `SBETAP'[`i',`j']=S_E_NBET[`i',`j']/S_E_NBET[`i',`i']
       	         	        	local j = `j'+1
	        		}
       	         	}
                	mat rownames `SBETAP' = `vecl'
                	mat colnames `SBETAP' = `varlist'
                	noi di _new in gr "Standardized Beta'"
                	noi mat l `SBETAP', nob noh
                	mat `STALPHA' = J(`vars',`vars',0)
                	local i 0
                	while `i'<`vars' {
                        	local i = `i'+1
                        	local j 0
                        	while `j'<`vars' {
         	                	local j = `j'+1
                                	mat `STALPHA'[`i',`j']=`TALPHA'[`i',`j']*S_E_NBET[`i',`i']
        	        	}
                	}
                	mat `SALPHA' = `STALPHA''
                	mat rownames `SALPHA' = `varlist'
                	mat colnames `SALPHA' = `vecl'
                	noi di _new in gr "Standardized Alpha"
                	noi mat l `SALPHA', nob noh
		}	/* end standardized matrices */
        }       /* end of unstored matrix results */
/*
        Store estimation results for later use.
*/
        global S_E_cmd "mlcoint"
        global S_E_if "`if'"
        global S_E_in "`in'"
        global S_E_lags = `lags' + 1    /* lags() on input           */
        global S_E_nv  `vars'           /* number of vars in varlist */
        global S_E_vl "`varlist'"       /* original varlist          */
	global S_E_MISD "S_E_ISDD"
        global S_E_MNBE "S_E_NBET"
        global S_E_MSDL "S_E_SDL"
        global S_E_MSLL "S_E_SLL"
        global S_E_MTEV "S_E_TEVL"
        global S_E_MTSD "S_E_TSDL"
}	/* end quietly */
end