/******************************************************************************
*! version 0.2  Ian White  15nov2021
version 0.1  Ian White  4jun2020
Exchangeable covariance matrix for mvmeta
Sigma = tau^2 * P(rho)
Parameters: tau (or log tau)
	rho
Note that Sigma is singular if rho is outside range -1/(dim - 1) to 1
	but solutions may lie outside this range
	since only Sigma+S`i' must be non-singular
	hence transformation is not desirable
	-> could allow truncate option?
	-> what transformation would I use?
******************************************************************************/

program define mvmeta_bscov_exchangeable, rclass

syntax [if] [in], [log  ///
    setup start(string) ///
    mm1 mm2 notrunc      /// Method of moments
    varparms(string)    /// Within -ml-
    postfit             /// After -ml-
    ]
local p $MVMETA_p
marksample touse
tempname startchol Sigma binit vinit init

if "$MVMETA_taulog"=="taulog" {
    // Estimate tau on log scale
    local exp exp
    local tauname logtau
	local taustart 0
}
else {
	local tauname tau
	local taustart 1
}
local rhoname rho
local rhostart 0
* could include transformation here, not done yet

if "`setup'"!="" {
    di as text "Note: variance-covariance matrix is " as result "exchangeable"
    // STARTING VALUES
    if "`start'"!="" {
        cap numlist "`start'", min(2) max(2)
        if _rc {
            di as error "Error in start(`start'): need start(# #)"
            exit 499
        }
    }
    else local start `taustart' 0
	local tau : word 1 of `start'
	local rho : word 2 of `start'
    mat `Sigma' = `exp'(`tau')^2 * (J(`p',`p',`rho')+(1-`rho')*I(`p'))
    cap mvmeta_mufromsigma, sigma(`Sigma')
    if _rc {
        di as error "mvmeta_bscov_exchangeable: mvmeta_mufrom sigma failed"
        mat l `Sigma', title(Sigma used)
        exit _rc
    }
    mat `binit' = e(b)
    mat `vinit' = (`tau', `rho')
    mat colnames `vinit' = "`tauname'" "`rhoname'"
    mat `init' = (`binit', `vinit')
    return local nvarparms = 2
    return matrix binit = `binit'
    return matrix init = `init'
    // SET UP EQUATIONS
    return local eqlist (`tauname':) (`rhoname':)
}

if "`varparms'" != "" {
	local tau = `varparms'[1,1]
	local rho = `varparms'[1,2]
    matrix `Sigma' = (`exp'(`tau'))^2 * (J(`p',`p',`rho')+(1-`rho')*I(`p'))
}

if "`postfit'" != "" {
	if "`exp'"=="exp" local tau2 `exp'(2*[`tauname']_b[_cons])
	else local tau2 ([`tauname']_b[_cons])^2
	local rho = [`rhoname']_b[_cons]
	matrix `Sigma' = (`tau2') * (J(`p',`p',`rho')+(1-`rho')*I(`p'))
    mat rownames `Sigma' = $MVMETA_ylist
    mat colnames `Sigma' = $MVMETA_ylist
    // SET UP VARIANCE EXPRESSIONS
    forvalues r=1/`p' {
        forvalues s=1/`r' {
			if `s' == `r' return local Sigma`s'`r' `tau2'
			else return local Sigma`s'`r' [`rhoname']_b[_cons] * `tau2'
        }
    }
}

if !mi("`mm1'`mm2'") {    // METHOD OF MOMENTS
    di as error "Sorry, method of moments is not yet implemented for bscov(exchangeable)"
    exit 498
}

return matrix Sigma = `Sigma'
return scalar nparms_aux = 2
return scalar neqs_aux = 2

end