/* Parse out the list of control terms. The user can enter 2 layers of grouped variables including either/or options. The outermost layer of grouped terms is called a Set. ex. Set 1 = ( (x1 (x2 | x3 )) | (x4 x5 ) ) Sets are split up into SetX by the either/or symbol "|". Only one SetX of each Set may appear in any given model. ex. Set 1, SetX 1 = (x1 (x2 | x3 )) Set 1, SetX 2 = (x4 x5 ) SetX are split up into Terms by parentheses. Each SetX contains one or more Terms. Given that a SetX appears in the model, all of the terms of the SetX must appear in that model. ex. Set 1, SetX1, Term 1 = x1 Set 1, SetX1, Term 2 = x2 | x3 Set 1, SetX2, Term 1 = x4 x5 Terms are split up into TermX by the either/or symbol "|". Only one TermX of each Term may appear in any given model. ex. Set 1, SetX1, Term 1, TermX 1 = x1 ex. Set 1, SetX1, Term 2, TermX 1 = x2 Set 1, SetX1, Term 2, TermX 1 = x3 Set 1, SetX2, Term 1, TermX 1 = x4 x5 ParseVarlist returns the following local macros: s`i'NSX = number of SetX in Set i s`i'sx`j'NT = number of Terms in Set i, SetX j s`i'sx`j't`k'NTX = number of TermX in Set i, SetX j, Term k s`i'sx`j't`k'tx`m' = the variable names that compose Set i, SetX j, Term k, TermX m nSets = total number of Sets (including dependent var set (#1) and interest var set (#2)) n_var_combinations = total number of variable combinations meeting the user's grouping and either/or criteria allvarnames = list of all of the variable names allvarnames_clean = list of all the variable names, with dependent and interest variables preceded by "__" and rotated variable names preceded by "r_" any extraneous characters e.g. "." converted to "_" always_in_varnames = list of all the always in variable names b_always_in_clean = list of all the always in variable names precede by "b_" with any extraneous characters e.g. "." converted to "_" intvarlist = variable(s) of interest name(s), separated by | depvarlist = dependent variable(s) name(s), separated by | If the display_only option is specified, ParseVarlist returns nothing. */ program multivrs_parse_varlist, rclass return add syntax anything (name = varlist_input) [ , display_only] local nSets 0 local depvarlist "" local intvarlist "" local allvarnames "" local allvarnames_clean "" local always_in_varnames "" local b_always_in_clean "" mata: multivrs_varnames = asarray_create() while `"`:list retok varlist_input'"' != "" { //Isolate the first grouped set of the varlist gettoken set varlist_input : varlist_input, bind match(par) if "`par'" == "" { if !strmatch("`set'", "*.*") capture unab set : `set' if `:word count `set'' != 1 { gettoken set rest : set local varlist_input `"`rest' `varlist_input'"' } } //Identify the components of this grouped set. local ++nSets local nsx 1 while `"`:list retok set'"' != "" { /* multivrs_expand_interxn_wrapper `set' local set `r(expanded)' */ //Build up setx by getting tokens until you reach | or the end of the set local setx "" gettoken setx0 set : set, bind parse(" |") while `"`setx0'"' != "|" & `"`setx0'"' != "" { local setx `"`setx' `setx0'"' gettoken setx0 set : set, bind parse(" |") } local nt 0 while `"`:list retok setx'"' != "" { gettoken term setx : setx, bind match(par) local ++nt local ntx 1 while `"`:list retok term'"' != "" { //There should be no more parentheses within the term so no need for bind option gettoken termx0 term : term, parse("|") if "`termx0'" == "|" { local ++ntx } else { local termx "" //Build up termx by getting tokens until the end of the term while `"`:list retok termx0'"' != "" { gettoken tk termx0 : termx0 if !strmatch("`tk'", "*.*") capture unab tk : `tk' /* //here is where you expand a single interaction if _rc != 0 { multivrs_expand_interxn `tk' local tk `r(expanded)' } */ local termx "`termx' `tk'" } //Build the depvarlist: Set #1, every setx, Term #1, Word 1 if `nSets' == 1 { ProcessKeyVariable `termx', nt(`nt') curr_varlist(`depvarlist') local depvarlist `r(new_varlist)' } //Build the intvarlist : Set #2, every setx, Term #1, Word 1 if `nSets' == 2 { ProcessKeyVariable `termx', nt(`nt') curr_varlist(`intvarlist') is_intvar local intvarlist `r(new_varlist)' } local s`nSets'sx`nsx't`nt'tx`ntx' `termx' local allvarnames "`allvarnames' `termx'" foreach varname of local termx { local varname_clean = strtoname("`varname'") if `nSets' == 2 { local always_in_varnames `"`always_in_varnames' `varname'"' local b_always_in_clean `"`b_always_in_clean' b_`varname_clean'"' } if `nSets' > 2 local varname_clean = `"r_`varname_clean'"' else local varname_clean `"__`varname_clean'"' local allvarnames_clean `"`allvarnames_clean' `varname_clean'"' mata: asarray(multivrs_varnames, "`varname_clean'", "`varname'") } } } //done parsing term: Record # of termx local s`nSets'sx`nsx't`nt'NTX `ntx' } //done parsing setx: Record # of term local s`nSets'sx`nsx'NT `nt' if "`setx0'" == "|" { local ++nsx } } //done parsing set: Record # of setx local s`nSets'NSX `nsx' } if "`display_only'" != "display_only" { forvalues is = 1/`nSets' { return local s`is'NSX = `s`is'NSX' forvalues isx = 1/`s`is'NSX' { return local s`is'sx`isx'NT = `s`is'sx`isx'NT' forvalues it = 1/`s`is'sx`isx'NT' { return local s`is'sx`isx't`it'NTX = `s`is'sx`isx't`it'NTX' forvalues itx = 1/`s`is'sx`isx't`it'NTX' { return local s`is'sx`isx't`it'tx`itx' `"`s`is'sx`isx't`it'tx`itx''"' //local TermX_varnames "`s`is'sx`isx't`it'tx`itx''" //local allvarnames "`allvarnames' `TermX_varnames'" } } } } local allvarnames : list uniq allvarnames local allvarnames_clean : list uniq allvarnames_clean local b_always_in_clean : list uniq b_always_in_clean local always_in_varnames : list uniq always_in_varnames local n_var_combinations 1 local nmodels 1 forvalues is = 1/`nSets' { local n_combos_this_Set 0 forvalues isx = 1/`s`is'NSX' { local n_combos_this_SetX 1 forvalues nt = 1/`s`is'sx`isx'NT' { local n_combos_this_SetX = `n_combos_this_SetX' * `s`is'sx`isx't`nt'NTX' } local n_combos_this_Set = `n_combos_this_Set' + `n_combos_this_SetX' } if `is' > 2 local ++n_combos_this_Set local n_var_combinations = `n_var_combinations' * `n_combos_this_Set' } return local nSets `nSets' return local n_var_combinations `n_var_combinations' return local allvarnames `"`allvarnames'"' return local allvarnames_clean `"`allvarnames_clean'"' return local b_always_in_clean `"`b_always_in_clean'"' return local always_in_varnames `"`always_in_varnames'"' return local intvarlist `"`intvarlist'"' return local depvarlist `"`depvarlist'"' } end // End program ParseVarlist /* Check the input of time-series operators to determine whether the name indicates one or more variables */ program CheckVarMeetsCriteria, rclass syntax , var(string) [is_depvar] return add if "`is_depvar'" == "is_depvar" local var_id "dependent variable" else local var_id "variable of interest" // If specified as a factor, check whether it's binary if strmatch("`var'", "i.*") { if "`is_depvar'" == "is_depvar" { di as err "depvar may not be a factor variable" exit 198 } local raw_var = regexr("`var'", "i.", "") qui sum `raw_var' if r(min) == 0 & r(max) == 1 { qui tab `raw_var' if r(r) == 2 { } else { di as err "To use a factor variable as the leading variable of interest, it must be binary and stored as 0/1." exit 198 } } else { di as err "To use a factor variable as the leading variable of interest, it must be binary and stored as 0/1." exit 198 } } else { if strmatch("`var'", "*.*") & regexm("`var'","^([LlDdSsFf]+[0-9LlDdSsFf]*\.[^.]+)$") == 0 { di as err "`var_id' must be a single variable" exit 198 } } end // process the dependent and independent variables of interest program ProcessKeyVariable, rclass syntax anything(name = termx), nt(integer) [curr_varlist(string) is_intvar] return add if "`is_intvar'" == "is_intvar" { local var_id "variable of interest" local is_depvar "" } else { local var_id "dependent variable" local is_depvar "is_depvar" } if `nt' == 1 { local var0 : word 1 of `termx' CheckVarMeetsCriteria, var(`var0') `is_depvar' if "`curr_varlist'" != "" local new_varlist "`curr_varlist' | `var0'" else local new_varlist `var0' } //Each setx of Set 1 should contain only 1 term = 1 dependent variable. else { if "`is_intvar'" == "" { di as err "`var_id' must be a single variable." exit 198 } else local new_varlist `curr_varlist' } return local new_varlist `new_varlist' end