*! _gvar_setup 1.0.1 21aug2026 *! gvar setup -- declare the GVAR: units, time, variable blocks, deterministic *! case and weight types. Builds the gvar_MODEL state object. *! Author: Merwan Roudane *! merwanroudane920@gmail.com *! https://github.com/merwanroudane * * Step -> source map * unit / variable inventory <- Toolbox gvar.m sections 1.1-1.3 * endogenous / weakly exogenous flags <- Toolbox create_countrymodels.m * (dvflag, fvflag, gvflag) * deterministic case II / III / IV <- MacKinnon, Haug & Michelis (1999), * Toolbox mlcoint.m * weight-matrix types per variable <- Toolbox gvar.m vtypes * restriction on weakly exogenous <- BGVAR expert$Wex.restr program define _gvar_setup, rclass version 14.0 syntax varlist(numeric) [if] [in] [, /// Unit(varname) /// Time(varname) /// GLObal(varlist numeric) /// GENDog(string) /// DOMinant(string) /// FOReign(string) /// NOForeign(string) /// EXClude(string) /// CASe(string) /// WType(string) /// PSC(integer 4) /// SPEC(string) /// noSUMmary ] * ----------------------------------------------------------------------- * 1. Identify the panel * ----------------------------------------------------------------------- if ("`unit'" == "" | "`time'" == "") { capture qui xtset if _rc { di as err "specify {bf:unit()} and {bf:time()}, or {bf:xtset} the data first" exit 459 } if ("`unit'" == "") local unit "`r(panelvar)'" if ("`time'" == "") local time "`r(timevar)'" } confirm variable `unit' confirm numeric variable `time' * Do NOT markout on the domestic varlist: in a GVAR a missing series is how * "this unit does not have that variable" is encoded, and marking those * observations out would delete the whole unit from the model. Absence is * handled below through the dflag matrix, exactly as the Toolbox's * create_countrymodels.m does. marksample touse, novarlist markout `touse' `time' capture confirm string variable `unit' if (_rc) { markout `touse' `unit' } else { qui replace `touse' = 0 if `unit' == "" } qui count if `touse' if (r(N) == 0) { di as err "no observations" exit 2000 } * ----------------------------------------------------------------------- * 2. Unit index and names * ----------------------------------------------------------------------- tempvar uid qui egen `uid' = group(`unit') if `touse' qui summarize `uid', meanonly local N = r(max) if (`N' < 2) { di as err "a GVAR needs at least two cross-section units" exit 459 } local isstr = 0 capture confirm string variable `unit' if (!_rc) local isstr = 1 local vlab : value label `unit' local cnames "" forvalues i = 1/`N' { if (`isstr') { qui levelsof `unit' if `uid' == `i' & `touse', local(nm) clean } else if ("`vlab'" != "") { qui levelsof `unit' if `uid' == `i' & `touse', local(nv) clean local nm : label `vlab' `nv' } else { qui levelsof `unit' if `uid' == `i' & `touse', local(nv) clean local nm "u`nv'" } local __gvclong`i' "`nm'" local short = strtoname("`nm'") local short = subinstr("`short'", "_", "", .) if ("`short'" == "") local short "u`i'" * keep the short names unique local dup : list posof "`short'" in cnames if (`dup' > 0) local short "`short'`i'" local cnames "`cnames' `short'" } local cnames = trim("`cnames'") * ----------------------------------------------------------------------- * 3. Balance check -- the GVAR needs the same T for every unit * ----------------------------------------------------------------------- tempvar nobs qui bysort `uid' (`time') : gen long `nobs' = _N if `touse' qui summarize `nobs' if `touse' if (r(min) != r(max)) { di as err "unbalanced panel: units have between " r(min) " and " r(max) " periods" di as err "the GVAR requires the same estimation window for every unit" exit 459 } local Traw = r(min) * (the time values are checked for alignment across units inside Mata, * once the data are sorted unit-major) * data frequency, for forecast date labelling local tfmt : format `time' local freq 1 if (strpos("`tfmt'", "%tq") > 0) local freq 4 if (strpos("`tfmt'", "%tm") > 0) local freq 12 if (strpos("`tfmt'", "%tw") > 0) local freq 52 if (strpos("`tfmt'", "%td") > 0) local freq 365 * ----------------------------------------------------------------------- * 4. Variable inventory * ----------------------------------------------------------------------- local V : word count `varlist' local G : word count `global' * ---- weight type per variable, default 1 ------------------------------ local wtypes "" forvalues j = 1/`V' { local wtypes "`wtypes' 1" } if ("`wtype'" != "") { foreach pair of local wtype { local nm = substr("`pair'", 1, strpos("`pair'", "=") - 1) local val = substr("`pair'", strpos("`pair'", "=") + 1, .) local pos : list posof "`nm'" in varlist if (`pos' == 0) { di as err "wtype(): {bf:`nm'} is not among the domestic variables" exit 198 } local wtypes : subinstr local wtypes " " " ", all local newl "" local k 0 foreach w of local wtypes { local ++k if (`k' == `pos') local newl "`newl' `val'" else local newl "`newl' `w'" } local wtypes = trim("`newl'") } } * ---- deterministic case per unit, default 3 --------------------------- local cases "" local defcase 3 if ("`case'" != "") { local first : word 1 of `case' if (strpos("`first'", "=") == 0) local defcase `first' } if (!inlist(`defcase', 2, 3, 4)) { di as err "case() must be 2, 3 or 4 (MacKinnon-Haug-Michelis)" exit 198 } forvalues i = 1/`N' { local cases "`cases' `defcase'" } if ("`case'" != "") { foreach pair of local case { if (strpos("`pair'", "=") == 0) continue local nm = substr("`pair'", 1, strpos("`pair'", "=") - 1) local val = substr("`pair'", strpos("`pair'", "=") + 1, .) local pos : list posof "`nm'" in cnames if (`pos' == 0) { di as err "case(): unknown unit {bf:`nm'}" exit 198 } if (!inlist(`val', 2, 3, 4)) { di as err "case(): value for {bf:`nm'} must be 2, 3 or 4" exit 198 } local newl "" local k 0 foreach c of local cases { local ++k if (`k' == `pos') local newl "`newl' `val'" else local newl "`newl' `c'" } local cases = trim("`newl'") } } * ----------------------------------------------------------------------- * 5. Build the data blocks and the specification flags in Mata * ----------------------------------------------------------------------- sort `uid' `time' * the long names already live in locals __gvclong1..__gvclong`N', so that * embedded spaces survive the trip into Mata mata: _gvar_do_setup("`varlist'", "`global'", "`touse'", "`uid'", /// "`time'", `N', `Traw', `freq', /// "`unit'", "`time'", "`cnames'", /// "`wtypes'", "`cases'") * ---- foreign-counterpart flags ---------------------------------------- * default: a unit gets the foreign counterpart of each variable it owns local forall = 0 if (lower("`foreign'") == "all") local forall = 1 mata: _gvar_do_flags(`forall', "`noforeign'", "`exclude'", "`gendog'", "`dominant'") * ----------------------------------------------------------------------- * A full specification grid overrides everything above. The Toolbox's * fvflag matrix is arbitrary -- in the published demo the USA is the only * country carrying ep* -- so a grid is the only faithful way to reproduce * a published model. Expected variables: * country, dv_, fv_, gv_, and optionally p q dcase rank * ----------------------------------------------------------------------- if (`"`spec'"' != "") { _gvar_read_spec `"`spec'"', domestic(`varlist') global(`global') /// units(`cnames') } mata: gvar_setpsc(`psc') mata: gvar_specify() * ----------------------------------------------------------------------- * 6. Report * ----------------------------------------------------------------------- mata: st_local("K", strofreal(gvar_getK())) if ("`summary'" != "nosummary") { _gvar_setup_report if ("`__gvabsent'" != "") { di as text " Variables absent for some units (unit:variable)" di as text " {hline 74}" local line " " foreach p of local __gvabsent { if (length("`line'`p' ") > 74) { di as text "`line'" local line " " } local line "`line'`p' " } if (trim("`line'") != "") di as text "`line'" di as text " {hline 74}" di "" } if ("`__gvpartial'" != "") { * {err:} markup, not "as err": a warning inside the summary block, * which "as err" would print through -quietly-. di as text " {err:Warning: these series are only PARTIALLY" /// " observed and have}" di as text " {err:therefore been dropped from the unit concerned:}" di as text " {err:`__gvpartial'}" di as text " {err:A GVAR variable must span the whole estimation" /// " window.}" di "" } } return local absent "`__gvabsent'" return local partial "`__gvpartial'" return scalar N = `N' return scalar T = `Traw' return scalar K = `K' return scalar V = `V' return scalar G = `G' return local units "`cnames'" return local domestic "`varlist'" return local global "`global'" return local unitvar "`unit'" return local timevar "`time'" end * --------------------------------------------------------------------------- * Read a full specification grid and install it over the defaults * --------------------------------------------------------------------------- program define _gvar_read_spec version 14.0 syntax anything(name=fname), domestic(string) global(string) units(string) local fname `fname' local N : word count `units' local V : word count `domestic' local G : word count `global' preserve qui use `"`fname'"', clear capture confirm string variable country if _rc { restore di as err "spec(): the grid must contain a string variable {bf:country}" exit 198 } tempname DF FF GF PQ matrix `DF' = J(`N', `V', 0) matrix `FF' = J(`N', `V', 0) if (`G' > 0) matrix `GF' = J(`N', `G', 0) matrix `PQ' = J(`N', 4, .) tempvar rowno qui gen long `rowno' = _n local nfound 0 local i 0 foreach u of local units { local ++i qui count if country == "`u'" if (r(N) == 0) continue local ++nfound qui levelsof `rowno' if country == "`u'", local(rr) local rr : word 1 of `rr' local j 0 foreach v of local domestic { local ++j capture confirm variable dv_`v' if !_rc matrix `DF'[`i', `j'] = dv_`v'[`rr'] capture confirm variable fv_`v' if !_rc matrix `FF'[`i', `j'] = fv_`v'[`rr'] } local g 0 foreach v of local global { local ++g capture confirm variable gv_`v' if !_rc matrix `GF'[`i', `g'] = gv_`v'[`rr'] } foreach k in p q dcase rank { capture confirm variable `k' if !_rc { if ("`k'" == "p") matrix `PQ'[`i', 1] = p[`rr'] if ("`k'" == "q") matrix `PQ'[`i', 2] = q[`rr'] if ("`k'" == "dcase") matrix `PQ'[`i', 3] = dcase[`rr'] if ("`k'" == "rank") matrix `PQ'[`i', 4] = rank[`rr'] } } } restore if (`nfound' == 0) { di as err "spec(): none of the GVAR units were found in the grid" exit 459 } if (`nfound' < `N') { di as err "spec(): the grid covers only `nfound' of the `N' units" exit 459 } if (`G' > 0) { mata: _gvar_apply_spec(st_matrix("`DF'"), st_matrix("`FF'"), /// st_matrix("`GF'"), st_matrix("`PQ'")) } else { mata: _gvar_apply_spec(st_matrix("`DF'"), st_matrix("`FF'"), /// J(`N', 0, 0), st_matrix("`PQ'")) } di as text "Specification grid read from " as result `"`fname'"' as text "." end * --------------------------------------------------------------------------- program define _gvar_setup_report version 14.0 tempname CN VN KI KS CS mata: st_local("N", strofreal(gvar_getN())) mata: st_local("K", strofreal(gvar_getK())) mata: st_local("T", strofreal(gvar_getT())) mata: st_matrix("`KI'", gvar_getki()) mata: st_matrix("`KS'", gvar_getksi()) mata: st_matrix("`CS'", gvar_getcase()) mata: st_local("cn", invtokens(gvar_getcname()')) _gvar_title "GVAR specification" di as text " Cross-section units " as result %8.0f `N' di as text " Time periods " as result %8.0f `T' di as text " Endogenous variables (K) " as result %8.0f `K' di "" di as text " {hline 62}" di as text " Unit" _col(16) "Domestic" _col(30) "Weakly exog." _col(48) "Case" di as text " {hline 62}" local i 0 foreach c of local cn { local ++i di as text " " abbrev("`c'", 12) /// _col(16) as result %8.0f `=`KI'[`i',1]' /// _col(30) as result %8.0f `=`KS'[`i',1]' /// _col(48) as result %4.0f `=`CS'[`i',1]' } di as text " {hline 62}" di as text " Case 2: restricted intercept, no trend" di as text " Case 3: unrestricted intercept in levels, no trend" di as text " Case 4: unrestricted intercept, restricted trend" di "" di as text " Next: {bf:gvar weights} to install the weight matrices," di as text " then {bf:gvar foreign} to rebuild the star variables." di "" end * ---------------------------------------------------------------------------