From 5284b9f67b69929bdafb51489c9bb2bd7ac3aa17 Mon Sep 17 00:00:00 2001 From: droodman Date: Sun, 12 Dec 2021 22:04:09 -0500 Subject: [PATCH] More type stabilization; use of SnoopCompile.write to precompile --- .gitignore | 2 + Project.toml | 2 +- precompiler | 0 precompiler.jl | 80 +++++++++++ src/StrBoottest.jl | 49 +++++-- src/WRE.jl | 25 ++-- src/WildBootTests.jl | 10 +- src/estimators.jl | 245 ++++++++++++++------------------ src/init.jl | 122 ++++++++-------- src/interface.jl | 151 +++++++++++++++++--- src/nonWRE.jl | 18 +-- src/plot-CI.jl | 64 +++++---- src/precompile.jl | 82 ----------- src/precompile_WildBootTests.jl | 69 +++++++++ src/utilities.jl | 62 ++++---- test/unittests.log | 34 ++--- 16 files changed, 597 insertions(+), 418 deletions(-) create mode 100644 precompiler create mode 100644 precompiler.jl delete mode 100644 src/precompile.jl create mode 100644 src/precompile_WildBootTests.jl diff --git a/.gitignore b/.gitignore index 7e3408f..7b98466 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ voters.dta test/profiling.jl src/WRE2.jl docs/build/ +profile.pb.gz +src/precompiler.jl diff --git a/Project.toml b/Project.toml index f96dd6f..af74400 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "WildBootTests" uuid = "65c2e505-86ba-4c19-93f1-95506c1443d5" authors = ["droodman "] -version = "0.6.2" +version = "0.6.3" [deps] Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" diff --git a/precompiler b/precompiler new file mode 100644 index 0000000..e69de29 diff --git a/precompiler.jl b/precompiler.jl new file mode 100644 index 0000000..f195c2c --- /dev/null +++ b/precompiler.jl @@ -0,0 +1,80 @@ +# run this in a fresh Julia session after having commented out the precompile lines at the bottom of WildBootTests.jl, both to avoid complications and force re-precompile +push!(LOAD_PATH, ".") +using WildBootTests + +using SnoopCompileCore +tinf = @snoopi_deep begin + for T in (Float32, Float64) + resp, predexog, clustid = rand(T, 400), rand(T, 400, 4), Int32.(rand(1900:1920, 400)) + test = wildboottest(T, [0 0 0 1], [.04]; resp, predexog, clustid, auxwttype=WildBootTests.webb) + teststat(test); p(test); CI(test); plotpoints(test); + + test = wildboottest(T, [0 0 0 1], [.04]; resp, predexog, clustid, reps=9999999, auxwttype=WildBootTests.webb, getCI=false) + teststat(test); p(test); + + test = wildboottest(T, [0 0 0 1; 0 0 1 0], [0.05; -0.02]; resp, predexog, clustid, reps=9999, auxwttype=WildBootTests.webb) + teststat(test); p(test); + + resp, predexog, clustid = rand(T, 2000), rand(T, 2000, 4), Int32.(rand(1:12, 2000)) + test = wildboottest(T, [0 1 0 0], [0]; R1=[0 0 1 0], r1=[.2], resp, predexog, clustid) + teststat(test); p(test); CI(test); + + resp, predexog, clustid, predendog, inst = rand(T, 2000), rand(T, 2000, 3), Int32.(rand(1:12, 2000)), rand(2000), rand(2000) + test = wildboottest(T, [0 0 0 1], [0]; resp, predexog, predendog, inst, clustid, small=false, reps=9999, ptype=WildBootTests.equaltail) + teststat(test); p(test); CI(test); + + test = wildboottest(T, [0 0 0 1], [.0]; resp, predexog, predendog, inst, clustid, small=false, reps=9999, auxwttype=WildBootTests.webb, bootstrapc=true, ptype=WildBootTests.equaltail) + teststat(test); p(test); CI(test); + + test = wildboottest(T, [0 0 0 1], [0]; resp, predexog, predendog, inst, clustid, small=false, ARubin=true, reps=9999) + teststat(test); p(test); CI(test); + + test = wildboottest(T, [0 0 0 1], [0]; resp, predexog, predendog, inst, clustid, small=false, ARubin=true, reps=9999, imposenull=false) + teststat(test); p(test); CI(test); + + test = wildboottest(T, [0 0 0 1], [0]; resp, predexog, predendog, inst, clustid, small=false, reps=0) + teststat(test); p(test); CI(test); + + test = wildboottest(T, [0 0 0 1], [0]; resp, predexog, predendog, inst, clustid, small=false, reps=0, imposenull=false) + teststat(test); p(test); CI(test); + + resp, predexog, clustid, predendog, inst = rand(T, 2000), rand(T, 2000, 1), Int32.(rand(1:12, 2000)), rand(2000), rand(2000,2) + test = wildboottest(T, [0 1], [0]; resp, predexog, predendog, inst, LIML=true, clustid, small=false, reps=999) + teststat(test); p(test); CI(test); + + resp, predexog, clustid, predendog, inst = rand(T, 2000,), rand(T, 2000, 5), Int32.(rand(1:12, 2000)), rand(2000), rand(2000,2) + test = wildboottest(T, [0 0 0 0 0 1], [0]; resp, predexog, predendog, inst, Fuller=1, clustid, small=false, reps=9999, auxwttype=WildBootTests.webb) + teststat(test); p(test); CI(test); + + resp, predexog, clustid, obswt, feid = rand(T, 2000,), rand(T, 2000, 3), Int32.(rand(1:12, 2000, 2)), rand(2000), Int64.(rand(1:12,2000)) + test = wildboottest(T, [0 0 1], [0]; resp, predexog, clustid, nbootclustvar=1, nerrclustvar=2, obswt, feid) + teststat(test); p(test); CI(test); + + resp, predexog, clustid, feid = rand(T, 20000,), rand(T, 20000, 12), Int32.(rand(1:12, 20000, 2)), Int32.(rand(1:12,20000)) + test = wildboottest(T, [1 zeros(1,size(predexog,2)-1)], [0]; resp, predexog, clustid, nbootclustvar=1, nerrclustvar=2, feid, reps=9999) + teststat(test); p(test); CI(test); + test = wildboottest(T, [1 zeros(1,size(predexog,2)-1)], [0]; resp, predexog, clustid, nbootclustvar=1, nerrclustvar=2, feid, reps=9999) + teststat(test); p(test); CI(test); + test = wildboottest(T, [1 zeros(1,size(predexog,2)-1)], [0]; resp, predexog, clustid, nbootclustvar=2, nerrclustvar=2, feid, reps=9999) + teststat(test); p(test); CI(test); + + + resp, predexog, clustid = rand(T, 20000,), rand(T, 20000, 12), Int32.(rand(1:12, 20000, 2)) + test = wildboottest(T, [0 1 zeros(1,size(predexog,2)-2)], [0]; resp, predexog, clustid=clustid[:,1], gridpoints=[10], reps=9999) + teststat(test); p(test); CI(test); + test = wildboottest(T, [0 1 zeros(1,size(predexog,2)-2)], [0]; resp, predexog, clustid=clustid[:,1], reps=9999, imposenull=false) + teststat(test); p(test); CI(test); + test = wildboottest(T, [0 1 zeros(1,size(predexog,2)-2)], [0]; resp, predexog, clustid=clustid[:,[2,1]], nbootclustvar=2, nerrclustvar=1, reps=9999) + teststat(test); p(test); CI(test); + test = wildboottest(T, [0 1 zeros(1,size(predexog,2)-2)], [0]; resp, predexog, clustid=clustid[:,[2,1]], nbootclustvar=2, nerrclustvar=1, reps=9999, imposenull=false) + teststat(test); p(test); CI(test); + test = wildboottest(T, [0 1 zeros(1,size(predexog,2)-2)], [0]; resp, predexog, clustid= [collect(1:size(resp,1)) clustid[:,2]], nbootclustvar=1, nerrclustvar=1, reps=9999) + teststat(test); p(test); CI(test); + test = wildboottest(T, [0 1 zeros(1,size(predexog,2)-2)], [0]; resp, predexog, clustid= [collect(1:size(resp,1)) clustid[:,2]], nbootclustvar=1, nerrclustvar=1, reps=9999, imposenull=false) + teststat(test); p(test); CI(test); + end +end + +using SnoopCompile +ttot, pcs = SnoopCompile.parcel(tinf); +SnoopCompile.write("/src", [pcs[end]]) \ No newline at end of file diff --git a/src/StrBoottest.jl b/src/StrBoottest.jl index d9861e9..0a1153d 100644 --- a/src/StrBoottest.jl +++ b/src/StrBoottest.jl @@ -1,4 +1,4 @@ -# Definition of StrBoottest "class" for holding intermediate results, with associated utilities and get functions +# Definition of StrBootTest "class" for holding intermediate results, with associated utilities and get functions "Auxilliary weight types: `rademacher`, `mammen`, `webb`, `normal`, `gamma`" @enum AuxWtType rademacher mammen webb normal gamma @@ -23,9 +23,35 @@ struct StrFE{T<:Real} wt::Vector{T} end +mutable struct StrEstimator{T<:AbstractFloat} + isDGP::Bool; LIML::Bool; Fuller::T; κ::T + R₁perp::Matrix{T}; Rpar::Matrix{T} -@inline vecconvert(T::DataType, X) = isa(X, AbstractArray) ? reshape(eltype(X)==T ? X : T.(X), size(X,1) ) : X -@inline matconvert(T::DataType, X) = isa(X, AbstractArray) ? reshape(eltype(X)==T ? X : T.(X), size(X,1), size(X,2)) : X + kZ::Int64 + y₁::Vector{T}; ü₁::Vector{T}; u⃛₁::Vector{T}; β̂::Vector{T}; β̂₀::Vector{T}; invXXXy₁par::Vector{T} + Yendog::Vector{Bool} + invZperpZperp::Symmetric{T,Matrix{T}}; XZ::Matrix{T}; PXZ::Matrix{T}; YPXY::Symmetric{T,Matrix{T}}; R₁invR₁R₁::Matrix{T} + RperpX::#=Uber=#Matrix{T}; RperpXperp::#=Uber=#Matrix{T}; RRpar::Matrix{T}; RparY::#=Uber=#Matrix{T}; RR₁invR₁R₁::Matrix{T} + ∂β̂∂r::Matrix{T}; YY::Symmetric{T,Matrix{T}}; AR::Matrix{T}; XAR::Matrix{T}; R₁invR₁R₁Y::Matrix{T}; invXXXZ::Matrix{T}; Ü₂::Matrix{T}; XinvXX::Matrix{T}; Rt₁::Vector{T} + invXX::Symmetric{T,Matrix{T}}; Y₂::Matrix{T}; X₂::Matrix{T}; invH::Symmetric{T,Matrix{T}} + y₁par::Vector{T}; Xy₁par::Vector{T} + A::Symmetric{T,Matrix{T}}; Z::Matrix{T}; Zperp::Matrix{T}; X₁::Matrix{T} + FillingT₀::Matrix{Matrix{T}} + WXAR::Matrix{T}; S⋂PXYZperp::Vector{Matrix{T}}; S⋂YX::Vector{Matrix{T}}; CT_XAR::Vector{Matrix{T}}; CT_FE⋂PY::Vector{Matrix{T}} + + # IV/GMM only + ZZ::Symmetric{T,Matrix{T}}; XY₂::Matrix{T}; XX::Symmetric{T,Matrix{T}}; H_2SLS::Symmetric{T,Matrix{T}}; V::Matrix{T}; ZY₂::Matrix{T}; X₂Y₂::Matrix{T}; X₁Y₂::Matrix{T}; ZR₁ZR₁::Symmetric{T,Matrix{T}}; X₂ZR₁::Matrix{T}; ZR₁Y₂::Matrix{T}; X₁ZR₁::Matrix{T} + ZZR₁::Matrix{T}; X₂y₁::Vector{T}; X₁y₁::Vector{T}; Zy₁::Vector{T}; ZXinvXXXZ::Matrix{T}; H_2SLSmZZ::Symmetric{T,Matrix{T}} + ZXinvXXXy₁par::Vector{T}; t₁Y::Vector{T} + Y₂y₁::Vector{T}; twoR₁Zy₁::Vector{T} + y₁y₁::T; y₁pary₁par::T + X₂y₁par::Vector{T}; X₁y₁par::Vector{T}; Zy₁par::Vector{T} + Y₂y₁par::Vector{T} + Rperp::Matrix{T}; ZR₁::Matrix{T} + kX::Int64 + + StrEstimator{T}(isDGP, LIML, Fuller, κ) where T<:AbstractFloat = new(isDGP, LIML, Fuller, κ, Matrix{T}(undef,0,0)) +end mutable struct StrBootTest{T<:AbstractFloat} R::Matrix{T}; r::Vector{T}; R₁::Matrix{T}; r₁::Vector{T} @@ -34,11 +60,11 @@ mutable struct StrBootTest{T<:AbstractFloat} LIML::Bool; Fuller::T; κ::T; ARubin::Bool B::Int64; auxtwtype::AuxWtType; rng::AbstractRNG; maxmatsize::Float16 ptype::PType; null::Bool; bootstrapt::Bool - ID::Matrix{Int64}; nbootclustvar::Int8; nerrclustvar::Int64; issorted::Bool; small::Bool + ID::Matrix{Int64}; nbootclustvar::Int8; nerrclustvar::Int8; issorted::Bool; small::Bool FEID::Vector{Int64}; FEdfadj::Bool level::T; rtol::T madjtype::MAdjType; NH₀::Int16 - ML::Bool; β̂::Vector{T}; A::Matrix{T}; sc::Matrix{T} + ML::Bool; β̂::Vector{T}; A::Symmetric{T,Matrix{T}}; sc::Matrix{T} willplot::Bool; gridmin::Vector{T}; gridmax::Vector{T}; gridpoints::Vector{Float32} q::Int16; twotailed::Bool; scorebs::Bool; robust::Bool @@ -52,14 +78,14 @@ mutable struct StrBootTest{T<:AbstractFloat} peak::NamedTuple{(:X, :p), Tuple{Vector{T}, T}} sqrt::Bool; Nobs::Int64; _Nobs::T; kZ::Int64; kY₂::Int64; kX₁::Int64; sumwt::T; NClustVar::Int8; haswt::Bool; REst::Bool; multiplier::T; smallsample::T - WREnonARubin::Bool; dof::Int64; dof_r::Int64; p::T; BootClust::Int8 + WREnonARubin::Bool; dof::Int64; dof_r::T; p::T; BootClust::Int8 purerobust::Bool; N✻::Int64; Nw::Int64; enumerate::Bool; interpolable::Bool; interpolate_u::Bool; kX₂::Int64; kX::Int64 _FEID::Vector{Int64}; AR::Matrix{T}; v::Matrix{T}; u✻::Matrix{T}; CT_WE::Matrix{T} infoBootData::Vector{UnitRange{Int64}}; infoBootAll::Vector{UnitRange{Int64}}; infoErrAll::Vector{UnitRange{Int64}} JN⋂N✻::Matrix{T}; statDenom::Matrix{T}; uXAR::Matrix{T}; SuwtXA::Matrix{T}; numer₀::Matrix{T}; β̂dev::Matrix{T}; δdenom_b::Matrix{T} _J⋂::Matrix{T}; YY✻_b::Matrix{T}; YPXY✻_b::Matrix{T}; numerw::Matrix{T}; Zyg::Vector{Matrix{T}}; numer_b::Vector{T} - distCDR::Matrix{T}; plotX::Tuple{Vararg{Vector{T}, N} where N}; plotY::Vector{T}; ClustShare::Vector{T}; WeightGrp::Vector{UnitRange{Int64}} + distCDR::Matrix{T}; plotX::Vector{Vector{T}}; plotY::Vector{T}; ClustShare::Vector{T}; WeightGrp::Vector{UnitRange{Int64}} numersum::Vector{T}; ü₀::Vector{T}; invFEwt::Vector{T} β̂s::Matrix{T}; As::Matrix{T} infoAllData::Vector{UnitRange{Int64}}; info⋂Data::Vector{UnitRange{Int64}}; IDAll::Matrix{T} @@ -78,9 +104,9 @@ mutable struct StrBootTest{T<:AbstractFloat} StrBootTest{T}(R, r, R₁, r₁, y₁, X₁, Y₂, X₂, wt, fweights, LIML, Fuller, κ, ARubin, B, auxtwtype, rng, maxmatsize, ptype, null, scorebs, bootstrapt, ID, nbootclustvar, nerrclustvar, issorted, robust, small, FEID, FEdfadj, level, rtol, madjtype, NH₀, ML, β̂, A, sc, willplot, gridmin, gridmax, gridpoints) where T<:Real = - new(matconvert(T,R), vecconvert(T,r), matconvert(T,R₁), vecconvert(T,r₁), vecconvert(T,y₁), matconvert(T,X₁), matconvert(T,Y₂), matconvert(T,X₂), vecconvert(T,wt), fweights, LIML || !iszero(Fuller), - Fuller, κ, ARubin, B, auxtwtype, rng, maxmatsize, ptype, null, bootstrapt, matconvert(Int64,ID), nbootclustvar, nerrclustvar, issorted, small, vecconvert(Int64,FEID), FEdfadj, level, rtol, madjtype, NH₀, ML, - vecconvert(T,β̂), matconvert(T,A), matconvert(T,sc), willplot, gridmin, gridmax, gridpoints, + new(R, r, R₁, r₁, y₁, X₁, Y₂, X₂, wt, fweights, LIML || !iszero(Fuller), + Fuller, κ, ARubin, B, auxtwtype, rng, maxmatsize, ptype, null, bootstrapt, ID, nbootclustvar, nerrclustvar, issorted, small, FEID, FEdfadj, level, rtol, madjtype, NH₀, ML, + β̂, A, sc, willplot, gridmin, gridmax, gridpoints, nrows(R), ptype==symmetric || ptype==equaltail, scorebs || iszero(B) || ML, @@ -92,7 +118,6 @@ mutable struct StrBootTest{T<:AbstractFloat} Vector{T}(undef,0), Vector{T}(undef,0), Matrix{T}(undef,0,0), Vector{T}(undef,0), Matrix{T}(undef,0,0), (X = Vector{T}(undef,0), p = T(NaN))) - end @@ -334,7 +359,7 @@ function getdf_r(o::StrBootTest) end function _getplot(o::StrBootTest) o.notplotted && plot!(o) - (X=o.plotX, p=o.plotY) + (X=Tuple(o.plotX), p=o.plotY) end function getpeak(o::StrBootTest) # x and y values of confidence curve peak (at least in OLS && ARubin) o.notplotted && plot!(o) diff --git a/src/WRE.jl b/src/WRE.jl index ecd6fb8..de90228 100644 --- a/src/WRE.jl +++ b/src/WRE.jl @@ -92,12 +92,12 @@ function Filling(o::StrBootTest{T}, ind1::Integer, β̂s::AbstractMatrix) where PXY✻ = reshape(o.Repl.PXZ[:,ind1], :, 1) # store as matrix to reduce compiler confusion o.Repl.Yendog[ind1+1] && (PXY✻ = PXY✻ .+ o.S✻UPX[ind1+1] * o.v) - dest = @panelsum(PXY✻ .* (o.Repl.y₁ .- o.S✻UMZperp[1] * o.v), o.wt, o.info⋂Data) + dest = @panelsum(PXY✻ .* (o.Repl.y₁ .- o.S✻UMZperp[1] * o.v), o.info⋂Data) for ind2 ∈ 1:o.Repl.kZ _β̂ = view(β̂s,ind2,:)' dest .-= @panelsum(PXY✻ .* (o.Repl.Yendog[ind2+1] ? view(o.Repl.Z,:,ind2) * _β̂ .- o.S✻UMZperp[ind2+1] * (o.v .* _β̂) : - (view(o.Repl.Z,:,ind2) * _β̂) ), o.wt, o.info⋂Data) + (view(o.Repl.Z,:,ind2) * _β̂) ), o.info⋂Data) end else # create pieces of each N x B matrix one at a time rather than whole thing at once dest = Matrix{T}(undef, o.clust[1].N, ncols(o.v)) # XXX preallocate this & turn Filling into Filling! ? @@ -110,11 +110,11 @@ function Filling(o::StrBootTest{T}, ind1::Integer, β̂s::AbstractMatrix) where o.Repl.Yendog[ind1+1] && (PXY✻ = PXY✻ .+ view(o.S✻UPX[ind1+1],i,:)'o.v) if iszero(ind2) - dest[i,:] = wtsum(o.wt, PXY✻ .* (o.Repl.y₁[i] .- view(o.S✻UMZperp[1],i,:))'o.v) + dest[i,:] = colsum(PXY✻ .* (o.Repl.y₁[i] .- view(o.S✻UMZperp[1],i,:))'o.v) elseif o.Repl.Yendog[ind2+1] - dest[i,:] .-= wtsum(o.wt, PXY✻ .* (o.Repl.Z[i,ind2] * _β̂ .- view(o.S✻UMZperp[ind2+1],i,:)'β̂v)) + dest[i,:] .-= colsum(PXY✻ .* (o.Repl.Z[i,ind2] * _β̂ .- view(o.S✻UMZperp[ind2+1],i,:)'β̂v)) else - dest[i,:] .-= wtsum(o.wt, PXY✻ .* (o.Repl.Z[i,ind2] * _β̂)) + dest[i,:] .-= colsum(PXY✻ .* (o.Repl.Z[i,ind2] * _β̂)) end end else @@ -124,9 +124,9 @@ function Filling(o::StrBootTest{T}, ind1::Integer, β̂s::AbstractMatrix) where reshape(o.Repl.PXZ[S,ind1], :, 1) if iszero(ind2) - dest[i,:] = wtsum(o.wt, PXY✻ .* (o.Repl.y₁[S] .- view(o.S✻UMZperp[1],S,:) * o.v)) + dest[i,:] = colsum(PXY✻ .* (o.Repl.y₁[S] .- view(o.S✻UMZperp[1],S,:) * o.v)) else - dest[i,:] .-= wtsum(o.wt, PXY✻ .* (o.Repl.Yendog[ind2+1] ? o.Repl.Z[S,ind2] * _β̂ .- view(o.S✻UMZperp[ind2+1],S,:) * β̂v : + dest[i,:] .-= colsum(PXY✻ .* (o.Repl.Yendog[ind2+1] ? o.Repl.Z[S,ind2] * _β̂ .- view(o.S✻UMZperp[ind2+1],S,:) * β̂v : o.Repl.Z[S,ind2] * _β̂ )) end end @@ -180,7 +180,7 @@ function Filling(o::StrBootTest{T}, ind1::Integer, β̂s::AbstractMatrix) where if o.Repl.Yendog[ind1+1] && o.Repl.Yendog[ind2+1] for i ∈ 1:o.clust[1].N S = o.info⋂Data[i] - colquadformminus!(dest, i, cross(view(o.S✻UPX[ind1+1],S,:), o.haswt ? o.wt[S] : zeros(T,0), view(o.S✻UMZperp[ind2+1],S,:)), o.v, β̂v) + colquadformminus!(dest, i, view(o.S✻UPX[ind1+1],S,:)'view(o.S✻UMZperp[ind2+1],S,:), o.v, β̂v) end end end @@ -190,12 +190,13 @@ end function PrepWRE!(o::StrBootTest{T}) where T - EstimateIVGMM!(o.DGP, o.null ? [o.r₁ ; o.r] : o.r₁) - MakeResidualsIVGMM!(o.DGP) + EstimateIV!(o.DGP, o, o.null ? [o.r₁ ; o.r] : o.r₁) + MakeResidualsIV!(o.DGP, o) Ü₂par = view(o.DGP.Ü₂ * o.Repl.RparY,:,:) for i ∈ 0:o.Repl.kZ # precompute various clusterwise sums - uwt = vHadw(i>0 ? view(Ü₂par,:,i) : view(o.DGP.u⃛₁,:), o.wt)::Union{Vector{T}, SubArray{T, 1}} + u = i>0 ? view(Ü₂par,:,i) : view(o.DGP.u⃛₁,:) + uwt = vHadw(u, o.wt)::Union{Vector{T}, SubArray{T, 1}} # S_✻(u .* X), S_✻(u .* Zperp) for residuals u for each endog var; store transposed o.S✻UX[i+1] = @panelsum2(o.Repl.X₁, o.Repl.X₂, uwt, o.infoBootData)' @@ -217,7 +218,7 @@ function PrepWRE!(o::StrBootTest{T}) where T if o.robust && o.bootstrapt if !o.granular # Within each bootstrap cluster, groupwise sum by all-error-cluster-intersections of u.*X and u.Zperp (and times invXX or invZperpZperp) for g ∈ 1:o.N✻ - o.SCT⋂uXinvXX[i+1,g] = @panelsum(o.Repl.XinvXX, uwt, o.infoCT⋂✻[g]) + o.SCT⋂uXinvXX[i+1,g] = @panelsum(o.Repl.XinvXX, u, o.infoCT⋂✻[g]) end end diff --git a/src/WildBootTests.jl b/src/WildBootTests.jl index 1cf9fbc..ed9d98f 100644 --- a/src/WildBootTests.jl +++ b/src/WildBootTests.jl @@ -5,8 +5,8 @@ export BoottestResult, wildboottest, AuxWtType, PType, MAdjType, DistStatType, using LinearAlgebra, Random, Distributions, SortingAlgorithms, LoopVectorization include("utilities.jl") -include("estimators.jl") include("StrBoottest.jl") +include("estimators.jl") include("init.jl") include("WRE.jl") include("nonWRE.jl") @@ -50,7 +50,7 @@ function NoNullUpdate!(o::StrBootTest{T} where T) if o.WREnonARubin o.numer[:,1] = o.R * o.DGP.Rpar * o.β̂s[1] - o.r elseif o.ARubin - EstimateARubin!(o.DGP, o.r) + EstimateARubin!(o.DGP, o, o.r) o.numer[:,1] = o.v_sd * @view o.DGP.β̂[o.kX₁+1:end,:] # coefficients on excluded instruments in ARubin OLS else o.numer[:,1] = o.v_sd * (o.R * (o.ML ? o.β̂ : o.M.β̂) - o.r) # Analytical Wald numerator; if imposing null then numer[:,1] already equals this. If not, then it's 0 before this @@ -80,5 +80,9 @@ function UpdateBootstrapcDenom!(o::StrBootTest{T} where T, w::Integer) nothing end -include("precompile.jl") +if Base.VERSION >= v"1.4.2" # source: https://timholy.github.io/SnoopCompile.jl/stable/snoopi_deep_parcel/#SnoopCompile.write + include("../src/precompile_WildBootTests.jl") + _precompile_() +end + end diff --git a/src/estimators.jl b/src/estimators.jl index 959cefe..49e7383 100644 --- a/src/estimators.jl +++ b/src/estimators.jl @@ -1,153 +1,122 @@ # Logically, wild bootstrap tests perform estimation at two stages, once as part of the bootstrap DGP, once in each bootstrap replication # The StrEstimator "class" and its three "children" hold the estimation logic for the OLS, Anderson-Rubin, and IV/GMM cases -mutable struct StrEstimator{T<:AbstractFloat} - parent - isDGP::Bool; LIML::Bool; Fuller::T; κ::T - R₁perp::Matrix{T}; Rpar::Matrix{T} - - kZ::Int64 - y₁::Vector{T}; ü₁::Vector{T}; u⃛₁::Vector{T}; β̂::Vector{T}; β̂₀::Vector{T}; invXXXy₁par::Vector{T} - Yendog::Vector{Bool} - invZperpZperp::Matrix{T}; XZ::Matrix{T}; PXZ::Matrix{T}; YPXY::Matrix{T}; R₁invR₁R₁::Matrix{T} - RperpX::UberMatrix{T}; RperpXperp::UberMatrix{T}; RRpar::Matrix{T}; RparY::UberMatrix{T}; RR₁invR₁R₁::Matrix{T} - ∂β̂∂r::Matrix{T}; YY::Matrix{T}; AR::Matrix{T}; XAR::Matrix{T}; R₁invR₁R₁Y::Matrix{T}; invXXXZ::Matrix{T}; Ü₂::Matrix{T}; XinvXX::Matrix{T}; Rt₁::Vector{T} - invXX::Matrix{T}; Y₂::Matrix{T}; X₂::Matrix{T}; invH - y₁par::Vector{T}; Xy₁par::Vector{T} - A::Matrix{T}; Z::Matrix{T}; Zperp::Matrix{T}; X₁::Matrix{T} - FillingT₀::Matrix{Matrix{T}} - WXAR::Matrix{T}; S⋂PXYZperp::Vector{Matrix{T}}; S⋂YX::Vector{Matrix{T}}; CT_XAR::Vector{Matrix{T}}; CT_FE⋂PY::Vector{Matrix{T}} - - # IV/GMM only - ZZ::Matrix{T}; XY₂::Matrix{T}; XX::Matrix{T}; H_2SLS::Matrix{T}; V::Matrix{T}; ZY₂::Matrix{T}; X₂Y₂::Matrix{T}; X₁Y₂::Matrix{T}; ZR₁ZR₁::Matrix{T}; X₂ZR₁::Matrix{T}; ZR₁Y₂::Matrix{T}; X₁ZR₁::Matrix{T} - ZZR₁::Matrix{T}; X₂y₁::Vector{T}; X₁y₁::Vector{T}; Zy₁::Vector{T}; ZXinvXXXZ::Matrix{T}; H_2SLSmZZ::Matrix{T} - ZXinvXXXy₁par::Vector{T}; t₁Y::Vector{T} - Y₂y₁::Vector{T}; twoR₁Zy₁::Vector{T} - y₁y₁::T; y₁pary₁par::T - X₂y₁par::Vector{T}; X₁y₁par::Vector{T}; Zy₁par::Vector{T} - Y₂y₁par::Vector{T} - Rperp::Matrix{T}; ZR₁::Matrix{T} - kX::Integer - - StrEstimator{T}(parent, isDGP, LIML, Fuller, κ) where T<:AbstractFloat = new(parent, isDGP, LIML, Fuller, κ, Matrix{T}(undef,0,0)) -end - function perp(A::AbstractMatrix) - F = eigensym(A*invsym(A'A)*A') + F = eigen(Symmetric(A*invsym(A'A)*A')) F.vectors[:, abs.(F.values) .< 1000eps(eltype(A))] end # R₁ is constraints. R is attack surface for null; only needed when using FWL for WRE # for DGP regression, R₁ is maintained constraints + null if imposed while R should have 0 nrows # for replication regressions R₁ is maintained constraints, R is null -function setR!(o::StrEstimator{T}, R₁::AbstractMatrix{T}, R::Union{UniformScaling{Bool},AbstractMatrix{T}}=Matrix{T}(undef,0,0)) where {T,E} +function setR!(o::StrEstimator{T}, parent::StrBootTest{T}, R₁::AbstractMatrix{T}, R::Union{UniformScaling{Bool},AbstractMatrix{T}}=Matrix{T}(undef,0,0)) where {T,E} if nrows(R₁) > 0 invR₁R₁ = invsym(R₁ * R₁') all(iszero.(diag(invR₁R₁))) && throw(ErrorException("Null hypothesis or model constraints are inconsistent or redundant.")) o.R₁invR₁R₁ = R₁'invR₁R₁ - F = eigensym(o.R₁invR₁R₁ * R₁) + F = eigen(Symmetric(o.R₁invR₁R₁ * R₁)) o.R₁perp = F.vectors[:, abs.(F.values) .< 1000*eps(T)] # eigenvectors orthogonal to span of R₁; foundation for parameterizing subspace compatible with constraints else - o.R₁invR₁R₁ = Matrix{T}(undef, o.parent.kZ, 0) # and R₁perp = I + o.R₁invR₁R₁ = Matrix{T}(undef, parent.kZ, 0) # and R₁perp = I end if !iszero(o.κ) - RR₁perp = Matrix([R ; zeros(T, o.parent.kY₂, o.parent.kX₁) I]) # nrows to prevent partialling out of endogenous regressors; convert sparse matrix produced by constructor to dense + RR₁perp = Matrix([R ; zeros(T, parent.kY₂, parent.kX₁) I]) # nrows to prevent partialling out of endogenous regressors; convert sparse matrix produced by constructor to dense length(R₁)>0 && (RR₁perp *= o.R₁perp) - F = eigensym(RR₁perp'pinv(RR₁perp * RR₁perp')*RR₁perp); val = abs.(F.values) .> 1000*eps(T) + F = eigen(Symmetric(RR₁perp'pinv(RR₁perp * RR₁perp')*RR₁perp)); val = abs.(F.values) .> 1000*eps(T) o.Rpar = F.vectors[:, val] # perp and par of RR₁perp - _RperpX = F.vectors[:, .!val] + o.RperpX = F.vectors[:, .!val] if nrows(R₁) > 0 # fold model constraint factors into Rpar, RperpX o.Rpar = o.R₁perp * o.Rpar - _RperpX = o.R₁perp * _RperpX + o.RperpX = o.R₁perp * o.RperpX end o.RRpar = R * o.Rpar - _RperpX = _RperpX[1:o.parent.kX₁,:] # Zperp=Z*RperpX; though formally a multiplier on Z, it will only extract exogenous components, in X₁, since all endogenous ones will be retained - o.RperpXperp = UberMatrix(T, perp(_RperpX)) - o.RperpX = UberMatrix(T, _RperpX) - o.RparY = UberMatrix(T, o.Rpar[o.parent.kX₁+1:end,:]) # part of Rpar that refers to Y₂ - o.R₁invR₁R₁Y = o.R₁invR₁R₁[o.parent.kX₁+1:end,:] + o.RperpX = o.RperpX[1:parent.kX₁,:] # Zperp=Z*RperpX; though formally a multiplier on Z, it will only extract exogenous components, in X₁, since all endogenous ones will be retained + o.RperpXperp = perp(o.RperpX) # UberMatrix(T, perp(_RperpX)) + # o.RperpX = UberMatrix(T, _RperpX) + o.RparY = o.Rpar[parent.kX₁+1:end,:] # UberMatrix(T, o.Rpar[parent.kX₁+1:end,:]) # part of Rpar that refers to Y₂ + o.R₁invR₁R₁Y = o.R₁invR₁R₁[parent.kX₁+1:end,:] o.RR₁invR₁R₁ = R * o.R₁invR₁R₁ end nothing end # stuff that can be done before r set, and depends only on exogenous variables, which are fixed throughout all bootstrap methods -function InitVarsOLS!(o::StrEstimator{T}, Rperp::AbstractMatrix{T}) where T # Rperp is for replication regression--no null imposed - o.y₁par = o.parent.y₁ - H = symcross(o.parent.X₁, o.parent.wt) - o.invH = inv(H) +function InitVarsOLS!(o::StrEstimator{T}, parent::StrBootTest{T}, Rperp::AbstractMatrix{T}) where T # Rperp is for replication regression--no null imposed + o.y₁par = parent.y₁ + H = symcross(parent.X₁, parent.wt) + o.invH = Symmetric(inv(H)) R₁AR₁ = iszero(nrows(o.R₁perp)) ? o.invH : Symmetric(o.R₁perp * invsym(o.R₁perp'H*o.R₁perp) * o.R₁perp') # for DGP regression - o.β̂₀ = R₁AR₁ * crossvec(o.parent.X₁, o.parent.wt, o.y₁par) + o.β̂₀ = R₁AR₁ * crossvec(parent.X₁, parent.wt, o.y₁par) o.∂β̂∂r = R₁AR₁ * H * o.R₁invR₁R₁ - o.R₁invR₁R₁ - o.A = iszero(nrows(Rperp)) ? o.invH : Rperp * invsym(Rperp'H*Rperp) * Rperp' # for replication regression - o.AR = o.A * o.parent.R' - (o.parent.scorebs || o.parent.robust) && (o.XAR = o.parent.X₁ * o.AR) + o.A = iszero(nrows(Rperp)) ? o.invH : Symmetric(Rperp * invsym(Rperp'H*Rperp) * Rperp') # for replication regression + o.AR = o.A * parent.R' + (parent.scorebs || parent.robust) && (o.XAR = parent.X₁ * o.AR) nothing end -function InitVarsARubin!(o::StrEstimator{T}) where T - X₂X₁ = cross(o.parent.X₂, o.parent.wt, o.parent.X₁) - H = Symmetric([symcross(o.parent.X₁, o.parent.wt) X₂X₁' ; X₂X₁ symcross(o.parent.X₂, o.parent.wt)]) +function InitVarsARubin!(o::StrEstimator{T}, parent::StrBootTest{T}) where T + X₂X₁ = cross(parent.X₂, parent.wt, parent.X₁) + H = Symmetric([symcross(parent.X₁, parent.wt) X₂X₁' ; X₂X₁ symcross(parent.X₂, parent.wt)]) o.A = inv(H) - o.AR = o.A * o.parent.R' - (o.parent.scorebs || o.parent.robust) && (o.XAR = X₁₂B(o.parent.X₁, o.parent.X₂, o.AR)) + o.AR = o.A * parent.R' + (parent.scorebs || parent.robust) && (o.XAR = X₁₂B(parent.X₁, parent.X₂, o.AR)) - R₁AR₁ = iszero(nrows(o.R₁perp)) ? o.A : o.R₁perp * invsym(o.R₁perp'H*o.R₁perp) * o.R₁perp' - o.β̂₀ = R₁AR₁ * [crossvec(o.parent.X₁, o.parent.wt, o.parent.y₁) ; crossvec(o.parent.X₂, o.parent.wt, o.parent.y₁)] - o.∂β̂∂r = R₁AR₁ * [cross(o.parent.X₁, o.parent.wt, o.parent.Y₂) ; cross(o.parent.X₂, o.parent.wt, o.parent.Y₂)] + R₁AR₁ = iszero(nrows(o.R₁perp)) ? o.A : Symmetric(o.R₁perp * invsym(o.R₁perp'H*o.R₁perp) * o.R₁perp') + o.β̂₀ = R₁AR₁ * [crossvec(parent.X₁, parent.wt, parent.y₁) ; crossvec(parent.X₂, parent.wt, parent.y₁)] + o.∂β̂∂r = R₁AR₁ * [cross(parent.X₁, parent.wt, parent.Y₂) ; cross(parent.X₂, parent.wt, parent.Y₂)] nothing end -function InitVarsIVGMM!(o::StrEstimator{T}, Rperp::AbstractMatrix{T}...) where T +function InitVarsIV!(o::StrEstimator{T}, parent::StrBootTest{T}, Rperp::AbstractMatrix{T}...) where T !isempty(Rperp) && (o.Rperp = Rperp[1]) - o.Zperp = o.parent.X₁ * o.RperpX - o.invZperpZperp = iszero(length(o.Zperp)) ? Matrix{T}(undef,0,0) : inv(symcross(o.Zperp, o.parent.wt)) - - o.X₁ = o.parent.X₁ * o.RperpXperp; o.X₁ .-= o.Zperp * (o.invZperpZperp * cross(o.Zperp, o.parent.wt, o.X₁)) # FWL-process X₁ - o.X₂ = o.Zperp * (o.invZperpZperp * cross(o.Zperp, o.parent.wt, o.parent.X₂)); o.X₂ .= o.parent.X₂ .- o.X₂ # FWL-process X₂ - X₂X₁ = cross(o.X₂, o.parent.wt, o.X₁) - o.XX = Symmetric([symcross(o.X₁, o.parent.wt) X₂X₁' ; X₂X₁ symcross(o.X₂, o.parent.wt)]) + o.Zperp = parent.X₁ * o.RperpX + o.invZperpZperp = iszero(length(o.Zperp)) ? Symmetric(Matrix{T}(undef,0,0)) : inv(symcross(o.Zperp, parent.wt)) + + o.X₁ = parent.X₁ * o.RperpXperp; o.X₁ .-= o.Zperp * (o.invZperpZperp * cross(o.Zperp, parent.wt, o.X₁)) # FWL-process X₁ + o.X₂ = o.Zperp * (o.invZperpZperp * cross(o.Zperp, parent.wt, parent.X₂)); o.X₂ .= parent.X₂ .- o.X₂ # FWL-process X₂ + X₂X₁ = cross(o.X₂, parent.wt, o.X₁) + o.XX = Symmetric([symcross(o.X₁, parent.wt) X₂X₁' ; X₂X₁ symcross(o.X₂, parent.wt)]) o.kX = ncols(o.XX) o.invXX = invsym(o.XX) - o.Z = X₁₂B(o.parent.X₁, o.parent.Y₂, o.Rpar ) # Zpar - o.ZR₁ = X₁₂B(o.parent.X₁, o.parent.Y₂, o.R₁invR₁R₁) + o.Z = X₁₂B(parent.X₁, parent.Y₂, o.Rpar ) # Z∥ + o.ZR₁ = X₁₂B(parent.X₁, parent.Y₂, o.R₁invR₁R₁) - o.Z .-= o.Zperp * (o.invZperpZperp * cross(o.Zperp, o.parent.wt, o.Z)) # partialling out - o.ZR₁ .-= o.Zperp * (o.invZperpZperp * cross(o.Zperp, o.parent.wt, o.ZR₁)) - o.Y₂ = o.parent.Y₂ - o.Zperp * (o.invZperpZperp * cross(o.Zperp, o.parent.wt, o.parent.Y₂)) - o.y₁ = o.parent.y₁ - o.Zperp * o.invZperpZperp * (crossvec(o.Zperp, o.parent.wt, o.parent.y₁)) + o.Z .-= o.Zperp * (o.invZperpZperp * cross(o.Zperp, parent.wt, o.Z)) # partialling out + o.ZR₁ .-= o.Zperp * (o.invZperpZperp * cross(o.Zperp, parent.wt, o.ZR₁)) + o.Y₂ = parent.Y₂ - o.Zperp * (o.invZperpZperp * cross(o.Zperp, parent.wt, parent.Y₂)) + o.y₁ = parent.y₁ - o.Zperp * o.invZperpZperp * (crossvec(o.Zperp, parent.wt, parent.y₁)) - o.X₁Y₂ = cross(o.X₁, o.parent.wt, o.Y₂) - o.X₂Y₂ = cross(o.X₂, o.parent.wt, o.Y₂) + o.X₁Y₂ = cross(o.X₁, parent.wt, o.Y₂) + o.X₂Y₂ = cross(o.X₂, parent.wt, o.Y₂) o.XY₂ = [o.X₁Y₂ ; o.X₂Y₂] - o.Y₂y₁ = crossvec(o.Y₂, o.parent.wt, o.y₁) - o.X₂y₁ = crossvec(o.X₂, o.parent.wt, o.y₁) - o.X₁y₁ = crossvec(o.X₁, o.parent.wt, o.y₁) - o.y₁y₁ = cross(o.y₁ , o.parent.wt, o.y₁)[1] - o.Zy₁ = crossvec(o.Z, o.parent.wt, o.y₁) - o.XZ = [cross(o.X₁, o.parent.wt, o.Z) ; - cross(o.X₂, o.parent.wt, o.Z)] - o.ZY₂ = cross(o.Z, o.parent.wt, o.Y₂) - o.ZZ = symcross(o.Z, o.parent.wt) + o.Y₂y₁ = crossvec(o.Y₂, parent.wt, o.y₁) + o.X₂y₁ = crossvec(o.X₂, parent.wt, o.y₁) + o.X₁y₁ = crossvec(o.X₁, parent.wt, o.y₁) + o.y₁y₁ = cross(o.y₁ , parent.wt, o.y₁)[1] + o.Zy₁ = crossvec(o.Z, parent.wt, o.y₁) + o.XZ = [cross(o.X₁, parent.wt, o.Z) ; + cross(o.X₂, parent.wt, o.Z)] + o.ZY₂ = cross(o.Z, parent.wt, o.Y₂) + o.ZZ = symcross(o.Z, parent.wt) o.invXXXZ = o.invXX * o.XZ - o.ZXinvXXXZ = o.XZ'o.invXXXZ + o.ZXinvXXXZ = o.XZ'o.invXXXZ # this is symmetric but converting to Symmetric() only hampers type inference in the one place it's used if ncols(o.R₁invR₁R₁)>0 - o.X₂ZR₁ = cross(o.X₂, o.parent.wt, o.ZR₁) - o.X₁ZR₁ = cross(o.X₁, o.parent.wt, o.ZR₁) - o.ZZR₁ = cross(o.Z , o.parent.wt, o.ZR₁) - o.twoR₁Zy₁ = 2crossvec(o.ZR₁, o.parent.wt, o.y₁) - o.ZR₁ZR₁ = symcross(o.ZR₁, o.parent.wt) - o.ZR₁Y₂ = cross(o.ZR₁, o.parent.wt, o.Y₂) + o.X₂ZR₁ = cross(o.X₂, parent.wt, o.ZR₁) + o.X₁ZR₁ = cross(o.X₁, parent.wt, o.ZR₁) + o.ZZR₁ = cross(o.Z , parent.wt, o.ZR₁) + o.twoR₁Zy₁ = 2crossvec(o.ZR₁, parent.wt, o.y₁) + o.ZR₁ZR₁ = symcross(o.ZR₁, parent.wt) + o.ZR₁Y₂ = cross(o.ZR₁, parent.wt, o.Y₂) else o.Y₂y₁par = o.Y₂y₁ o.X₂y₁par = o.X₂y₁ @@ -158,40 +127,47 @@ function InitVarsIVGMM!(o::StrEstimator{T}, Rperp::AbstractMatrix{T}...) where T o.y₁par = o.y₁ end - o.V = o.invXX * o.XZ # in 2SLS case, StrEstimator is (V' XZ)^-1 * (V'Xy₁). Also used in k-class and LIML robust VCV by Stata convention + o.V = o.invXX * o.XZ # in 2SLS case, StrEstimator is (V' XZ)^-1 * (V'Xy₁). Also used in k-class and LIML robust VCV by Stata convention o.H_2SLS = Symmetric(o.V'o.XZ) # Hessian (o.LIML || o.κ ≠ 1) && (o.H_2SLSmZZ = o.H_2SLS - o.ZZ) if o.isDGP - !o.LIML && MakeH!(o, !isempty(Rperp)) # DGP is LIML except possibly when getting confidence peak for A-R plot; but LIML=0 when exactly id'd, for then κ=1 always and Hessian doesn't depend on r₁ and can be computed now + !o.LIML && MakeH!(o, parent, !isempty(Rperp)) # DGP is LIML except possibly when getting confidence peak for A-R plot; but LIML=0 when exactly id'd, for then κ=1 always and Hessian doesn't depend on r₁ and can be computed now else o.kZ = ncols(o.Rpar) - o.Yendog = [true; isa(o.RparY, UniformScaling{Bool}) ? fill(true, o.kZ) : vec(colsum(o.RparY.≠0)).>0] # columns of Y = [y₁par Zpar] that are endogenous (normally all) + o.Yendog = [true; #=o.RparY.type==identity ? fill(true, o.kZ) :=# mapreduce(v->v.≠0, .|, eachcol(o.RparY))] # columns of Y = [y₁par Zpar] that are endogenous (normally all) - if o.parent.robust && o.parent.bootstrapt # for WRE replication regression, prepare for CRVE + if parent.robust && parent.bootstrapt # for WRE replication regression, prepare for CRVE o.S⋂YX = Vector{Matrix{T}}(undef, o.kZ+1) o.S⋂PXYZperp = Vector{Matrix{T}}(undef, o.kZ+1) - o.XinvXX = X₁₂B(o.X₁, o.X₂, o.invXX) - - o.PXZ = X₁₂B(o.X₁, o.X₂, o.invXXXZ) + + o.XinvXX = X₁₂B(o.X₁, o.X₂, o.invXX); o.PXZ = X₁₂B(o.X₁, o.X₂, o.invXXXZ) + if parent.haswt + o.PXZ .*= parent.wt + o.XinvXX .*= parent.wt + end o.FillingT₀ = Matrix{Matrix{T}}(undef, o.kZ+1, o.kZ+1) # fixed component of groupwise term in sandwich filling - o.parent.NFE>0 && + parent.NFE>0 && (o.CT_FE⋂PY = Vector{Matrix{T}}(undef, o.kZ+1)) for i ∈ 1:o.kZ - uwt = vHadw(view(o.PXZ,:,i), o.parent.wt) - o.parent.NFE>0 && - (o.CT_FE⋂PY[i+1] = crosstabFEt(o.parent, uwt, o.parent.info⋂Data) .* o.parent.invFEwt) - tmp = @panelsum(o.Z, uwt, o.parent.info⋂Data) + u = view(o.PXZ,:,i) + parent.NFE>0 && + (o.CT_FE⋂PY[i+1] = crosstabFEt(parent, u, parent.info⋂Data) .* parent.invFEwt) + tmp = @panelsum(o.Z, u, parent.info⋂Data) for j ∈ 1:o.kZ o.FillingT₀[i+1,j+1] = reshape(view(tmp,:,j),:,1) end end - for i ∈ 1:o.kZ # precompute various clusterwise sums - o.S⋂PXYZperp[i+1] = @panelsum(o.Zperp, vHadw(view(o.PXZ,:,i), o.parent.wt), o.parent.info⋂Data) # S⋂(P_(MZperpX) * Z .* Zperp) - !o.parent.granular && - (o.S⋂YX[i+1] = @panelsum2(o.X₁, o.X₂, vHadw(view(o.Z,:,i), o.parent.wt), o.parent.info⋂Data)) # S⋂(M_Zperp[Z or y₁] .* P_(MZperpX)]) + o.S⋂PXYZperp[i+1] = @panelsum(o.Zperp, view(o.PXZ,:,i), parent.info⋂Data) # S⋂(P_(MZperpX) * Z .* Zperp) + if !parent.granular + if parent.haswt + (o.S⋂YX[i+1] = @panelsum2(o.X₁, o.X₂, view(o.Z,:,i) .* parent.wt, parent.info⋂Data)) # S⋂(M_Zperp[Z or y₁] .* P_(MZperpX)]) + else + (o.S⋂YX[i+1] = @panelsum2(o.X₁, o.X₂, view(o.Z,:,i), parent.info⋂Data)) # S⋂(M_Zperp[Z or y₁] .* P_(MZperpX)]) + end + end end end end @@ -208,24 +184,24 @@ function EstimateOLS!(o::StrEstimator{T} where T, r₁::AbstractVector) nothing end -function EstimateARubin!(o::StrEstimator{T} where T, r₁::AbstractVector) +function EstimateARubin!(o::StrEstimator{T}, parent::StrBootTest{T}, r₁::AbstractVector) where T o.β̂ = o.β̂₀ - o.∂β̂∂r * r₁ - o.y₁par = o.parent.y₁ - o.parent.Y₂ * r₁ + o.y₁par = parent.y₁ - parent.Y₂ * r₁ nothing end -function MakeH!(o::StrEstimator{T} where T, makeXAR::Bool=false) +function MakeH!(o::StrEstimator{T}, parent::StrBootTest{T}, makeXAR::Bool=false) where T H = isone(o.κ) ? o.H_2SLS : o.ZZ + o.κ * o.H_2SLSmZZ o.invH = invsym(H) if makeXAR # for replication regression in score bootstrap of IV/GMM - o.A = ncols(o.Rperp)>0 ? o.Rperp * invsym(o.Rperp'H*o.Rperp) * o.Rperp' : o.invH - o.AR = o.A * (o.Rpar'o.parent.R') + o.A = ncols(o.Rperp)>0 ? Symmetric(o.Rperp * invsym(o.Rperp'H*o.Rperp) * o.Rperp') : o.invH + o.AR = o.A * (o.Rpar'parent.R') o.XAR = X₁₂B(o.X₁, o.X₂, o.V * o.AR) end nothing end -function EstimateIVGMM!(o::StrEstimator{T} where T, r₁::AbstractVector) +function EstimateIV!(o::StrEstimator{T}, parent::StrBootTest{T}, r₁::AbstractVector) where T if ncols(o.R₁invR₁R₁)>0 o.y₁pary₁par = o.y₁y₁ - (o.twoR₁Zy₁'r₁)[1] + r₁'o.ZR₁ZR₁ * r₁ o.y₁par = o.y₁ - o.ZR₁ * r₁ @@ -238,44 +214,43 @@ function EstimateIVGMM!(o::StrEstimator{T} where T, r₁::AbstractVector) o.invXXXy₁par = o.invXX * o.Xy₁par o.ZXinvXXXy₁par = o.XZ'o.invXXXy₁par - o.YY = [o.y₁pary₁par o.Zy₁par' ; o.Zy₁par o.ZZ] - o.YPXY = [o.invXXXy₁par'o.Xy₁par o.ZXinvXXXy₁par' ; o.ZXinvXXXy₁par o.ZXinvXXXZ] + o.YY = Symmetric([[o.y₁pary₁par ] o.Zy₁par' ; o.Zy₁par Matrix(o.ZZ)]) + o.YPXY = Symmetric([[o.invXXXy₁par'o.Xy₁par] o.ZXinvXXXy₁par' ; o.ZXinvXXXy₁par o.ZXinvXXXZ]) if o.isDGP if o.LIML - o.κ = 1/(1 - eigvals(invsym(o.YY) * o.YPXY)[1]) # like Fast & Wild (81), but more stable, at least in Mata - !iszero(o.Fuller) && (o.κ -= o.Fuller / (o.parent._Nobs - o.parent.kX)) - MakeH!(o) + o.κ = 1/(1 - real(eigvals(invsym(o.YY) * o.YPXY)[1])) # like Fast & Wild (81), but more stable, at least in Mata + !iszero(o.Fuller) && (o.κ -= o.Fuller / (parent._Nobs - parent.kX)) + MakeH!(o, parent) end o.β̂ = o.invH * (isone(o.κ) ? o.ZXinvXXXy₁par : o.κ * (o.ZXinvXXXy₁par - o.Zy₁par) + o.Zy₁par) o.t₁Y = o.R₁invR₁R₁Y * r₁ - elseif o.parent.WREnonARubin # if not score bootstrap of IV/GMM + elseif parent.WREnonARubin # if not score bootstrap of IV/GMM o.Rt₁ = o.RR₁invR₁R₁ * r₁ - if o.parent.robust && o.parent.bootstrapt # prepare WRE replication regressions - uwt = vHadw(o.y₁par, o.parent.wt) - tmp = @panelsum(o.PXZ, uwt, o.parent.info⋂Data) + if parent.robust && parent.bootstrapt # prepare WRE replication regressions + tmp = @panelsum(o.PXZ, o.y₁par, parent.info⋂Data) for i ∈ 1:o.kZ o.FillingT₀[i+1,1] = reshape(view(tmp,:,i),:,1) end - !o.parent.granular && - (o.S⋂YX[1] = @panelsum2(o.X₁, o.X₂, uwt, o.parent.info⋂Data)) # S⋂(M_Zperp*y₁ .* P_(MZperpX)]) + !parent.granular && + (o.S⋂YX[1] = @panelsum2(o.X₁, o.X₂, vHadw(o.y₁par, parent.wt), parent.info⋂Data)) # S⋂(M_Zperp*y₁ .* P_(MZperpX)]) end end nothing end -@inline function MakeResidualsOLSARubin!(o::StrEstimator{T} where T) - o.ü₁ = o.y₁par - X₁₂B(o.parent.X₁, o.parent.X₂, o.β̂) +@inline function MakeResidualsOLSARubin!(o::StrEstimator{T}, parent::StrBootTest{T}) where T + o.ü₁ = o.y₁par - X₁₂B(parent.X₁, parent.X₂, o.β̂) nothing end -function MakeResidualsIVGMM!(o::StrEstimator{T} where T) +function MakeResidualsIV!(o::StrEstimator{T}, parent::StrBootTest{T}) where T o.ü₁ = o.y₁par - o.Z * o.β̂ - if !o.parent.scorebs + if !parent.scorebs _β = [1 ; -o.β̂] uu = _β'o.YY * _β @@ -295,13 +270,13 @@ end # non-WRE stuff that only depends on r in A-R case, for test stat denominators in replication regressions # since the non-AR OLS code never creates an object for replication regresssions, in that case this is called on the DGP regression object # depends on results of Estimate() only when doing OLS-style bootstrap on an overidentified IV/GMM regression--score bootstrap or A-R. Then κ from DGP LIML affects Hessian, H. -function InitTestDenoms!(o::StrEstimator) - if o.parent.bootstrapt && (o.parent.scorebs || o.parent.robust) - (o.parent.granular || o.parent.purerobust) && (o.WXAR = vHadw(o.XAR, o.parent.wt)) +function InitTestDenoms!(o::StrEstimator{T}, parent::StrBootTest{T}) where T + if parent.bootstrapt && (parent.scorebs || parent.robust) + (parent.granular || parent.purerobust) && (o.WXAR = vHadw(o.XAR, parent.wt)) - if o.parent.robust && o.parent.NFE>0 && !(o.parent.FEboot || o.parent.scorebs) && o.parent.granular < o.parent.NErrClustCombs # make first factor of second term of (64) for c=⋂ (c=1) - !isdefined(o, :WXAR) && (o.WXAR = vHadw(o.XAR, o.parent.wt)) - o.CT_XAR = [crosstabFEt(o.parent, view(o.WXAR,:,d), o.parent.info⋂Data) for d ∈ 1:o.parent.dof] + if parent.robust && parent.NFE>0 && !(parent.FEboot || parent.scorebs) && parent.granular < parent.NErrClustCombs # make first factor of second term of (64) for c=⋂ (c=1) + !isdefined(o, :WXAR) && (o.WXAR = vHadw(o.XAR, parent.wt)) + o.CT_XAR = [crosstabFEt(parent, view(o.WXAR,:,d), parent.info⋂Data) for d ∈ 1:parent.dof] end end nothing diff --git a/src/init.jl b/src/init.jl index 28404fd..3e4dbb3 100644 --- a/src/init.jl +++ b/src/init.jl @@ -23,8 +23,8 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea iszero(o.B) && (o.scorebs = true) o.haswt = !iszero(nrows(o.wt)) - o.sumwt = o.haswt ? sum(o.wt) : 1 - o._Nobs = o.haswt && o.fweights ? o.sumwt : o.Nobs + o.sumwt = o.haswt ? sum(o.wt) : one(T) + o._Nobs = o.haswt && o.fweights ? o.sumwt : T(o.Nobs) if !(iszero(o.NClustVar) || o.issorted) o.subcluster = o.NClustVar - o.nerrclustvar @@ -53,7 +53,7 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea if o.bootstrapt if o.NClustVar>0 - minN = Inf; sumN = 0 + minN = T(Inf) combs = [x & 2^y > 0 for x in 2^o.nerrclustvar-1:-1:1, y in o.nerrclustvar-1:-1:0] # represent all error clustering combinations. First is intersection of all error clustering vars o.clust = Vector{StrClust{T}}(undef, nrows(combs)) # leave out no-cluster combination @@ -81,12 +81,12 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea else o.info⋂Data = panelsetup(o.ID, o.subcluster+1:o.NClustVar) end - ID⋂ = length(o.info⋂Data)==o.Nobs ? o.ID : @views o.ID[first.(o.info⋂Data),:] # version of ID matrix with one row for each all-error-cluster-var intersection instead of 1 row for each obs; gets resorted - o.IDAll = Nall==o.Nobs ? o.ID : @view o.ID[first.(o.infoAllData),:] # version of ID matrix with one row for each all-bootstrap && error cluster-var intersection instead of 1 row for each obs + ID⋂ = length(o.info⋂Data)==o.Nobs ? o.ID : o.ID[first.(o.info⋂Data),:] # version of ID matrix with one row for each all-error-cluster-var intersection instead of 1 row for each obs; gets resorted + o.IDAll = Nall==o.Nobs ? o.ID : o.ID[first.(o.infoAllData),:] # version of ID matrix with one row for each all-bootstrap && error cluster-var intersection instead of 1 row for each obs else o.info⋂Data = o.infoAllData # info for intersections of error clustering wrt data o.WREnonARubin && !o.granular && (ID⋂Data = IDAllData) - o.IDAll = ID⋂ = nrows(o.info⋂Data)==o.Nobs ? o.ID : @views o.ID[first.(o.info⋂Data),:] # version of ID matrix with one row for each all-error-cluster-var intersection instead of 1 row for each obs; gets resorted + o.IDAll = ID⋂ = nrows(o.info⋂Data)==o.Nobs ? o.ID : o.ID[first.(o.info⋂Data),:] # version of ID matrix with one row for each all-error-cluster-var intersection instead of 1 row for each obs; gets resorted end o.BootClust = 2^(o.NClustVar - o.nbootclustvar) # location of bootstrap clustering within list of cluster combinations @@ -102,26 +102,23 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea N = Nall else order = _sortperm(@view ID⋂[:,ClustCols]) - ID⋂ = @view ID⋂[order, :] - info = panelsetup(ID⋂, ClustCols) + info = panelsetup(view(ID⋂,order,:), ClustCols) N = nrows(info) end else - if any(combs[c, min(findall(view(combs,c,:) .≠ view(combs,c-1,:))...):end]) # if this sort ordering same as last to some point and missing thereafter, no need to re-sort + if any(combs[c, minimum(findall(combs[c,:] .≠ combs[c-1,:])):end]) # if this sort ordering same as last to some point and missing thereafter, no need to re-sort order = _sortperm(@view ID⋂[:,ClustCols]) - ID⋂ = @view ID⋂[order,:] + info = panelsetup(view(ID⋂,order,:), ClustCols) else order = Vector{Int64}(undef,0) + info = panelsetup(ID⋂, ClustCols) end - info = panelsetup(ID⋂, ClustCols) N = nrows(info) end - sumN += N - - if o.small + if o.small multiplier = T(N / (N-1)) - N < minN && (minN = N) + minN = min(minN,N) else multiplier = one(T) end @@ -129,14 +126,13 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea end (o.scorebs || !o.WREnonARubin) && - (o.ClustShare = o.haswt ? @panelsum(o.wt, o.info⋂Data)/o.sumwt : length.(o.info⋂Data)./o.Nobs) # share of observations by group + (o.ClustShare = o.haswt ? @panelsum(o.wt, o.info⋂Data)/o.sumwt : T.(length.(o.info⋂Data)./o.Nobs)) # share of observations by group else # if no clustering, cast "robust" as clustering by observation - o.clust = StrClust{T}(Nobs, small ? _Nobs / (_Nobs - 1) : 1, true, Vector{Int64}(undef,0), Vector{UnitRange{Int64}}(undef,0)) - sumN = o.Nobs - o.NErrClustCombs = 1 + o.clust = StrClust{T}(Nobs, small ? o._Nobs / (o._Nobs - one(T)) : one(T), true, Vector{Int64}(undef,0), Vector{UnitRange{Int64}}(undef,0)) + o.NErrClustCombs = one(Int16) (o.scorebs || !o.WREnonARubin) && - (o.ClustShare = o.haswt ? o.wt/o.sumwt : 1/o._Nobs) + (o.ClustShare = o.haswt ? o.wt/o.sumwt : fill(one(T)/o._Nobs,o._Nobs)) end o.purerobust = o.robust && !o.scorebs && iszero(o.subcluster) && o.N✻==o.Nobs # do we ever error-cluster *and* bootstrap-cluster by individual? @@ -164,7 +160,7 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea end end else - minN = nrows(o.infoBootData) + minN = T(nrows(o.infoBootData)) end if isdefined(o, :FEID) && nrows(o.FEID)>0 @@ -180,12 +176,12 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea tmp = o.wt[is] wt = tmp / (sumFEwt = sum(tmp)) else - sumFEwt = j - i + sumFEwt = T(j - i) wt = fill(1/sumFEwt, j-i) end o.FEs[i_FE] = StrFE{T}(is, wt) if (o.B>0 && o.robust && o.granular < o.nerrclustvar) || (o.WREnonARubin && o.robust && o.granular && o.bootstrapt) - o.invFEwt[i_FE] = 1 / sumFEwt + o.invFEwt[i_FE] = one(T) / sumFEwt end j = i @@ -203,7 +199,7 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea tmp = o.wt[is] wt = tmp / (sumFEwt = sum(tmp)) else - sumFEwt = j + sumFEwt = T(j) wt = fill(1/sumFEwt, j) end o.FEs[i_FE] = StrFE{T}(is, wt) @@ -211,7 +207,7 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea (o.invFEwt[i_FE] = 1 / sumFEwt) o.NFE = i_FE resize!(o.invFEwt, o.NFE) - resize!(o.FEs, o.NFE) + resize!(o.FEs , o.NFE) if o.FEboot # are all of this FE's obs in same bootstrapping cluster? tmp = o.ID[is, 1:o.nbootclustvar] o.FEboot = all(tmp .== @view tmp[1,:]) @@ -238,13 +234,13 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea o.enumerate = o.B>0 && o.auxtwtype==rademacher && o.N✻*log(2) < log(o.B)+1e-6 # generate full Rademacher set? o.enumerate && (o.maxmatsize = 0) - o.Nw = iszero(o.maxmatsize) ? 1 : ceil((o.B+1) * Float64(max(nrows(o.IDBootData), length(o.IDBootAll), o.N✻) * sizeof(T)) / o.maxmatsize / 1073741824) # 1073741824 = giga(byte) + o.Nw = iszero(o.maxmatsize) ? one(Int64) : ceil(Int64, (o.B+1) * Float64(max(nrows(o.IDBootData), length(o.IDBootAll), o.N✻) * sizeof(T)) / o.maxmatsize / 1073741824) # 1073741824 = giga(byte) if isone(o.Nw) MakeWildWeights!(o, o.B, first=true) # make all wild weights, once o.enumerate && (o.B = ncols(o.v) - 1) # replications reduced to 2^G o.WeightGrp = [1:ncols(o.v)] else - o.seed = rand(o.rng,UInt64) + o.seed = rand(o.rng, UInt64) _B = ceil(Int64, (o.B+1) / o.Nw) o.Nw = ceil(Int64, (o.B+1) / _B) o.WeightGrp = [(i-1)*_B+1:i*_B for i ∈ 1:o.Nw] @@ -256,48 +252,48 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea else if o.ARubin o.R = hcat(zeros(o.kX₂,o.kX₁), Matrix(I(o.kX₂))) # attack surface is all endog vars - o.R₁ = o.kX₁>0 && nrows(o.R₁)>0 ? hcat(o.R₁[:,1:kX₁], zeros(nrows(o.R₁),o.kX₂)) : zeros(0, o.kX) # and convert model constraints from referring to X₁, Y₂ to X₁, X₂ + o.R₁ = o.kX₁>0 && nrows(o.R₁)>0 ? hcat(o.R₁[:,1:o.kX₁], zeros(nrows(o.R₁),o.kX₂)) : zeros(0, o.kX) # and convert model constraints from referring to X₁, Y₂ to X₁, X₂ end o.dof = nrows(o.R) if !o.WRE && iszero(o.κ) # regular OLS - o.DGP = StrEstimator{T}(o, true, o.LIML, o.Fuller, o.κ) - o.Repl = StrEstimator{T}(o, true, false, zero(T), zero(T)) # XXX isDGP=1 for Repl? doesn't matter? - setR!(o.DGP, o.null ? [o.R₁ ; o.R] : o.R₁) # DGP constraints: model constraints + null if imposed - setR!(o.Repl, o.R₁) # model constraints only - InitVarsOLS!(o.DGP, o.Repl.R₁perp) - InitTestDenoms!(o.DGP) + o.DGP = StrEstimator{T}(true, o.LIML, o.Fuller, o.κ) + o.Repl = StrEstimator{T}(true, false, zero(T), zero(T)) # XXX isDGP=1 for Repl? doesn't matter? + setR!(o.DGP, o, o.null ? [o.R₁ ; o.R] : o.R₁) # DGP constraints: model constraints + null if imposed + setR!(o.Repl, o, o.R₁) # model constraints only + InitVarsOLS!(o.DGP, o, o.Repl.R₁perp) + InitTestDenoms!(o.DGP, o) o.M = o.DGP # StrEstimator object from which to get A, AR, XAR elseif o.ARubin if o.willplot # for plotting/CI purposes get original point estimate since not normally generated - o.DGP = StrEstimator{T}(o, true, o.LIML, o.Fuller, o.κ) - setR!(o.DGP, o.R₁, zeros(T,0,o.kZ)) # no-null model - InitVarsIVGMM!(o.DGP) - EstimateIVGMM!(o.DGP, o.r₁) + o.DGP = StrEstimator{T}(true, o.LIML, o.Fuller, o.κ) + setR!(o.DGP, o, o.R₁, zeros(T,0,o.kZ)) # no-null model + InitVarsIV!(o.DGP, o) + EstimateIV!(o.DGP, o, o.r₁) o.confpeak = o.DGP.β̂ # estimated coordinate of confidence peak end - o.DGP = StrEstimator{T}(o, true, false, zero(T), zero(T)) - setR!(o.DGP, o.R₁) - InitVarsARubin!(o.DGP) - InitTestDenoms!(o.DGP) + o.DGP = StrEstimator{T}(true, false, zero(T), zero(T)) + setR!(o.DGP, o, o.R₁) + InitVarsARubin!(o.DGP, o) + InitTestDenoms!(o.DGP, o) o.M = o.DGP # StrEstimator object from which to get A, AR, XAR o.kZ = o.kX elseif o.WREnonARubin - o.DGP = StrEstimator{T}(o, true, T(o.kX₂ ≠ o.kY₂), zero(T), one(T)) - setR!(o.DGP, o.null ? [o.R₁ ; o.R] : o.R₁, zeros(T,0,o.kZ)) # DGP constraints: model constraints + null if imposed - InitVarsIVGMM!(o.DGP) + o.DGP = StrEstimator{T}(true, T(o.kX₂ ≠ o.kY₂), zero(T), one(T)) + setR!(o.DGP, o, o.null ? [o.R₁ ; o.R] : o.R₁, zeros(T,0,o.kZ)) # DGP constraints: model constraints + null if imposed + InitVarsIV!(o.DGP, o) if !o.null # if not imposing null, then DGP constraints, κ, Hessian, etc. do not vary with r and can be set now - EstimateIVGMM!(o.DGP, o.r₁) - MakeResidualsIVGMM!(o.DGP) + EstimateIV!(o.DGP, o, o.r₁) + MakeResidualsIV!(o.DGP, o) end - o.Repl = StrEstimator{T}(o, false, o.LIML, o.Fuller, o.κ) - setR!(o.Repl, o.R₁, o.R) - InitVarsIVGMM!(o.Repl) - EstimateIVGMM!(o.Repl, o.r₁) + o.Repl = StrEstimator{T}(false, o.LIML, o.Fuller, o.κ) + setR!(o.Repl, o, o.R₁, o.R) + InitVarsIV!(o.Repl, o) + EstimateIV!(o.Repl, o, o.r₁) o.LIML && o.Repl.kZ==1 && o.Nw==1 && (o.As = o.β̂s = zeros(1, o.B+1)) o.S✻UZperpinvZperpZperp = Vector{Matrix{T}}(undef, o.Repl.kZ+1) @@ -325,18 +321,18 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea else # the score bootstrap for IV/GMM uses a IV/GMM DGP but then masquerades as an OLS test because most factors are fixed during the bootstrap. To conform, need DGP and Repl objects with different R, R₁, one with FWL, one not - o.DGP = StrEstimator{T}(o, true, o.LIML, o.Fuller, o.κ) - setR!(o.DGP, o.null ? [o.R₁ ; o.R] : o.R₁, zeros(T,0,o.kZ)) # DGP constraints: model constraints + null if imposed - InitVarsIVGMM!(o.DGP) - o.Repl = StrEstimator{T}(o, true, o.LIML, o.Fuller, o.κ) - setR!(o.Repl, o.R₁, I) # process replication restraints = model constraints only - InitVarsIVGMM!(o.Repl, o.Repl.R₁perp) - EstimateIVGMM!(o.Repl, o.r₁) # bit inefficient to estimate in both objects, but maintains the conformity - InitTestDenoms!(o.Repl) + o.DGP = StrEstimator{T}(true, o.LIML, o.Fuller, o.κ) + setR!(o.DGP, o, o.null ? [o.R₁ ; o.R] : o.R₁, zeros(T,0,o.kZ)) # DGP constraints: model constraints + null if imposed + InitVarsIV!(o.DGP, o) + o.Repl = StrEstimator{T}(true, o.LIML, o.Fuller, o.κ) + setR!(o.Repl, o, o.R₁, I) # process replication restraints = model constraints only + InitVarsIV!(o.Repl, o, o.Repl.R₁perp) + EstimateIV!(o.Repl, o, o.r₁) # bit inefficient to estimate in both objects, but maintains the conformity + InitTestDenoms!(o.Repl, o) o.M = o.Repl # StrEstimator object from which to get A, AR, XAR; DGP follows WRE convention of using FWL, Repl follows OLS convention of not; scorebs for IV/GMM mixes the two if !o.null # if not imposing null, then DGP constraints, κ, Hessian, etc. do not vary with r and can be set now - EstimateIVGMM!(o.DGP, o.r₁) - MakeResidualsIVGMM!(o.DGP) + EstimateIV!(o.DGP, o, o.r₁) + MakeResidualsIV!(o.DGP, o) end end end @@ -358,7 +354,7 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea end end - o.small && (o.dof_r = o.NClustVar>0 ? minN - 1 : o._Nobs - o.kZ - o.NFE) + o.small && (o.dof_r = o.NClustVar>0 ? minN - one(T) : o._Nobs - (o.kZ + o.NFE)) # floating-point dof_r allows for fractional fweights, FWIW... o.sqrt = isone(o.dof) # work with t/z stats instead of F/chi2? @@ -382,7 +378,7 @@ function Init!(o::StrBootTest{T}) where T # for efficiency when varying r repea o.numer_b = Vector{T}(undef,nrows(o.Repl.RRpar)) end o.bootstrapt && o.robust && - (o.crosstabBootind = o.Nobs==o.N✻ ? diagind(FakeArray(o.N✻,o.N✻)) : + (o.crosstabBootind = o.Nobs==o.N✻ ? Vector(diagind(FakeArray(o.N✻,o.N✻))) : LinearIndices(FakeArray(o.Nobs,o.N✻))[CartesianIndex.(1:o.Nobs, o.IDBootData)]) else o.poles = o.anchor = zeros(T,0) diff --git a/src/interface.jl b/src/interface.jl index 69aefc5..8c1087e 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -6,7 +6,7 @@ struct BoottestResult{T} p::T; padj::T reps::Int64; repsfeas::Int64 NBootClust::Int64 - dof::Int64; dof_r::Int64 + dof::Int64; dof_r::T plot::Union{Nothing, NamedTuple{(:X, :p), Tuple{Tuple{Vararg{Vector{T}, N} where N},Vector{T}}}} peak::Union{Nothing, NamedTuple{(:X, :p), Tuple{Vector{T}, T}}} CI::Union{Nothing, Matrix{T}} @@ -79,6 +79,77 @@ function Base.show(io::IO, o::BoottestResult{T}) where T isdefined(o, :CI) && !isnothing(o.CI) && length(o.CI)>0 && print(io, "CI = $(CI(o))\n") end +# single entry point with arguments already converted to standardized types, to allow a small set of precompile() calls +function __wildboottest( + R::Matrix{T}, + r::Vector{T}; + resp::Vector{T}, + predexog::Matrix{T}, + predendog::Matrix{T}, + inst::Matrix{T}, + R1::Matrix{T}, + r1::Vector{T}, + clustid::Matrix{Int64}, + nbootclustvar::Int8, + nerrclustvar::Int8, + issorted::Bool, + hetrobust::Bool, + feid::Vector{Int64}, + fedfadj::Bool, + obswt::Vector{T}, + fweights::Bool, + maxmatsize::Float16, + ptype::PType, + bootstrapc::Bool, + LIML::Bool, + Fuller::T, + kappa::T, + ARubin::Bool, + small::Bool, + scorebs::Bool, + reps::Int64, + imposenull::Bool, + auxwttype::AuxWtType, + rng::AbstractRNG, + level::T, + rtol::T, + madjtype::MAdjType, + NH0::Int16, + ML::Bool, + scores::Matrix{T}, + beta::Vector{T}, + A::Symmetric{T,Matrix{T}}, + gridmin::Vector{T}, + gridmax::Vector{T}, + gridpoints::Vector{Float32}, + diststat::DistStatType, + getCI::Bool, + getplot::Bool, + getauxweights::Bool) where T + + M = StrBootTest{T}(R, r, R1, r1, resp, predexog, predendog, inst, obswt, fweights, LIML, Fuller, kappa, ARubin, + reps, auxwttype, rng, maxmatsize, ptype, imposenull, scorebs, !bootstrapc, clustid, nbootclustvar, nerrclustvar, issorted, hetrobust, small, + feid, fedfadj, level, rtol, madjtype, NH0, ML, beta, A, scores, getplot, + gridmin, gridmax, gridpoints) + + if getplot || (level<1 && getCI) + plot = getplot ? _getplot(M) : nothing + peak = getpeak(M) + CI = level<1 & getCI ? _getCI(M) : nothing + else + CI = plot = peak = nothing + end + + BoottestResult{T}(getstat(M), + isone(nrows(R)) ? (small ? "t" : "z") : (small ? "F" : "χ²"), + getp(M), getpadj(M), getreps(M), getrepsfeas(M), getNBootClust(M), getdf(M), getdf_r(M), plot, peak, CI, + getdist(M,diststat), + getb(M), getV(M), + getauxweights && reps>0 ? getauxweights(M) : nothing , M) +end + +@inline vecconvert(T::DataType, X) = isa(X, AbstractArray) ? reshape(eltype(X)==T ? X : T.(X), size(X,1) ) : X +@inline matconvert(T::DataType, X) = isa(X, AbstractArray) ? reshape(eltype(X)==T ? X : T.(X), size(X,1), size(X,2)) : X function _wildboottest(T::DataType, R::AbstractVecOrMat, @@ -153,27 +224,65 @@ function _wildboottest(T::DataType, @assert iszero(length(gridpoints)) || length(gridpoints)==nrows(R) "Length of gridpoints doesn't match number of hypotheses being jointly tested" end - M = StrBootTest{T}(R, r, R1, r1, resp, predexog, predendog, inst, obswt, fweights, LIML, Fuller, kappa, ARubin, - reps, auxwttype, rng, maxmatsize, ptype, imposenull, scorebs, !bootstrapc, clustid, nbootclustvar, nerrclustvar, issorted, hetrobust, small, - feid, fedfadj, level, rtol, madjtype, NH0, ML, beta, A, scores, getplot, - map(x->T(ismissing(x) ? NaN : x), gridmin), - map(x->T(ismissing(x) ? NaN : x), gridmax), - map(x->Float32(ismissing(x) ? NaN : x), gridpoints)) - - if getplot || (level<1 && getCI) - plot = getplot ? _getplot(M) : nothing - peak = getpeak(M) - CI = level<1 & getCI ? _getCI(M) : nothing - else - CI = plot = peak = nothing - end + _gridmin = Vector{T}(undef, length(gridmin)) + _gridmax = Vector{T}(undef, length(gridmax)) + _gridpoints = Vector{Float32}(undef, length(gridpoints)) + for i ∈ 1:length(gridmin) # cumbersome loops because map() and list comprehensions mess up type inference(?!) + _gridmin[i] = T(ismissing(gridmin[i]) ? NaN : gridmin[i]) + end + for i ∈ 1:length(gridmax) + _gridmax[i] = T(ismissing(gridmax[i]) ? NaN : gridmax[i]) + end + for i ∈ 1:length(gridpoints) + _gridpoints[i] = T(ismissing(gridpoints[i]) ? NaN : gridpoints[i]) + end - BoottestResult{T}(getstat(M), - isone(nrows(R)) ? (small ? "t" : "z") : (small ? "F" : "χ²"), - getp(M), getpadj(M), getreps(M), getrepsfeas(M), getNBootClust(M), getdf(M), getdf_r(M), plot, peak, CI, - getdist(M,diststat), - getb(M), getV(M), - getauxweights && reps>0 ? getauxweights(M) : nothing , M) + __wildboottest( + matconvert(T,R), + vecconvert(T,r); + resp=vecconvert(T,resp), + predexog=matconvert(T,predexog), + predendog=matconvert(T,predendog), + inst=matconvert(T,inst), + R1=matconvert(T,R1), + r1=vecconvert(T,r1), + clustid=matconvert(Int64,clustid), # bootstrap-only clust vars, then boot&err clust vars, then err-only clust vars + nbootclustvar=Int8(nbootclustvar), + nerrclustvar=Int8(nerrclustvar), + issorted, + hetrobust, + feid=vecconvert(Int64,feid), + fedfadj, + obswt=vecconvert(T,obswt), + fweights, + maxmatsize=Float16(maxmatsize), + ptype, + bootstrapc, + LIML, + Fuller=T(Fuller), + kappa=T(kappa), + ARubin, + small, + scorebs, + reps=Int64(reps), + imposenull, + auxwttype, + rng, + level=T(level), + rtol=T(rtol), + madjtype, + NH0=Int16(NH0), + ML, + scores=matconvert(T,scores), + beta=vecconvert(T,beta), + A=Symmetric(matconvert(T,A)), + gridmin=_gridmin, + gridmax=_gridmax, + gridpoints=_gridpoints, + diststat, + getCI, + getplot, + getauxweights) end _wildboottest(T::DataType, R, r::Number; kwargs...) = _wildboottest(T, R, [r]; kwargs...) diff --git a/src/nonWRE.jl b/src/nonWRE.jl index f6d4a6a..b0a5795 100644 --- a/src/nonWRE.jl +++ b/src/nonWRE.jl @@ -1,7 +1,7 @@ # OLS, ML (score bootstrap), and Anderson-Rubin tests # Construct stuff that depends linearly or quadratically on r, possibly by interpolation -function MakeInterpolables!(o::StrBootTest{T} where T) +function MakeInterpolables!(o::StrBootTest{T}) where T if o.interpolable if iszero(nrows(o.anchor)) # first call? save current r as permanent anchor for interpolation o.anchor = o.r @@ -17,7 +17,7 @@ function MakeInterpolables!(o::StrBootTest{T} where T) o.robust && (o.denom₀ = deepcopy(o.denom)) # grab quadratic denominator from *previous* (1st) evaluation newPole = trues(o.q) # all poles new else # been here at least twice? interpolate unless current r stretches range > 2X in some dimension(s) - newPole = abs.(o.r - o.anchor) .> 2 * abs.(o.poles) + newPole = abs.(o.r - o.anchor) .> T(2) * abs.(o.poles) end if any(newPole) # prep interpolation @@ -101,15 +101,15 @@ function _MakeInterpolables!(o::StrBootTest{T}, thisr::AbstractVector) where T o.uXAR = o.sc * (o.AR = o.A * o.R') else if o.ARubin - EstimateARubin!(o.DGP, thisr) - MakeResidualsOLSARubin!(o.DGP) + EstimateARubin!(o.DGP, o, thisr) + MakeResidualsOLSARubin!(o.DGP, o) elseif iszero(o.κ) # regular OLS EstimateOLS!(o.DGP, o.null ? [o.r₁ ; thisr] : o.r₁) - MakeResidualsOLSARubin!(o.DGP) + MakeResidualsOLSARubin!(o.DGP, o) elseif o.null # in score bootstrap for IV/GMM, if imposing null, then DGP constraints, κ, Hessian, etc. do vary with r and must be set now - EstimateIVGMM!(o.DGP, [o.r₁ ; thisr]) - InitTestDenoms!(o.DGP) - MakeResidualsIVGMM!(o.DGP) + EstimateIV!(o.DGP, o, [o.r₁ ; thisr]) + InitTestDenoms!(o.DGP, o) + MakeResidualsIV!(o.DGP, o) end o.ü = o.DGP.ü₁ @@ -123,7 +123,7 @@ function _MakeInterpolables!(o::StrBootTest{T}, thisr::AbstractVector) where T o.NClustVar ? @panelsum(o.uXAR, o.wt, o.infoBootData) : vHadw(o.uXAR, o.wt) : - wtsum(o.wt, o.uXAR) : + o.haswt ? reshape(o.uXAR'o.wt,1,:) : sum(o.uXAR,dims=1) : o.DGP.A * @panelsum2(o.X₁, o.X₂, vHadw(o.ü, o.wt), o.infoBootData)' # same calc as in score BS but broken apart to grab intermediate stuff, and assuming residuals defined; X₂ empty except in Anderson-Rubin if o.robust && o.bootstrapt && o.granular < o.NErrClustCombs diff --git a/src/plot-CI.jl b/src/plot-CI.jl index 553721d..4b7af67 100644 --- a/src/plot-CI.jl +++ b/src/plot-CI.jl @@ -48,26 +48,22 @@ function plot!(o::StrBootTest{T}) where T boottest!(o) if o.ARubin - halfwidth = abs.(o.confpeak) * T.(quantile(Normal(), getpadj(o, classical=true)/2) / quantile(Normal(), α/2)) + halfwidth = abs.(o.confpeak) * quantile(Normal{T}(zero(T),one(T)), getpadj(o, classical=true)/2) / quantile(Normal{T}(zero(T),one(T)), α/2) else halfwidth = T.(-1.5 * quantile(Normal(), α/2)) .* sqrtNaN.(diag(getV(o))) o.confpeak = getb(o) + o.r end - +# println("o.confpeak=$(o.confpeak)") if isone(o.q) # 1D plot α≤0 && (α = T(.05)) # if level=100, no CI constructed, but we need a reasonable α to choose graphing bounds - - if α > 0 && ncols(o.v)-1 ≤ 1/α-1e6 - throw(ErrorException("need at least $(ceil(1/α)) replications to resolve a $(o.level)% two-sided confidence interval.")) - end - - p_lo, p_hi = T(NaN), T(NaN) +# println("gridmin=$(o.gridmin) gridmax=$(o.gridmax) 1") + p_lo = p_hi = T(NaN) if isnan(o.gridmin[1]) || isnan(o.gridmax[1]) if o.B>0 # initial guess based on classical distribution lo = isnan(o.gridmin[1]) ? o.confpeak - halfwidth : o.gridmin hi = isnan(o.gridmax[1]) ? o.confpeak + halfwidth : o.gridmax else - tmp = vec(sqrtNaN.(o.statDenom)) * T(o.small ? cquantile(TDist(o.dof_r), α/2) : cquantile(Normal(), α/2)) + tmp = vec(sqrtNaN.(o.statDenom)) * (o.small ? cquantile(TDist(o.dof_r), α/2) : cquantile(Normal{T}(zero(T),one(T)), α/2)) lo = isnan(o.gridmin[1]) ? o.confpeak - tmp : o.gridmin hi = isnan(o.gridmax[1]) ? o.confpeak + tmp : o.gridmax if o.scorebs && !o.null && !o.willplot # if doing simple Wald test with no graph, we're done @@ -75,24 +71,24 @@ function plot!(o::StrBootTest{T}) where T return end end - +# println("lo=$lo hi=$hi") if abs(lo[1] - o.r[1]) > abs(hi[1] - o.r[1]) # brute force way to ensure that first trial bound tested is the farther one from r, for better interpolation if isnan(o.gridmin[1]) && o.ptype≠lower # unless lower-tailed p value, try at most 10 times to bracket confidence set by symmetrically widening for _ ∈ 1:10 p_lo = r_to_p(o, lo) p_lo < α && break - tmp = hi - lo - lo .-= tmp - isnan(o.gridmax[1]) && o.twotailed && (hi .+= tmp) # maintain rough symmetry unless user specified upper bound + diff = hi - lo + lo .-= diff + isnan(o.gridmax[1]) && o.twotailed && (hi .+= diff) # maintain rough symmetry unless user specified upper bound end end if isnan(o.gridmax[1]) && o.ptype≠upper # ditto for high side for _ ∈ 1:10 p_hi = r_to_p(o, hi) p_hi < α && break - tmp = hi - lo - isnan(o.gridmin[1]) && o.twotailed && (lo .-= tmp) - hi .+= tmp + diff = hi - lo + isnan(o.gridmin[1]) && o.twotailed && (lo .-= diff) + hi .+= diff end end else @@ -100,18 +96,18 @@ function plot!(o::StrBootTest{T}) where T for _ ∈ 1:10 p_hi = r_to_p(o, hi) p_hi < α && break - tmp = hi - lo - isnan(o.gridmin[1]) && o.twotailed && (lo .-= tmp) - hi .+= tmp + diff = hi - lo + isnan(o.gridmin[1]) && o.twotailed && (lo .-= diff) + hi .+= diff end end if isnan(o.gridmin[1]) && o.ptype≠lower # unless upper-tailed p value, try at most 10 times to bracket confidence set by symmetrically widening for _ ∈ 1:10 p_lo = r_to_p(o, lo) p_lo < α && break - tmp = hi - lo - lo .-= tmp - isnan(o.gridmax[1]) && o.twotailed && (hi .+= tmp) # maintain rough symmetry unless user specified upper bound + diff = hi - lo + lo .-= diff + isnan(o.gridmax[1]) && o.twotailed && (hi .+= diff) # maintain rough symmetry unless user specified upper bound end end end @@ -119,10 +115,11 @@ function plot!(o::StrBootTest{T}) where T lo = [o.gridmin[1]] hi = [o.gridmax[1]] end +println("lo=$lo hi=$hi after") - _gridpoints = round(Int32, o.gridpoints[1]) - o.plotX = (collect(range(lo[1], hi[1], length=_gridpoints)),) # store as 1-tuple since q=1 - o.plotY = fill(T(NaN), _gridpoints) + _gridpoints = round.(Int32, o.gridpoints) + o.plotX = [collect(range(lo[1], hi[1], length=_gridpoints[1]))] # store as 1-vector since q=1 + o.plotY = fill(T(NaN), _gridpoints[1]) o.plotY[1 ] = p_lo o.plotY[end] = p_hi p_confpeak = o.WREnonARubin ? T(NaN) : o.twotailed ? one(T) : T(.5) @@ -131,6 +128,11 @@ function plot!(o::StrBootTest{T}) where T insert!(o.plotX[1], c, o.confpeak[1]) insert!(o.plotY , c, p_confpeak) + isnan(o.plotY[1]) && (o.plotY[1] = r_to_p(o, [o.plotX[1][1]])) # do in this order for widest interpolation base range + for (i,v) ∈ Iterators.reverse(enumerate(o.plotX[1])) + i>1 && isnan(o.plotY[i]) && (o.plotY[i] = r_to_p(o, [v])) + end + else # 2D plot _gridpoints = round.(Int32, o.gridpoints) @@ -140,14 +142,14 @@ function plot!(o::StrBootTest{T}) where T lo[d] = isnan(o.gridmin[d]) ? o.confpeak[d] - halfwidth[d] : o.gridmin[d] hi[d] = isnan(o.gridmax[d]) ? o.confpeak[d] + halfwidth[d] : o.gridmax[d] end - o.plotX = (collect(range(lo[1], hi[1], length=_gridpoints[1])), - collect(range(lo[2], hi[2], length=_gridpoints[2]))) + o.plotX = [collect(range(lo[1], hi[1], length=_gridpoints[1])), + collect(range(lo[2], hi[2], length=_gridpoints[2]))] o.plotY = fill(T(NaN), _gridpoints[1]*_gridpoints[2]) - end - isnan(o.plotY[1]) && (o.plotY[1] = r_to_p(o, [o.plotX[i][1] for i in 1:o.q])) # do in this order for widest interpolation - @views for (i,v) ∈ Iterators.reverse(enumerate(Iterators.product(o.plotX...))) - i>1 && isnan(o.plotY[i]) && (o.plotY[i] = r_to_p(o, [v...])) + isnan(o.plotY[1]) && (o.plotY[1] = r_to_p(o, [o.plotX[i][1] for i in 1:o.q])) # do in this order for widest interpolation base range + for (i,v) ∈ Iterators.reverse(enumerate(Iterators.product(o.plotX[1],o.plotX[2]))) + i>1 && isnan(o.plotY[i]) && (o.plotY[i] = r_to_p(o, [v...])) + end end if any(isnan.(o.plotY)) diff --git a/src/precompile.jl b/src/precompile.jl deleted file mode 100644 index f48e50b..0000000 --- a/src/precompile.jl +++ /dev/null @@ -1,82 +0,0 @@ -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :auxwttype), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 1}, WildBootTests.AuxWtType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :auxwttype, :predexog), Tuple{Array{Float32, 1}, Array{Int32, 1}, WildBootTests.AuxWtType, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"##_wildboottest#46", Array{Float32, 1}, Array{Float32, 2}, Array{Float32, 2}, Array{Float32, 2}, Array{Float32, 2}, Array{Float32, 1}, Array{Int32, 1}, Int64, Int64, Bool, Bool, Array{Int8, 1}, Bool, Array{Float32, 1}, Bool, Int64, WildBootTests.PType, Bool, Bool, Int64, Float64, Bool, Bool, Bool, Int64, Bool, WildBootTests.AuxWtType, Random.MersenneTwister, Float64, Float64, WildBootTests.MAdjType, Int64, Bool, Array{Float32, 2}, Array{Float32, 1}, Array{Float32, 2}, Array{Float32, 1}, Array{Float32, 1}, Array{Int32, 1}, WildBootTests.DistStatType, Bool, Bool, Bool, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :reps, :auxwttype, :getCI), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 1}, Int64, WildBootTests.AuxWtType, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :getCI, :auxwttype, :predexog), Tuple{Array{Float32, 1}, Array{Int32, 1}, Int64, Bool, WildBootTests.AuxWtType, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :reps, :auxwttype), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 1}, Int64, WildBootTests.AuxWtType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :auxwttype, :predexog), Tuple{Array{Float32, 1}, Array{Int32, 1}, Int64, WildBootTests.AuxWtType, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:R1, :r1, :resp, :predexog, :clustid), Tuple{Array{Int64, 2}, Array{Float64, 1}, Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 1}}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :r1, :R1, :predexog), Tuple{Array{Float32, 1}, Array{Int32, 1}, Array{Float64, 1}, Array{Int64, 2}, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :reps, :ptype), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Int64, WildBootTests.PType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :predendog, :ptype, :predexog), Tuple{Array{Float32, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Array{Float64, 1}, WildBootTests.PType, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :reps, :auxwttype, :bootstrapc, :ptype), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Int64, WildBootTests.AuxWtType, Bool, WildBootTests.PType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :predendog, :auxwttype, :bootstrapc, :ptype, :predexog), Tuple{Array{Float32, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Array{Float64, 1}, WildBootTests.AuxWtType, Bool, WildBootTests.PType, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :ARubin, :reps), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Bool, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :ARubin, :small, :predendog, :predexog), Tuple{Array{Float32, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Bool, Array{Float64, 1}, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :ARubin, :reps, :imposenull), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Bool, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :imposenull, :ARubin, :small, :predendog, :predexog), Tuple{Array{Float32, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Bool, Bool, Array{Float64, 1}, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :reps), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :predendog, :predexog), Tuple{Array{Float32, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Array{Float64, 1}, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :reps, :imposenull), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :imposenull, :small, :predendog, :predexog), Tuple{Array{Float32, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Bool, Array{Float64, 1}, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :LIML, :clustid, :small, :reps), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 2}, Bool, Array{Int32, 1}, Bool, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :LIML, :predendog, :predexog), Tuple{Array{Float32, 1}, Array{Float64, 2}, Array{Int32, 1}, Int64, Bool, Bool, Array{Float64, 1}, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :Fuller, :clustid, :small, :reps, :auxwttype), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 2}, Int64, Array{Int32, 1}, Bool, Int64, WildBootTests.AuxWtType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :predendog, :auxwttype, :predexog, :Fuller), Tuple{Array{Float32, 1}, Array{Float64, 2}, Array{Int32, 1}, Int64, Bool, Array{Float64, 1}, WildBootTests.AuxWtType, Array{Float32, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :obswt, :feid), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 2}, Int64, Int64, Array{Float64, 1}, Array{Int64, 1}}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :obswt, :feid, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float32, 1}, Array{Int32, 2}, Array{Float64, 1}, Array{Int64, 1}, Int64, Array{Float32, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :feid, :reps), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 2}, Int64, Int64, Array{Int32, 1}, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :feid, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float32, 1}, Array{Int32, 2}, Int64, Array{Int32, 1}, Int64, Array{Float32, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :gridpoints, :reps), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 1}, Array{Int64, 1}, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :gridpoints, :predexog), Tuple{Array{Float32, 1}, Array{Int32, 1}, Int64, Array{Int64, 1}, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :reps, :imposenull), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 1}, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :imposenull, :predexog), Tuple{Array{Float32, 1}, Array{Int32, 1}, Int64, Bool, Array{Float32, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :reps), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 2}, Int64, Int64, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float32, 1}, Array{Int32, 2}, Int64, Int64, Array{Float32, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :reps, :imposenull), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int32, 2}, Int64, Int64, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :imposenull, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float32, 1}, Array{Int32, 2}, Int64, Bool, Int64, Array{Float32, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :reps), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int64, 2}, Int64, Int64, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float32, 1}, Array{Int64, 2}, Int64, Int64, Array{Float32, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :reps, :imposenull), Tuple{Array{Float32, 1}, Array{Float32, 2}, Array{Int64, 2}, Int64, Int64, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :imposenull, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float32, 1}, Array{Int64, 2}, Int64, Bool, Int64, Array{Float32, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :auxwttype), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 1}, WildBootTests.AuxWtType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :auxwttype, :predexog), Tuple{Array{Float64, 1}, Array{Int32, 1}, WildBootTests.AuxWtType, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"##_wildboottest#46", Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 2}, Array{Float64, 2}, Array{Float64, 2}, Array{Float64, 1}, Array{Int32, 1}, Int64, Int64, Bool, Bool, Array{Int8, 1}, Bool, Array{Float64, 1}, Bool, Int64, WildBootTests.PType, Bool, Bool, Int64, Float64, Bool, Bool, Bool, Int64, Bool, WildBootTests.AuxWtType, Random.MersenneTwister, Float64, Float64, WildBootTests.MAdjType, Int64, Bool, Array{Float32, 2}, Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, WildBootTests.DistStatType, Bool, Bool, Bool, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :reps, :auxwttype, :getCI), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 1}, Int64, WildBootTests.AuxWtType, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :getCI, :auxwttype, :predexog), Tuple{Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, WildBootTests.AuxWtType, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :reps, :auxwttype), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 1}, Int64, WildBootTests.AuxWtType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :auxwttype, :predexog), Tuple{Array{Float64, 1}, Array{Int32, 1}, Int64, WildBootTests.AuxWtType, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:R1, :r1, :resp, :predexog, :clustid), Tuple{Array{Int64, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 1}}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :r1, :R1, :predexog), Tuple{Array{Float64, 1}, Array{Int32, 1}, Array{Float64, 1}, Array{Int64, 2}, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :reps, :ptype), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Int64, WildBootTests.PType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :predendog, :ptype, :predexog), Tuple{Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Array{Float64, 1}, WildBootTests.PType, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :reps, :auxwttype, :bootstrapc, :ptype), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Int64, WildBootTests.AuxWtType, Bool, WildBootTests.PType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :predendog, :auxwttype, :bootstrapc, :ptype, :predexog), Tuple{Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Array{Float64, 1}, WildBootTests.AuxWtType, Bool, WildBootTests.PType, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Float64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :ARubin, :reps), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Bool, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :ARubin, :small, :predendog, :predexog), Tuple{Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Bool, Array{Float64, 1}, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :ARubin, :reps, :imposenull), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Bool, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :imposenull, :ARubin, :small, :predendog, :predexog), Tuple{Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Bool, Bool, Array{Float64, 1}, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :reps), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :predendog, :predexog), Tuple{Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Array{Float64, 1}, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :clustid, :small, :reps, :imposenull), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Bool, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :imposenull, :small, :predendog, :predexog), Tuple{Array{Float64, 1}, Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Bool, Array{Float64, 1}, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :LIML, :clustid, :small, :reps), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 2}, Bool, Array{Int32, 1}, Bool, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :LIML, :predendog, :predexog), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 1}, Int64, Bool, Bool, Array{Float64, 1}, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :predendog, :inst, :Fuller, :clustid, :small, :reps, :auxwttype), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Float64, 1}, Array{Float64, 2}, Int64, Array{Int32, 1}, Bool, Int64, WildBootTests.AuxWtType}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :inst, :clustid, :reps, :small, :predendog, :auxwttype, :predexog, :Fuller), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 1}, Int64, Bool, Array{Float64, 1}, WildBootTests.AuxWtType, Array{Float64, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :obswt, :feid), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 2}, Int64, Int64, Array{Float64, 1}, Array{Int64, 1}}}, typeof(WildBootTests.wildboottest), Type, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :obswt, :feid, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float64, 1}, Array{Int32, 2}, Array{Float64, 1}, Array{Int64, 1}, Int64, Array{Float64, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Int64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :feid, :reps), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 2}, Int64, Int64, Array{Int32, 1}, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :feid, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float64, 1}, Array{Int32, 2}, Int64, Array{Int32, 1}, Int64, Array{Float64, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :gridpoints, :reps), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 1}, Array{Int64, 1}, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :gridpoints, :predexog), Tuple{Array{Float64, 1}, Array{Int32, 1}, Int64, Array{Int64, 1}, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :reps, :imposenull), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 1}, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :imposenull, :predexog), Tuple{Array{Float64, 1}, Array{Int32, 1}, Int64, Bool, Array{Float64, 2}}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :reps), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 2}, Int64, Int64, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float64, 1}, Array{Int32, 2}, Int64, Int64, Array{Float64, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :reps, :imposenull), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int32, 2}, Int64, Int64, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :imposenull, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float64, 1}, Array{Int32, 2}, Int64, Bool, Int64, Array{Float64, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :reps), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int64, 2}, Int64, Int64, Int64}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float64, 1}, Array{Int64, 2}, Int64, Int64, Array{Float64, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#wildboottest##kw", NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :reps, :imposenull), Tuple{Array{Float64, 1}, Array{Float64, 2}, Array{Int64, 2}, Int64, Int64, Int64, Bool}}, typeof(WildBootTests.wildboottest), Type, Array{Float64, 2}, Array{Int64, 1}}) -precompile(Tuple{WildBootTests.var"#_wildboottest##kw", NamedTuple{(:resp, :clustid, :reps, :imposenull, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Array{Float64, 1}, Array{Int64, 2}, Int64, Bool, Int64, Array{Float64, 2}, Int64}}, typeof(WildBootTests._wildboottest), DataType, Array{Float64, 2}, Array{Int64, 1}}) diff --git a/src/precompile_WildBootTests.jl b/src/precompile_WildBootTests.jl new file mode 100644 index 0000000..8fdec1e --- /dev/null +++ b/src/precompile_WildBootTests.jl @@ -0,0 +1,69 @@ +const __bodyfunction__ = Dict{Method,Any}() + +# Find keyword "body functions" (the function that contains the body +# as written by the developer, called after all missing keyword-arguments +# have been assigned values), in a manner that doesn't depend on +# gensymmed names. +# `mnokw` is the method that gets called when you invoke it without +# supplying any keywords. +function __lookup_kwbody__(mnokw::Method) + function getsym(arg) + isa(arg, Symbol) && return arg + @assert isa(arg, GlobalRef) + return arg.name + end + + f = get(__bodyfunction__, mnokw, nothing) + if f === nothing + fmod = mnokw.module + # The lowered code for `mnokw` should look like + # %1 = mkw(kwvalues..., #self#, args...) + # return %1 + # where `mkw` is the name of the "active" keyword body-function. + ast = Base.uncompressed_ast(mnokw) + if isa(ast, Core.CodeInfo) && length(ast.code) >= 2 + callexpr = ast.code[end-1] + if isa(callexpr, Expr) && callexpr.head == :call + fsym = callexpr.args[1] + if isa(fsym, Symbol) + f = getfield(fmod, fsym) + elseif isa(fsym, GlobalRef) + if fsym.mod === Core && fsym.name === :_apply + f = getfield(mnokw.module, getsym(callexpr.args[2])) + elseif fsym.mod === Core && fsym.name === :_apply_iterate + f = getfield(mnokw.module, getsym(callexpr.args[3])) + else + f = getfield(fsym.mod, fsym.name) + end + else + f = missing + end + else + f = missing + end + else + f = missing + end + __bodyfunction__[mnokw] = f + end + return f +end + +function _precompile_() + ccall(:jl_generating_output, Cint, ()) == 1 || return nothing + Base.precompile(Tuple{Core.kwftype(typeof(wildboottest)),NamedTuple{(:resp, :predexog, :clustid, :nbootclustvar, :nerrclustvar, :feid, :reps), Tuple{Vector{Float32}, Matrix{Float32}, Matrix{Int16}, Int64, Int64, Vector{Int16}, Int64}},typeof(wildboottest),Matrix{Float64},Vector{Int64}}) # time: 29.61254 + let fbody = try __lookup_kwbody__(which(wildboottest, (Type,Matrix{Float64},Vector{Int64},))) catch missing end + if !ismissing(fbody) + precompile(fbody, (Base.Pairs{Symbol, Any, NTuple{7, Symbol}, NamedTuple{(:resp, :clustid, :reps, :feid, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Vector{Float32}, Matrix{Int16}, Int64, Vector{Int16}, Int64, Matrix{Float32}, Int64}}},typeof(wildboottest),Type,Matrix{Float64},Vector{Int64},)) + end + end # time: 28.634747 + Base.precompile(Tuple{Core.kwftype(typeof(_wildboottest)),NamedTuple{(:resp, :clustid, :reps, :feid, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Vector{Float32}, Matrix{Int16}, Int64, Vector{Int16}, Int64, Matrix{Float32}, Int64}},typeof(_wildboottest),DataType,Matrix{Float64},Vector{Int64}}) # time: 0.1897423 + Base.precompile(Tuple{Core.kwftype(typeof(_wildboottest)),NamedTuple{(:resp, :clustid, :reps, :feid, :nbootclustvar, :predexog, :nerrclustvar), Tuple{Vector{Float32}, Matrix{Int16}, Int64, Vector{Int16}, Int64, Matrix{Float32}, Int64}},typeof(_wildboottest),Matrix{Float64},Vector{Int64}}) # time: 0.0375642 + Base.precompile(Tuple{Core.kwftype(typeof(__wildboottest)),NamedTuple{(:resp, :predexog, :predendog, :inst, :R1, :r1, :clustid, :nbootclustvar, :nerrclustvar, :issorted, :hetrobust, :feid, :fedfadj, :obswt, :fweights, :maxmatsize, :ptype, :bootstrapc, :LIML, :Fuller, :kappa, :ARubin, :small, :scorebs, :reps, :imposenull, :auxwttype, :rng, :level, :rtol, :madjtype, :NH0, :ML, :scores, :beta, :A, :gridmin, :gridmax, :gridpoints, :diststat, :getCI, :getplot, :getauxweights), Tuple{Vector{Float32}, Matrix{Float32}, Matrix{Float32}, Matrix{Float32}, Matrix{Float32}, Vector{Float32}, Matrix{Int64}, Int8, Int8, Bool, Bool, Vector{Int64}, Bool, Vector{Float32}, Bool, Float16, PType, Bool, Bool, Float32, Float32, Bool, Bool, Bool, Int64, Bool, AuxWtType, MersenneTwister, Float32, Float32, MAdjType, Int16, Bool, Matrix{Float32}, Vector{Float32}, Symmetric{Float32, Matrix{Float32}}, Vector{Float32}, Vector{Float32}, Vector{Float32}, DistStatType, Bool, Bool, Bool}},typeof(__wildboottest),Matrix{Float32},Vector{Float32}}) # time: 0.0167941 + let fbody = try __lookup_kwbody__(which(_wildboottest, (DataType,Matrix{Float64},Vector{Int64},))) catch missing end + if !ismissing(fbody) + precompile(fbody, (Vector{Float32},Matrix{Float32},Matrix{Float32},Matrix{Float32},Matrix{Float32},Vector{Float32},Matrix{Int16},Int64,Int64,Bool,Bool,Vector{Int16},Bool,Vector{Float32},Bool,Int64,PType,Bool,Bool,Int64,Float64,Bool,Bool,Bool,Int64,Bool,AuxWtType,MersenneTwister,Float64,Float64,MAdjType,Int64,Bool,Matrix{Float32},Vector{Float32},Matrix{Float32},Vector{Float32},Vector{Float32},Vector{Int32},DistStatType,Bool,Bool,Bool,typeof(_wildboottest),DataType,Matrix{Float64},Vector{Int64},)) + end + end # time: 0.0094284 + Base.precompile(Tuple{Type{BoottestResult{Float32}},Float32,String,Float32,Float32,Int64,Int64,Int64,Int64,Float32,NamedTuple{(:X, :p), Tuple{Tuple{Vector{Float32}}, Vector{Float32}}},NamedTuple{(:X, :p), Tuple{Vector{Float32}, Float32}},Matrix{Float32},Matrix{Float32},Vector{Float32},Matrix{Float32},Nothing,StrBootTest{Float32}}) # time: 0.0043929 +end diff --git a/src/utilities.jl b/src/utilities.jl index e9ec70b..95dbc36 100644 --- a/src/utilities.jl +++ b/src/utilities.jl @@ -1,13 +1,12 @@ # core functions not referencing StrBootest or StrEstimator "classes" @inline sqrtNaN(x) = x<0 ? typeof(x)(NaN) : sqrt(x) -@inline invsym(X) = iszero(length(X)) ? Symmetric(X) : inv(Symmetric(X)) -@inline eigensym(X) = eigen(Symmetric(X)) # does eigen recognize symmetric matrices? +@inline invsym(X) = iszero(nrows(X)) ? Symmetric(X) : inv(Symmetric(X)) @inline symcross(X::AbstractVecOrMat, wt::AbstractVector) = Symmetric(cross(X,wt,X)) # maybe bad name since it means cross product in Julia -@inline function cross(X::AbstractVecOrMat{T}, wt::AbstractVector{T}, Y::AbstractVecOrMat{T}) where T - dest = Matrix{T}(undef, ncols(X), ncols(Y)) - if iszero(nrows(wt)) +function cross(X::AbstractVecOrMat{T}, wt::AbstractVector{T}, Y::AbstractVecOrMat{T}) where T + dest = Matrix{T}(undef, ncols(X), ncols(Y)) + if iszero(nrows(wt)) mul!(dest, X', Y) elseif ncols(X)>ncols(Y) mul!(dest, X', wt.*Y) @@ -15,7 +14,7 @@ mul!(dest, (X.*wt)', Y) end end -@inline function crossvec(X::AbstractMatrix{T}, wt::AbstractVector{T}, Y::AbstractVector{T}) where T +function crossvec(X::AbstractMatrix{T}, wt::AbstractVector{T}, Y::AbstractVector{T}) where T dest = Vector{T}(undef, ncols(X)) if iszero(nrows(wt)) mul!(dest, X', Y) @@ -26,7 +25,7 @@ end end end -@inline vHadw(v::AbstractArray, w::AbstractVector) = iszero(nrows(w)) ? v : v .* w +@inline vHadw(v::AbstractArray, w::AbstractVector) = iszero(nrows(w)) ? v : v .* w # not type-stable @inline nrows(X::AbstractArray) = size(X,1) @inline ncols(X::AbstractArray) = size(X,2) @@ -34,8 +33,6 @@ end @inline colsum(X::AbstractArray) = iszero(length(X)) ? similar(X, 1, size(X)[2:end]...) : sum(X, dims=1) @inline rowsum(X::AbstractArray) = vec(sum(X, dims=2)) -@inline wtsum(wt::AbstractVector, X::AbstractMatrix) = iszero(nrows(wt)) ? sum(X,dims=1) : reshape(X'wt,1,:) # return 1xN Matrix - function X₁₂B(X₁::AbstractVecOrMat, X₂::AbstractArray, B::AbstractMatrix) dest = X₁ * view(B,1:size(X₁,2),:) length(dest)>0 && length(X₂)>0 && matmulplus!(dest, X₂, B[size(X₁,2)+1:end,:]) @@ -244,30 +241,31 @@ macro panelsum2(X₁, X₂, wt, info) :( panelsum2($(esc(X₁)), $(esc(X₂)), $(esc(wt)), $(esc(info))) ) end -# UberMatrix type to efficiently represent selection matrices -@enum MatType identity selection regular -import Base.size, Base.getindex, Base.* -struct UberMatrix{T} <: AbstractMatrix{T} - type::MatType - size::Tuple{Int64,Int64} - p::Vector{Int64} # for selection matrix - M::Matrix{T} -end -UberMatrix(T::DataType, X::UniformScaling{Bool}) = UberMatrix{T}(identity, (0,0), Int64[], zeros(T,0,0)) -function UberMatrix(T::DataType, X::AbstractMatrix) - if isa(X,AbstractMatrix) && length(X) > 0 && all(sum(isone.(X), dims=1) .== 1) && all(sum(iszero.(X), dims=1) .== size(X,1)-1) - UberMatrix{T}(selection, size(X), Base.:*(X',collect(1:size(X,1))), zeros(T,0,0)) - else - UberMatrix{T}(regular, size(X), Int64[], X) - end -end -size(X::UberMatrix) = X.size -getindex(X::UberMatrix, i, j) = X.type==identity ? i==j : X.type==selection ? i==X.p[j] : X.M[i,j] -*(X::AbstractVector, Y::UberMatrix) = Y.type==identity ? view(X,:) : Y.type==selection ? view(X,Y.p) : view(Base.:*(X,Y.M),:) -*(X::AbstractMatrix, Y::UberMatrix) = Y.type==identity ? view(X,:,:) : Y.type==selection ? view(X,:,Y.p) : view(Base.:*(X,Y.M),:,:) -*(X::UberMatrix, Y::AbstractMatrix) = X.type==identity ? view(Y,:,:) : X.type==selection ? view(Y, X.p, :) : view(Base.:*(X.M,Y),:,:) -*(X::UberMatrix, Y::AbstractVector) = X.type==identity ? view(Y,:) : X.type==selection ? view(Y, X.p) : view(Base.:*(X.M,Y),:) +# # UberMatrix type to efficiently represent selection matrices +# @enum MatType identity selection regular +# import Base.size, Base.getindex, Base.* +# struct UberMatrix{T} <: AbstractMatrix{T} +# type::MatType +# size::Tuple{Int64,Int64} +# p::Vector{Int64} # for selection matrix +# M::Matrix{T} +# end +# UberMatrix(T::DataType, X::UniformScaling{Bool}) = UberMatrix{T}(identity, (0,0), Int64[], zeros(T,0,0)) +# function UberMatrix(T::DataType, X::AbstractMatrix) +# if isa(X,AbstractMatrix) && length(X) > 0 && all(sum(isone.(X), dims=1) .== 1) && all(sum(iszero.(X), dims=1) .== size(X,1)-1) +# UberMatrix{T}(selection, size(X), Base.:*(X',collect(1:size(X,1))), zeros(T,0,0)) +# else +# UberMatrix{T}(regular, size(X), Int64[], X) +# end +# end +# size(X::UberMatrix) = X.size +# getindex(X::UberMatrix, i, j) = X.type==identity ? i==j : X.type==selection ? i==X.p[j] : X.M[i,j] +# *(X::AbstractVector, Y::UberMatrix) = Y.type==identity ? view(X,:) : Y.type==selection ? view(X,Y.p) : view(Base.:*(X,Y.M),:) +# function *(X::AbstractMatrix{T}, Y::UberMatrix{T})::SubArray{T,2,Matrix{T}} where T Y.type==identity ? view(X,:,:) : Y.type==selection ? view(X,:,Y.p) : view(Base.:*(X,Y.M),:,:) end +# *(X::UberMatrix, Y::AbstractMatrix) = X.type==identity ? view(Y,:,:) : X.type==selection ? view(Y, X.p, :) : view(Base.:*(X.M,Y),:,:) +# *(X::UberMatrix, Y::AbstractVector) = X.type==identity ? view(Y,:) : X.type==selection ? view(Y, X.p) : view(Base.:*(X.M,Y),:) +import Base.size struct FakeArray{N} <: AbstractArray{Bool,N} size::Tuple{Vararg{Int64,N}} end # AbstractArray with almost no storage, just for LinearIndices() conversion FakeArray(size...) = FakeArray{length(size)}(size) size(X::FakeArray) = X.size \ No newline at end of file diff --git a/test/unittests.log b/test/unittests.log index 5268482..70efaa9 100644 --- a/test/unittests.log +++ b/test/unittests.log @@ -1,18 +1,18 @@ boottest post_self=.04, weight(webb) -t=2.0194175 p=0.06406406 CI=Float32[0.03877484 0.069972485] +t=2.019417 p=0.06406406 CI=Float32[0.038774837 0.069972485] boottest post_self=.04, weight(webb) reps(9999999) noci -t=2.0194175 p=0.075657405 +t=2.019417 p=0.07565891 regress hasinsurance selfemployed post post_self, cluster(year) boottest (post_self=.05) (post=-.02), reps(9999) weight(webb) -F=0.33827603 p=0.82128215 +F=0.33827585 p=0.82128215 constraint 1 ttl_exp = .2 cnsreg wage tenure ttl_exp collgrad, constr(1) cluster(industry) boottest tenure -t=2.1249483 p=0.0 CI=Float32[0.008769161 0.18435653] +t=2.1249485 p=0.0 CI=Float32[0.008769164 0.18435656] ivregress 2sls wage ttl_exp collgrad (tenure = union), cluster(industry) boottest tenure, ptype(equaltail) @@ -22,16 +22,16 @@ boottest tenure, ptype(equaltail) reps(99999) weight(webb) stat(c) z=1.6443632 p=0.11061106 CI=Float32[-Inf Inf] boottest, ar -z=2.4454055 p=0.030273438 CI=Float32[0.06995599 1.2517976] +z=2.4454045 p=0.030273438 CI=Float32[0.0699562 1.2517973] boottest, ar nonull -z=2.4454055 p=0.030273438 CI=Float32[0.0560943 1.4158137] +z=2.4454045 p=0.030273438 CI=Float32[0.056094516 1.4158134] scoretest tenure -z=2.3278728 p=0.01991886 CI=Float32[0.13671665 1.3236711] +z=2.3278728 p=0.01991886 CI=Float32[0.13671672 1.3236711] waldtest tenure -z=2.604013 p=0.009213928 CI=Float32[0.18202372 1.2898893] +z=2.604013 p=0.009213928 CI=Float32[0.1820237 1.2898893] ivregress liml wage (tenure = collgrad ttl_exp), cluster(industry) boottest tenure @@ -39,11 +39,11 @@ z=7.584672 p=0.003003003 CI=Float32[0.3354117 0.8054973] ivreg2 wage collgrad smsa race age (tenure = union married), cluster(industry) fuller(1) boottest tenure, nograph weight(webb) reps(9999) -z=4.026846 p=0.0250025 CI=Float32[-0.8936746 -0.38782808; 0.30943274 1.2528461] +z=4.0268483 p=0.0250025 CI=Float32[-0.89367354 -0.3875849; 0.30943295 1.2528456] areg wage ttl_exp collgrad tenure [aw=hours] if occupation<., cluster(age) absorb(industry) boottest tenure, cluster(age occupation) bootcluster(occupation) -t=0.48740005 p=0.6596597 CI=Float32[-0.041599624 0.114947945] +t=0.4873999 p=0.6596597 CI=Float32[-0.041599624 0.114947945] global pix lnkm pixpetro pixdia pixwaterd pixcapdist pixmal pixsead pixsuit pixelev pixbdist global geo lnwaterkm lnkm2split mean_elev mean_suit malariasuit petroleum diamondd @@ -53,8 +53,8 @@ qui areg lnl0708s centr_tribe lnpd0 $pix $geo $poly, absorb(ccode) boottest centr_tribe, nogr reps(9999) clust(ccode pixcluster) bootcluster(ccode) boottest centr_tribe, nogr reps(9999) clust(ccode pixcluster) bootcluster(pixcluster) boottest centr_tribe, nogr reps(9999) clust(ccode pixcluster) bootcluster(ccode pixcluster) -t=3.5211518 p=0.00210021 CI=Float32[0.055923488 0.25092918] -t=3.5211346 p=0.00260026 CI=Float32[0.045336463 0.26122943] +t=3.5211513 p=0.00210021 CI=Float32[0.05592348 0.25092924] +t=3.5211344 p=0.00260026 CI=Float32[0.045336455 0.2612295] t=3.5211346 p=0.0033003301 CI=Float32[0.054486457 0.24806121] infile coll merit male black asian year state chst using regm.raw, clear @@ -66,9 +66,9 @@ boottest merit, nogr reps(9999) gridpoints(10) bootcluster(state year) boottest merit, nogr reps(9999) gridpoints(10) nonull bootcluster(state year) boottest merit, nogr reps(9999) gridpoints(10) bootcluster(individual) boottest merit, nogr reps(9999) gridpoints(10) nonull bootcluster(individual) -t=6.7126637 p=0.49184918 CI=Float32[-2.815854 1.2845851] -t=6.712715 p=0.0 CI=Float32[0.049524896 0.0948111] -t=6.712664 p=0.29282928 CI=Float32[-5.339361 4.5325885] +t=6.712663 p=0.49184918 CI=Float32[-2.8158534 1.2845849] +t=6.7127156 p=0.0 CI=Float32[0.049524896 0.0948111] +t=6.7126627 p=0.29282928 CI=Float32[-5.339361 4.5325885] t=6.7127147 p=0.08940894 CI=Float32[-0.011595309 0.15593131] -t=6.7126617 p=0.37383738 CI=Float32[-0.09999678 0.2419289] -t=6.712718 p=0.37593758 CI=Float32[-0.0941135 0.2384495] +t=6.712662 p=0.37383738 CI=Float32[-0.09999681 0.24192892] +t=6.7127175 p=0.37593758 CI=Float32[-0.0941135 0.2384495]