*! version 0.7.5 11jun2026 (companion predict program, shipped with xtdpthresh 0.7.5) *! *! predict program for xtdpthresh: residuals, xb, regime, arresiduals. *! *! Architecture: xtdpthresh_run persists two row sets in Mata globals that *! survive -restore-, both keyed by (panelvar, timevar): *! (1) the ESTIMATION-equation series — y and e-hat on the rows the estimator *! actually used (FOD rows under method(fod); FD rows under fd); *! (2) the FD AR-test series — the exact rows the AR(1)/AR(2) tests consume. *! This program merges the requested series back by key via xdpt2_p_fill() *! (defined in xtdpthresh.ado), guarded by e(p_serial) against stale Mata *! state. Both series are identical BY CONSTRUCTION to their estimation-time *! values, for every method and any panel pattern — no transformation, trim, *! t-2 membership, or zero-instrument (B4) filter is re-derived here. *! *! Syntax: *! predict [type] newvar [if] [in] [, RESiduals XB Regime ARResiduals] *! *! residuals (default) residual of the ESTIMATED equation: *! method(fd) — FD residual dy - dW(g)theta *! method(fod) — forward-orthogonal-deviation residual *! method(system) — FD-restack residual (level-equation *! residuals are not yet exposed; equals *! -arresiduals- for this method) *! arresiduals the FD residual series the AR(1)/AR(2) tests consume *! (xtabond2 convention; always FD-form). For method(fd) this *! equals -residuals-; for method(fod) it is the FD restack, *! which differs from the FOD estimation residual (different *! variance and a mechanical first-order autocorrelation — *! use this, not -residuals-, to reproduce the reported AR *! statistics under fod). *! xb fit of whichever equation -residuals- corresponds to *! (residuals + xb = transformed y, row by row) *! regime 1{q_it > g} on raw rows (within if/in, q non-missing); *! not restricted to e(sample) *! *! Notes: *! - Requires xtdpthresh as the active estimation results AND its Mata state *! intact. After -mata: mata clear-, -discard-, a Stata restart, or *! -estimates restore- of an older run, re-run xtdpthresh first (a clear *! error is issued in those cases). *! - Rows outside the estimation row set (trimmed rows, rows failing the t-2 *! instrument-history requirement, zero-instrument rows) are missing. program xtdpthresh_p version 15.0 if "`e(cmd)'" != "xtdpthresh" { di as err "predict must follow xtdpthresh" exit 301 } syntax newvarname [if] [in] [, RESiduals XB Regime ARResiduals] // Resolve statistic (default residuals); reject combinations local n_opts = ("`residuals'" != "") + ("`xb'" != "") /// + ("`regime'" != "") + ("`arresiduals'" != "") if `n_opts' > 1 { di as err "only one of residuals, xb, regime, arresiduals may be specified" exit 198 } local stat "residuals" if "`xb'" != "" local stat "xb" if "`regime'" != "" local stat "regime" if "`arresiduals'" != "" local stat "arresiduals" local panelvar "`e(panelvar)'" local timevar "`e(timevar)'" local qvar "`e(q_var)'" local method "`e(method)'" marksample touse, novarlist // ---------- regime indicator: raw rows, no e(sample) restriction ---------- if "`stat'" == "regime" { tempname gam scalar `gam' = e(gamma) qui gen `typlist' `varlist' = (`qvar' > `gam') /// if `touse' & !missing(`qvar') label var `varlist' "1{`qvar' > gamma_hat} (xtdpthresh)" exit } // ---------- residuals / xb / arresiduals: merge from persisted rows ------ // e(p_serial) exists only for runs that stored the row sets (>= v0.7.3). if missing(e(p_serial)) { di as err "these e() results were produced by an xtdpthresh version (or run)" di as err "that did not store prediction rows; re-run xtdpthresh (>= v0.7.4)" exit 301 } // source: 1 = FD AR-test series, 2 = estimation-equation series. // arresiduals -> always the FD AR-test series (source 1) // residuals/xb -> estimation-equation series (source 2) EXCEPT for // fd (the two series are identical; use 1) and system (level rows make // the estimation series non-mergeable by key; route to the FD series). // which: 1 = residual, 2 = xb (fit = dy - e-hat, row by row). if "`stat'" == "arresiduals" { local source = 1 local which = 1 } else { local which = cond("`stat'" == "xb", 2, 1) local source = cond("`method'" == "fod", 2, 1) } qui gen `typlist' `varlist' = . if `touse' mata: xdpt2_p_fill("`panelvar'", "`timevar'", "`varlist'", /// "`touse'", `source', `which', `=e(p_serial)') // ---------- labels ---------- if "`stat'" == "arresiduals" { label var `varlist' "FD AR-test residual (xtdpthresh, `method')" } else if "`stat'" == "xb" { if "`method'" == "fod" /// label var `varlist' "FOD fit (estimation eq, xtdpthresh)" else if "`method'" == "system" /// label var `varlist' "FD-restack fit (xtdpthresh system)" else /// label var `varlist' "FD fit dW*theta_hat (xtdpthresh)" } else { if "`method'" == "fod" /// label var `varlist' "FOD residual (estimation eq, xtdpthresh)" else if "`method'" == "system" /// label var `varlist' "FD-restack residual (xtdpthresh system)" else /// label var `varlist' "FD residual (estimation eq, xtdpthresh)" } end // ============================================================================ // Mata helper for predict — duplicated from xtdpthresh.ado because functions // in an ado's inline mata: block are private to that ado on Stata 17 (the // version targeted by SSC), so xtdpthresh.ado's xdpt2_p_fill is not callable // from xtdpthresh_p.ado. The externals xdpt_p_resid / xdpt_p_est / // xdpt_p_serial_m ARE persistent across calls (Mata externals survive), so // they refer to the values xtdpthresh_run populated. // ============================================================================ mata: mata set matastrict off void xdpt2_p_fill(string scalar pvar, string scalar tvar, string scalar outvar, string scalar touse, real scalar source, real scalar which, real scalar serial_expect) { external real matrix xdpt_p_resid, xdpt_p_est, xdpt_p_serial_m real matrix D, S real scalar r, v transmorphic A S = (source == 2 ? xdpt_p_est : xdpt_p_resid) if (rows(xdpt_p_serial_m) == 0 | rows(S) == 0) { errprintf("xtdpthresh predict: stored estimation rows not found in Mata memory\n") errprintf(" (cleared by -mata: mata clear-, -discard-, or restarting Stata).\n") errprintf(" Re-run xtdpthresh, then predict.\n") exit(498) } if (serial_expect >= . | xdpt_p_serial_m[1, 1] != serial_expect) { errprintf("xtdpthresh predict: stored rows belong to a different xtdpthresh run\n") errprintf(" than the current e() results (e.g. -estimates restore- of an older\n") errprintf(" model). Re-run xtdpthresh, then predict.\n") exit(498) } A = asarray_create("real", 2) asarray_notfound(A, .) for (r = 1; r <= rows(S); r++) { asarray(A, (S[r, 1], S[r, 2]), (which == 2 ? S[r, 3] - S[r, 4] : S[r, 4])) } st_view(D = ., ., (pvar, tvar, outvar), touse) for (r = 1; r <= rows(D); r++) { v = asarray(A, (D[r, 1], D[r, 2])) if (v < .) D[r, 3] = v } } end