Skip to content

Commit 67b3613

Browse files
committed
Removed optimization hacks from WRE code because they created matrices with 1 row per obs and 1 col per replication
1 parent d3397eb commit 67b3613

File tree

3 files changed

+37
-74
lines changed

3 files changed

+37
-74
lines changed

boottest.ado

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*! boottest 2.2.2 25 September 2018
1+
*! boottest 2.3.0 8 Octember 2018
22
*! Copyright (C) 2015-18 David Roodman
33

44
* This program is free software: you can redistribute it and/or modify
@@ -731,6 +731,7 @@ program define _boottest, rclass sortpreserve
731731
end
732732

733733
* Version history
734+
* 2.3.0 Removed optimization hacks from WRE code because they created matrices with 1 row per obs and 1 col per replication
734735
* 2.2.2 Allowed quietly option in ado interface to suppress dots. Made sorts in Mata code stable.
735736
* For LIML, reverted to finding eigenvalue of I-TT/TPZT instead of TT/TPZT; seems to avoid instances of eigensystem() returning all missing
736737
* 2.2.1 Fixed failure to detect # of FE after areg in Stata version < 15

boottest.mata

Lines changed: 35 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ struct structFE {
3939
4040
class AnalyticalModel { // class for analyitcal OLS, 2SLS, LIML, GMM estimation--everything but iterative ML
4141
real scalar LIML, YY, ee, eec, Fuller, AR, K, k
42-
real matrix ZX, ZXEnd, ZZ, H_2SLS, invH, A, VR0, ZVR0, e2, numer, Splus, pi, XXEnd, dbetads, Ze2
42+
real matrix ZX, ZXEnd, ZZ, H_2SLS, invH, A, VR0, ZVR0, e2, numer, Splus, pi, XXEnd, dbetads, Ze2, ZExclXEnd, XExXEnd
4343
real colvector sAll, e, beta, beta0, Ze, ZY
4444
real rowvector YXEnd
4545
pointer(real colvector) scalar pY
46-
pointer(real matrix) scalar pXEnd, pXX, pXY, pZExclY, pXExY, pZExclXEnd, pV, pW, pinvZZ, pXExXEx, pZXEx, pXExXEnd, pH, pR0, pS
46+
pointer(real matrix) scalar pXEnd, pXX, pXY, pZExclY, pXExY, pV, pW, pinvZZ, pXExXEx, pZXEx, pH, pR0, pS
4747
pointer (class boottestModel scalar) scalar parent
4848
pointer (class AnalyticalModel scalar) scalar DGP
4949
struct smatrix matrix CT_ZVR0
@@ -57,7 +57,7 @@ class boottestModel {
5757
real scalar scoreBS, reps, small, weighttype, null, dirty, initialized, Neq, ML, Nobs, _Nobs, k, kEx, el, sumwt, NClustVar, robust, weights, REst, multiplier, quietly, FEboot, NErrClustCombs, ///
5858
sqrt, hascons, LIML, Fuller, K, IV, WRE, WREnonAR, ptype, twotailed, df, df_r, AR, D, cuepoint, willplot, plotted, NumH0s, p, NBootClustVar, NErrClust, ///
5959
NFE, doQQ, granular, purerobust, subcluster, NBootClust, repsFeas, u_sd, level, MaxMatSize, NWeightGrps, enumerate
60-
real matrix QQ, eZVR0, SewtXV, VR0, betadev, numer, u, U, S, SAR, SAll, LAll_invRAllLAll, plot, CI, CT_WE, infoBootAll, infoErrAll, infoAllData, J_ClustN_NBootClust, denom0
60+
real matrix QQ, eZVR0, SewtXV, VR0, betadev, numer, u, S, SAR, SAll, LAll_invRAllLAll, plot, CI, CT_WE, infoBootAll, infoErrAll, infoAllData, J_ClustN_NBootClust, denom0
6161
pointer (real matrix) scalar pZExcl, pR, pR0, pID, pFEID, pXEnd, pXEx, pG, pX, pinfoBootData, pinfoErrData
6262
pointer (real colvector) scalar pr, pr0, pY, pSc, pwt, pW, pV
6363
string scalar wttype, madjtype, seed
@@ -67,7 +67,7 @@ class boottestModel {
6767
class AnalyticalModel scalar M_DGP
6868
pointer (class AnalyticalModel scalar) scalar pM_Repl, pM
6969
struct smatrix matrix denom
70-
struct smatrix colvector Kcd, XEndstar, XExXEndstar, ZExclXEndstar, XZi, eZi, euZVR0
70+
struct smatrix colvector Kcd, XZi, eZi, euZVR0
7171
struct structFE rowvector FEs
7272
pointer (real matrix) matrix pQ
7373
pointer (struct boottest_clust scalar) scalar pBootClust
@@ -121,25 +121,25 @@ void AnalyticalModel::SetS(real matrix S) {
121121
122122
// stuff that can be done before S & r0 set, but depend on endogenous variables, which are bootstrapped in WRE
123123
void AnalyticalModel::InitEndog(pointer (real colvector) scalar _pY, pointer (real matrix) scalar _pXEnd, | ///
124-
pointer (real colvector) scalar _pZExclY, pointer (real rowvector) scalar _pXExY, real scalar _YY, pointer (real matrix) scalar _pZExclXEnd, pointer (real matrix) scalar _pXExXEnd) {
124+
pointer (real colvector) scalar _pZExclY, pointer (real rowvector) scalar _pXExY) {
125125
126126
pY = partialFE(_pY); pXEnd = partialFE(_pXEnd)
127-
128-
pXExY = _pXExY==NULL? &cross(*parent->pXEx, *parent->pwt, *parent->pY) : _pXExY
127+
128+
pXExY = _pXExY==NULL? &cross(*parent->pXEx, *parent->pwt, *pY) : _pXExY
129129
if (K | AR)
130130
pZExclY = _pZExclY==NULL? &cross(*parent->pZExcl, *parent->pwt, *pY) : _pZExclY
131131
if (K) {
132-
pXExXEnd = _pXExXEnd ==NULL? &cross(*parent->pXEx , *parent->pwt, *pXEnd) : _pXExXEnd
133-
pZExclXEnd = _pZExclXEnd==NULL? &cross(*parent->pZExcl, *parent->pwt, *pXEnd) : _pZExclXEnd
134-
ZXEnd = *pXExXEnd \ *pZExclXEnd
132+
XExXEnd = cross(*parent->pXEx , *parent->pwt, *pXEnd)
133+
ZExclXEnd = cross(*parent->pZExcl, *parent->pwt, *pXEnd)
134+
ZXEnd = XExXEnd \ ZExclXEnd
135135
ZX = *pZXEx, ZXEnd
136-
XXEnd = *pXExXEnd \ cross(*pXEnd, *parent->pwt, *pXEnd)
137-
pXX = &(*pXExXEx, *pXExXEnd \ XXEnd')
136+
XXEnd = XExXEnd \ cross(*pXEnd, *parent->pwt, *pXEnd)
137+
pXX = &(*pXExXEx, XExXEnd \ XXEnd')
138138
YXEnd = cross(*pY, *parent->pwt, *pXEnd)
139139
ZY = *pXExY \ *pZExclY
140140
pXY = &(*pXExY \ YXEnd')
141141
if (LIML | !(parent->robust | parent->scoreBS))
142-
YY = _YY==.? cross(*pY, *parent->pwt, *pY) : _YY
142+
YY = cross(*pY, *parent->pwt, *pY)
143143
144144
if (parent->IV) // if GMM weight matrix not provided, prepare 2SLS one
145145
A = (I(parent->kEx) \ J(parent->el-parent->kEx, parent->kEx, 0)), *pinvZZ * ZXEnd // 2SLS is (A' ZX)^-1 * (A'ZY). Also apparently used in k-class and LIML robust VCV by Stata convention
@@ -845,7 +845,6 @@ void boottestModel::boottest() {
845845
846846
denom = smatrix(df,df)
847847
if (WREnonAR) {
848-
XEndstar = XExXEndstar = ZExclXEndstar = smatrix(D-1)
849848
if (NClustVar)
850849
XZi = eZi = smatrix(NBootClust)
851850
} else if (robust) {
@@ -890,7 +889,7 @@ void boottestModel::boottest() {
890889
891890
if (!ML) // GMM, 2SLS, analytical LIML
892891
if (AR) {
893-
pM_Repl->InitEndog(&(*pY - *pXEnd * *pr0), NULL, &(*M_DGP.pZExclY - *M_DGP.pZExclXEnd * *pr0), &(*M_DGP.pXExY - *M_DGP.pXExXEnd * *pr0))
892+
pM_Repl->InitEndog(&(*pY - *pXEnd * *pr0), NULL, &(*M_DGP.pZExclY - M_DGP.ZExclXEnd * *pr0), &(*M_DGP.pXExY - M_DGP.XExXEnd * *pr0))
894893
pM_Repl->InitEstimate()
895894
pM_Repl->Estimate(sAR)
896895
pM_Repl->InitTestDenoms(SAR)
@@ -954,21 +953,18 @@ void boottestModel::MakeWildWeights(real scalar _reps, real scalar first) {
954953
u = runiform(NBootClust, _reps+first) :>= .5; u = u :- .5 // Rademacher weights, divided by 2
955954
u_sd = .5
956955
}
956+
957957
if (first)
958958
u[,1] = J(NBootClust, 1, WREnonAR? 0 : u_sd) // keep original residuals in first entry to compute base model stat
959-
960-
U = WREnonAR? u[IDBootData,] : J(0,0,0)
961959
}
962960
963-
964961
real scalar boottestModel::MakeWREStats(real scalar thisWeightGrpStart, real scalar thisWeightGrpStop) {
965-
real scalar c, j, i
966-
real colvector _e, Ystar, _beta, betaEnd
967-
real rowvector YstarYstar
968-
real matrix ZExclYstar, XExYstar, Subscripts, Zi, AVR0, t, XExi
969-
pointer (real matrix) scalar peZVR0, pu, pXEndstar, pXExXEndstar, pZExclXEndstar
970962
pragma unused thisWeightGrpStop
971-
963+
real scalar c, j, i
964+
real colvector _e, _beta, betaEnd, _u
965+
real matrix Subscripts, Zi, AVR0, t, XExi
966+
pointer (real matrix) scalar peZVR0
967+
972968
if (initialized & !null) { // if not imposing null and we have returned, then df=1; and distribution doesn't change with r0, only test stat
973969
numer[1] = *pR0 * pM_Repl->beta - *pr0
974970
Dist[1] = numer[1] / sqrt(denom.M[1]) * multiplier
@@ -977,52 +973,27 @@ real scalar boottestModel::MakeWREStats(real scalar thisWeightGrpStart, real sca
977973
978974
if (thisWeightGrpStart == 1) { // first/only weight group? initialize a couple of things
979975
_e = M_DGP.e + M_DGP.e2 * M_DGP.beta[|kEx+1\.|]
980-
pu = NClustVar? &U : &u
981-
}
982-
983-
Ystar = *M_DGP.pY :+ _e :* *pu
984-
XExYstar = cross(*pXEx , *pwt, Ystar)
985-
ZExclYstar = cross(*pZExcl, *pwt, Ystar)
986-
987-
if ((LIML | !robust) & !NFE)
988-
YstarYstar = weights? cross(*pwt, Ystar:*Ystar) : colsum(Ystar:*Ystar)
989976
990-
if (D==2) {
991-
XEndstar.M = *pXEnd :+ M_DGP.e2 :* *pu
992-
XExXEndstar.M = cross(*pXEx , *pwt, XEndstar.M)
993-
ZExclXEndstar.M = cross(*pZExcl, *pwt, XEndstar.M)
994-
} else
995-
for (j=D-1; j; j--) {
996-
XEndstar[j].M = (*pXEnd)[,j] :+ M_DGP.e2[,j] :* *pu
997-
XExXEndstar [j].M = cross(*pXEx , *pwt, XEndstar[j].M)
998-
ZExclXEndstar[j].M = cross(*pZExcl, *pwt, XEndstar[j].M)
999-
}
1000-
1001-
if (NClustVar & !NFE) // prep for optimized computation for bootstrapping cluster when no FE
1002-
for (i=NBootClust; i; i--) {
1003-
Subscripts = (*pinfoBootData)[i,]', (.\.)
1004-
XExi = kEx? (*pXEx)[|Subscripts|] : J((*pinfoBootData)[i,2]-(*pinfoBootData)[i,1]+1,0,0)
1005-
Zi = XExi , (*pZExcl)[|Subscripts|] // inefficient?
1006-
if (weights) Zi = Zi :* (*pwt)[|Subscripts|]
1007-
XZi[i].M = cross(XExi, Zi) \ cross((*pXEnd)[|Subscripts|], Zi) \ cross((*pY)[|Subscripts|], Zi)
1008-
eZi[i].M = cross(M_DGP.e2[|Subscripts|], Zi) \ cross( _e[|Subscripts|], Zi)
1009-
}
977+
if (NClustVar & !NFE) // prep for optimized computation for bootstrapping cluster when no FE
978+
for (i=NBootClust; i; i--) {
979+
Subscripts = (*pinfoBootData)[i,]', (.\.)
980+
XExi = kEx? (*pXEx)[|Subscripts|] : J(Subscripts[2,1]-Subscripts[1,1]+1,0,0)
981+
Zi = XExi , (*pZExcl)[|Subscripts|] // inefficient?
982+
if (weights) Zi = Zi :* (*pwt)[|Subscripts|]
983+
XZi[i].M = cross(XExi, Zi) \ cross((*pXEnd)[|Subscripts|], Zi) \ cross((*pY)[|Subscripts|], Zi)
984+
eZi[i].M = cross(M_DGP.e2[|Subscripts|], Zi) \ cross( _e[|Subscripts|], Zi)
985+
}
986+
}
1010987
1011988
for (j=cols(u); j; j--) { // WRE bootstrap
1012-
pXEndstar = &( XEndstar.M [,j])
1013-
pXExXEndstar = &(XExXEndstar.M [,j])
1014-
pZExclXEndstar = &(ZExclXEndstar.M[,j])
1015-
for (i=2; i<D; i++) {
1016-
pXEndstar = &(*pXEndstar , XEndstar [i].M[,j])
1017-
pXExXEndstar = &(*pXExXEndstar , XExXEndstar [i].M[,j])
1018-
pZExclXEndstar = &(*pZExclXEndstar, ZExclXEndstar[i].M[,j])
1019-
}
1020-
1021-
pM_Repl->InitEndog(&(Ystar[,j]), pXEndstar, &(ZExclYstar[,j]), &(XExYstar[,j]), (cols(YstarYstar)? YstarYstar[j] : .), pZExclXEndstar, pXExXEndstar)
989+
_u = u[IDBootData,j]
990+
991+
pM_Repl->InitEndog(&(*M_DGP.pY:+_e:*_u) , &(*pXEnd:+M_DGP.e2:*_u))
1022992
pM_Repl->InitEstimate()
1023993
pM_Repl->InitTestDenoms(S) // prepare for replication regressions, null not imposed
1024994
pM_Repl->Estimate(s)
1025-
numer = null | j==1? *pR0 * pM_Repl->beta - *pr0 : *pR0 * (pM_Repl->beta - M_DGP.beta0)
995+
996+
numer = null | thisWeightGrpStart==1 & j==1? *pR0 * pM_Repl->beta - *pr0 : *pR0 * (pM_Repl->beta - M_DGP.beta0)
1026997
1027998
if (robust) { // Compute denominator for this WRE test stat
1028999
denom = smatrix()
@@ -1048,7 +1019,6 @@ real scalar boottestModel::MakeWREStats(real scalar thisWeightGrpStart, real sca
10481019
denom.M = (*pR0 * pM_Repl->VR0) * pM_Repl->eec
10491020
10501021
Dist[j+thisWeightGrpStart-1] = sqrt? numer/sqrt(denom.M) : cross(numer, invsym(denom.M) * numer)
1051-
10521022
}
10531023
if (thisWeightGrpStart==1 & df==2) denom0 = denom.M // original-sample denominator
10541024
@@ -1093,14 +1063,6 @@ real scalar boottestModel::MakeNonWRENumers(real scalar thisWeightGrpStart, real
10931063
return(0)
10941064
}
10951065
1096-
1097-
1098-
1099-
1100-
1101-
1102-
1103-
11041066
void boottestModel::MakeNonWREStats(real scalar thisWeightGrpStart, real scalar thisWeightGrpStop) {
11051067
real scalar d, i, c, j, l; real matrix eu, eueu, t; real colvector numer_l; pointer (real matrix) scalar peZVR0, pVR0
11061068

lboottest.mlib

-4.59 KB
Binary file not shown.

0 commit comments

Comments
 (0)