{smcl}
{* 30 Nov 2011}{...}
{cmd:help smwoodbury}
{hline}
{title:Syntax}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_lu(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:,} real matrix {it:V}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_lu_solve(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:,} real matrix {it:V}{cmd:,} real matrix {it:AinvB}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_qr(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:,} real matrix {it:V}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_qr_solve(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:,} real matrix {it:V}{cmd:,} real matrix {it:AinvB}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym1_lu(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym1_lu_solve(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:AinvB}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym1_qr(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym1_qr_solve(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:AinvB}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym1_posdef(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym1_posdef_solve(}real matrix {it:Ainv}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:AinvB}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym2_lu(}real scalar {it:s}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym2_lu_solve(}real scalar {it:s}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:,} real matrix {it:sB}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym2_qr(}real scalar {it:s}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym2_qr_solve(}real scalar {it:s}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:,} real matrix {it:sB}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym2_posdef(}real scalar {it:s}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:)}
{p 8 12 2}
{it:real matrix}{bind: }{cmd:smwoodbury_sym2_posdef_solve(}real scalar {it:s}{cmd:,} real matrix {it:U}{cmd:,} real matrix {it:Cinv}{cmd:,} real matrix {it:sB}{cmd:)}
{title:Description}
{p 4 4 2}
This package provides a set of Mata functions that implement the Sherman-Morrison-Woodbury formula for a rank-k update to a matrix inverse and that use the formula to efficiently solve matrix equations. The formula is:
{p 4 4 2}
inv(A+U*C*V) = inv(A) - inv(A)*U*inv(inv(C)+V*inv(A)*U)*V*inv(A)
{p 4 4 2}
where A is NxN, U is NxK, C is KxK, V is KxN.
Use of this formula can save computation time when N is much larger than K and either inv(A) is easy to calculate or inv(A+U*C*V) must be calculated many times for different values of U, C and V.
Such situations arise, for example, in Markov chain Monte Carlo estimation of mixed models.
{p 4 4 2}
Notice that the functions require as input Ainv and Cinv, the inverses of A and C, rather than A and C themselves.
{p 4 4 2}
{cmd:smwoodbury_lu()} and {cmd:smwoodbury_qr()} implement the full formula.
The former uses lusolve() and thus assumes Cinv+V*Ainv*U has full rank.
The latter uses qrsolve() and will work even when Cinv+V*Ainv*U does not have full rank (or is poorly conditioned), but is typically slower.
{p 4 4 2}
{cmd:smwoodbury_sym1_lu()} and {cmd:smwoodbury_sym1_qr()} implement the special case where C=I(K), V=U', and A is symmetric.
The former uses lusolve() and thus assumes I(K)+U'*Ainv*U has full rank. This assumption generally holds but can fail for unusual values of A and U.
The latter uses qrsolve() and will work even when I(K)+U'*Ainv*U does not have full rank (or is poorly conditioned), but is typically slower.
To maximize speed, {cmd:smwoodbury_sym1_lu()} and {cmd:smwoodbury_sym1_qr()} do not verify that Ainv is symmetric.
You may get unexpected results if Ainv is not symmetric.
{p 4 4 2}
{cmd:smwoodbury_sym1_posdef()} implements the special case where C=I(K), V=U', A is symmetric, and I(K)+U'*Ainv*U is positive definite.
To maximize speed, the function does not verify that Ainv is symmetric or that I(K)+U'*Ainv*U is positive definite. You may get unexpected results if these conditions fail.
{p 4 4 2}
{cmd:smwoodbury_sym2_lu()} and {cmd:smwoodbury_sym2_qr()} implement the special case where V=U' and A=I(N)/s for a nonzero scalar s.
The former uses lusolve() and thus assumes Cinv+s*U'*U has full rank. This assumption generally holds but can fail for unusual values of s and U.
The latter uses qrsolve() and will work even when Cinv+s*U'*U does not have full rank (or is poorly conditioned), but is typically slower.
{p 4 4 2}
{cmd:smwoodbury_sym2_posdef()} implements the special case where V=U', A=I(N)/s for a nonzero scalar s, Cinv is symmetric, and Cinv+s*U'*U is positive definite.
To maximize speed, the function does not verify that Cinv is symmetric or that Cinv+s*U'*U is positive definite. You may get unexpected results if these conditions fail.
{p 4 4 2}
Functions {cmd:smwoodbury_*_solve()} are equivalent to the functions without {cmd:solve} in the name but are designed to efficiently solve the equation (A+U*C*V)X=B for X. These functions require as input either AinvB=inv(A)*B or sB=(s*I(N))*B.
{title:Author}
{p 4}Sam Schulhofer-Wohl{p_end}
{p 4}Federal Reserve Bank of Minneapolis{p_end}
{p 4}90 Hennepin Ave.{p_end}
{p 4}Minneapolis MN 55480-0291{p_end}
{p 4}wohls@minneapolisfed.org{p_end}
{p 4 4 2}The views expressed herein are those of the author and not necessarily those of the Federal Reserve Bank of Minneapolis or the Federal Reserve System.