*! domme version 1.2.0 1/12/2024 Joseph N. Luchman // version information at end of file **# Pre-program definition quietly include dominance.mata, adopath program define domme, eclass version 15 if replay() & !strlen("`0'") { if ("`e(cmd)'" != "domme") error 301 if _by() error 190 Display `0' exit 0 } **# Program definition and argument checks syntax [anything(id="equation names" equalok)] [in] [if] [aw pw iw fw], /// Reg(string) Fitstat(string) /// [Sets(string) All(string) /// noCOMplete noCONditional REVerse /// ROPts(string)] **# Wrapper process for -domme- processing in Mata mata: domme_2mata("`reg'", "`fitstat'", "`sets'", "`all'", /// "`conditional'", "`complete'", "`ropts'", "`reverse'", /// "`weight'`exp'", "`in' `if'", "`anything'") **# Ereturn processing tempname domwgts cdldom cptdom stdzd ranks if !strlen("`conditional'") matrix `cdldom' = r(cdldom) if !strlen("`complete'") matrix `cptdom' = r(cptdom) if strlen("`e(title)'") local title "`e(title)'" else if !strlen("`e(title)'") & strlen("`e(cmd)'") local title "`e(cmd)'" else local title "Custom user analysis" matrix `domwgts' = r(domwgts) ereturn post `domwgts' [`weight'`exp'] , obs(`=r(N)') esample(`touse') **# Ereturn scalars ereturn scalar fitstat_o = `=r(fullfs) + r(allfs) + r(consfs)' if `=r(allfs)' != 0 ereturn scalar fitstat_a = r(allfs) if `=r(consfs)' != 0 ereturn scalar fitstat_c = r(consfs) if strlen("`setcount'") { ereturn hidden scalar setcount = `setcount' forvalues set = 1/`setcount' { ereturn local set`set' = trim("`set`set''") } } else ereturn hidden scalar setcount = 0 **# Ereturn macros ereturn hidden local disp_title "`title'" ereturn hidden local reverse "`reverse'" if strlen("allset") ereturn local all = "`allset'" if strlen("`ropts'") ereturn local ropts `"`ropts'"' ereturn local reg "`reg'" ereturn local fitstat "`fitstat'" ereturn local cmd "domme" ereturn local title `"Dominance analysis for multiple equations"' ereturn local cmdline `"domme `0'"' **# Ereturn matrices if !strlen("`conditional'") ereturn matrix cdldom `cdldom' if !strlen("`complete'") ereturn matrix cptdom `cptdom' matrix `ranks' = r(ranks) ereturn matrix ranking `ranks' matrix `stdzd' = r(stdzd) ereturn matrix std `stdzd' Display end /*Display program*/ program define Display version 15 /*set up*/ tempname gendom stzd_gendom ranks matrix `gendom' = e(b) matrix `stzd_gendom' = e(std) matrix `ranks' = e(ranking) local diivs: colnames e(b) local eqivs: coleq e(b) mata: st_local("cdltest", strofreal(cols(st_matrix("e(cdldom)")))) mata: st_local("cpttest", strofreal(cols(st_matrix("e(cptdom)")))) tokenize `diivs' display _newline "{txt}General dominance statistics: `e(disp_title)'" /// _newline "{txt}Number of obs{col 27}={res}{col 40}" %12.0f e(N) display "{txt}Overall Fit Statistic{col 27}={res}{col 36}" /// %16.4f e(fitstat_o) if !missing( e(fitstat_a) ) display "{txt}All Sub-models Fit Stat." /// "{col 27}={res}{col 36}" %16.4f e(fitstat_a) if !missing( e(fitstat_c) ) display "{txt}Constant-only Fit Stat." /// "{col 27}={res}{col 36}" %16.4f e(fitstat_c) display _newline "{txt}{col 13}{c |}{col 20}Dominance" /// "{col 35}Standardized{col 53}Ranking" display "{txt}{col 13}{c |}{col 20}Stat.{col 35}Domin. Stat." display "{txt}{hline 12}{c +}{hline 72}" local current_eq "" forvalues iv = 1/`:list sizeof diivs' { if "`current_eq'" != abbrev("`: word `iv' of `eqivs''", 11) /// display `"{txt}`=abbrev("`: word `iv' of `eqivs''", 11)'{txt}{col 13}{c |}"' local current_eq = abbrev("`: word `iv' of `eqivs''", 11) local `iv' = abbrev("``iv''", 10) display "{txt}{col 2}{lalign 11:``iv''}{c |}{col 14}{res}" /// %15.4f `gendom'[1,`iv'] "{col 29}" %12.4f /// `stzd_gendom'[1,`iv'] "{col 53}" %-2.0f `ranks'[1,`iv'] } display "{txt}{hline 12}{c BT}{hline 72}" if `cdltest' { display "{txt}Conditional dominance statistics" _newline "{hline 85}" matrix list e(cdldom), noheader format(%12.4f) display "{txt}{hline 85}" } if `cpttest' { display "{txt}Complete dominance designation" _newline "{hline 85}" matrix list e(cptdom), noheader display "{txt}{hline 85}" } if `=`cpttest'*`cdltest'' { display _newline "{txt}Strongest dominance designations" tempname bestdom cdl gen decision if strlen("`e(reverse)'") mata: st_matrix("`bestdom'", /// st_matrix("e(cptdom)"):*-1) else matrix `bestdom' = e(cptdom) forvalues dominator = 1/`=colsof(e(cdldom))-1' { forvalues dominatee = `=`dominator'+1'/`=colsof(e(cdldom))' { scalar `cdl' = 0 scalar `gen' = 0 mata: st_numscalar("`cdl'", /// ( sum( st_matrix("e(cdldom)")[`dominator', .] /// :>st_matrix("e(cdldom)")[`dominatee', .] ) ) /// :==rows( st_matrix("e(cdldom)") ) ) if !`cdl' mata: /// st_numscalar("`cdl'", -1*((sum(st_matrix("e(cdldom)")[`dominator', .] /// :st_matrix("e(b)")[1, `dominatee']) if !`gen' mata: st_numscalar("`gen'", /// (st_matrix("e(b)")[1, `dominator']?":+eq_display \ parm_display)' ) st_matrixcolstripe("r(cptdom)", ("=(st_matrix("r(domwgts)")') ) ) st_matrixcolstripe("r(ranks)", (eq_display \ parm_display)' ) st_numscalar("r(N)", obs) st_local("reg", reg) st_local("touse", marks[1]) built_in st_local("built_in", strofreal(strlen(bi_type)>0)) st_local("built_in_style", bi_type) st_numscalar("r(allfs)", all_fitstat) st_numscalar("r(consfs)", (strlen(bi_type) ? 0 : cons_fitstat) ) st_numscalar("r(fullfs)", full_fitstat) /* mechanism to drop constraints if generated */ exit_constraint((dv_iv_cns, set_cns, all_cns), 0) } end **# Mata function to execute 'domme-flavored' models version 15 mata: mata set matastrict on real scalar domme_call(string scalar params_to_remove, class AssociativeArray scalar model_specs) { real scalar fitstat, rc string scalar params_in_model string rowvector cns /*enumerate all constraints generated*/ cns = tokens(invtokens(model_specs.get("cns"))) /*constraints indicate omitted parm est; reverse to get all included*/ params_in_model = select(cns, !colsum((J(length(tokens(params_to_remove)), 1, strtoreal(cns)):==J(1, length(cns), strtoreal(tokens(params_to_remove))')))) rc = _stata(model_specs.get("reg") + " [" + model_specs.get("weight") + "] " + model_specs.get("inif") + ", constraints(" + invtokens(params_in_model) + ") " + model_specs.get("ropts"), 1) /*drop constraints if generated*/ if (rc) { exit_constraint(cns, rc) } fitstat = built_in_fitstat(model_specs.get("fitstat"), model_specs.get("bi_type"), model_specs.get("cons_fitstat"), 0) fitstat = fitstat - model_specs.get("all_fitstat") - (strlen(model_specs.get("bi_type")) ? 0 : model_specs.get("cons_fitstat") ) return(fitstat) } end **# Mata function to drop constraints and exit version 15 mata: mata set matastrict on void exit_constraint(string rowvector cns_list, numeric scalar exit_num) { numeric scalar cns for (cns=1; cns<=length(cns_list); cns++) { stata("constraint drop " + cns_list[cns]) } if (exit_num) exit(exit_num) } end **# Mata program to obtain fit statistics after model estimation version 15 mata: mata set matastrict on numeric scalar built_in_fitstat( string scalar fitstat, string scalar type, numeric scalar constant, numeric scalar isconstant ) { numeric scalar value /*compute McFadden R2*/ if (type == "mcf") { value = (isconstant? st_numscalar("e(ll)") : 1 - st_numscalar("e(ll)")/constant) } /*not a built-in, pass the name and assume Stata returns it*/ else value = st_numscalar( strtrim(fitstat) ) return(value) } end /* programming notes and history - domme version 1.0 - date - July 2, 2019 -base version // 1.0.1 - April 17, 2021 (initiating new versioning: #major.#minor.#patch) -update to documentation for SJ article -bug fix on constraint dropping with all() option and use with xi: --- domme version 1.1.0 - February 7, 2023 - leverage dominance() function in -domin-; create own function to function passing; Mata struct to handle input specs - -domin- now a dependency. - use an AssociativeArray to map parameters/parameter sets to constraints in a way that is conformable with -domin- - extensive documentation update - fixed complete dominance table display; retains equation name and adds informative prefix // 1.1.1 - March 7, 2023 - call 'dominance.mata' as opposed to using 'lb_dominance.mlib' to allow backward compatability // 1.1.2 - August 14, 2023 - migrated to a sub-method in the -domin- module - call temporary 'dominance0.mata' (v 0.0) for time being until re-designed similar to -domin- to use 'dominance.mata' versions > 0.0 --- domme version 1.2.0 - January 12, 2024 - most of command migrated to Mata - now dependent on dominance.mata (not dominance0.mata) - fixed references to 'all subsets' - should be 'all sub-models' - minimum version sync-ed with -domin- at 15 (not 15.1) - fixed issue with -all()- option; not consistent with documentation - required full 'all' typed (not 'a()') - estrella, aic and bic disallowed with built-in; mcfadden remains */