Don’t invert that matrix
johndcook.com
johndcook.com
Use a library instead, and use the most specific methods that are available: if there are specialized routines to solve Ax=b, use them, don't use the matrix inversion methods (which are probably also there), or even the LU decomposition ones, even if Real Math tells you that the result is equivalent - in numerical computation, mathematical equivalence is an entirely different entity than what "real" mathematicians concern themselves with.
Seriously. I don't care if you're a math PhD, I don't even care if you know a decent amount about numerical methods. Whatever code you're going to put together to do the job will be inferior to what a mature library can do, simply because the library has been put through many iterations and has had a lot more time to get patched up to handle all those special cases (usually related to finite precision or discretization) that Real Math doesn't have to worry about. And it will probably be vastly more optimized than anything you'll put together, because it's spent years of heavy use in some critical research environments.
The only time you should be writing your own math code (beyond simple arithmetic) is if no mature libraries are available to you. In which case you should allocate at the very least twice the amount of time it will take to research and implement the methods, and probably a lot more, because you're going to have a lot of fiddling to do.
Then, you can go on and use third party libraries in production while feeling satisfied that you know what's going on inside the library.
Depends if your goal is to become an aeronautical engineer or an assembly language hacker, really. Neither one's "better" than the other, but the the former won't benefit much from understanding exactly how to optimize on SPARC vs x64... Nor will the latter need to worry about his compiler's stalling speed :-)
[EDITED to add: That's if what you want is specifically linear algebra. <<<numerical library>>> does pretty well if your needs are more general.]
I remember this also being the case for Constraint Satisfaction Problem (CSP) algorithms in AI. If you can formulate your problem as a CSP and feed it to a library, you automatically benefit from future improvements in the field of CSP solvers.
We can all count the floating-point operations, and today caches sometimes influence matrix algorithms more than raw flop counts. The problem gets more interesting when the matrix becomes ill conditioned and different algorithms will produce very different results.
Side note: My professor also mentioned it at least 3 times in each lecture... so it is important.
>> A = randn(100); x = randn(100,1); b = A*x;
>> tic; x1 = inv(A)*b; toc
Elapsed time is 0.142381 seconds.
>> tic; x2 = A\b; toc
Elapsed time is 0.000736 seconds.
>> max(abs(x-x1))
ans =
7.1054e-14
>> max(abs(x-x2))
ans =
4.8406e-14
Edit: Actually this is a warning about timing stuff. The inv function hadn't "warmed up". On a second run both times drop, and the difference is much smaller: >> tic; x1 = inv(A)*b; toc
Elapsed time is 0.000737 seconds.
>> tic; x2 = A\b; toc
Elapsed time is 0.000471 seconds.http://www.mathworks.com/matlabcentral/fileexchange/18798-ti...
which warms up the function, averages over repetitions and tries to account for various overheads, the ratio states about the same (1:1.5 ish). I would normally use timeit(), but for a quick post, I was being sloppy.
For amusement, it's really worth knowing about
http://www.comlab.ox.ac.uk/people/nick.trefethen/publication...
which shows that each of the popular nonsymmetric iterations can beat all others by a huge factor.
But this is all justification that you should use a library like PETSc for your linear solvers. Then all aspects of the solve become run-time (typically command-line) options including an algebra for composing preconditioners and other components, with a plugin architecture for every component.
Actually, this isn't so weird. There are a number of domain decomposition schemes that use CG, but keep all iterates in a benign space on which the operator is SPD, even though the real system is indefinite (porous media and Stokes/mixed elasticity). See work by Axel Klawonn, and recent stuff from Xuemin Tu.
But that kind of obscures the fact that, while algorithms like LU decomposition are faster than a pure matrix inversion, they're faster by a constant factor of about 2 or so. It's not a fundamentally different algorithm, just a different set of tricks to solve a bunch of simultaneous equations. If you aren't hugely performance constrained and already have a matrix inversion routine, you'd never be bothered to re-write your equation solver just for this speedup.
Really, check Numerical Recipes. I like their section a lot, though I don't have my copy handy to give you a cite.
Sadly they're using the horrid 'File open' encryption on the PDFs.
It's easy for a wonk to flame about something as pedestrian as a how-to text for working scientists, but it's really not helpful.
http://www.fceia.unr.edu.ar/~fisicomp/apuntes/biblios/wnotnr...
and the suggested alternatives
http://www.fceia.unr.edu.ar/~fisicomp/apuntes/biblios/altnr....
In addition to those suggestions, here are a few more relevant to the present discussion. For dense matrices and how to think about linear algebra algorithms, I highly recommend Trefethen and Bau "Numerical Linear Algebra". For sparse direct solvers, Tim Davis' book (http://www.ec-securehost.com/SIAM/FA02.html) is good, and you can transition from the "learning"-level implementation to Umfpack which is his production-quality solver (it's what is behind Matlab's backslash). For iterative solvers, Saad is pretty standard. For multiphysics solvers, I don't think any book can match the Knoll and Keyes' 2004 review on Jacobian-free Newton-Krylov methods (it's very accessible).
The GSL has better implementations for many general-purpose algorithms in NR. SciPy is great if you work in Python. For scalable linear and nonlinear solvers, look at PETSc.
Could you recommend a better book?
The result of carrying out the elimination steps is a triangular matrix with all zeros below the main diagonal. Call it U, for "upper".
The elimination steps themselves can be encoded as a matrix, rather than describing them in words. For instance, "subtract 2 times row 1 from row 2" is the matrix:
[ 1 0 0]
[-2 1 0]
[ 0 0 1]
So, to solve the system, you can perform elimination on A x = b, which gives you two matrices (U, and the elimination steps L). In some sense, you've factored A in to L and U.
Example:
Using Strang's terminology, let's call the matrix that "eliminates (i.e. sets to 0) the (i,j) entry" Eij
So, to solve a 3x3 system A x = b, you want to do elimination as: (E32 E31 E21) A = U
I.e.
1) Take A and subtract some multiple of row 2 from row 1, to put 0 in (2,1)
2) Take the result and subtract some multiple of row 3 from row 1 to put 0 in (3,1)
3) Take the result and subtract some multiple of row 3 from row 2 to put 0 in (3,2)
Now the goal of elimination is to get an uppper-triangular matrix U. I.e. if you were solving some system of equations in x, y, z, then because U is triangular, you could just read off the answer to z. Then plug that into the equation for row 2 to solve for y, then plug that into the equation for row 1 to solve for x. That's back-substitution.
BUT, let's return to our operations. We have:
E32 E31 E21 A = U
(E32 E31 E21) A = U
inverse(E32 E31 E21) (E32 E31 E21) A = inverse(E32 E31 E21) U
I A = inverse(E32 E31 E21) U
Now, it just so happens that the inverse of (E32 E31 E21) is lower-triangular. I.e. all entries above the diagonal are zero, so let's call it L.
I A = L U
A = L U
LU-decomposition. Or "factorization", since we've factored A into two matrices: L, and U.
see http://en.wikipedia.org/wiki/Pivoting and http://en.wikipedia.org/wiki/Gaussian_elimination