C++ for Scientists - Technische Universität Dresden
C++ for Scientists - Technische Universität Dresden
C++ for Scientists - Technische Universität Dresden
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
2.11. REAL-WORLD EXAMPLE: MATRIX INVERSION 61<br />
This does not work yet <strong>for</strong> technical reasons but will in the future.<br />
You may argue that the transpostions and passing the matrix and the vector once more takes<br />
more time. More importantly, we know that the lower matrix has a unit diagonal and we did<br />
not explore this property, e.g. <strong>for</strong> avoiding the divisions in the triangular solver. We could<br />
even ignore or omit the diagonal and treat this implicitly in the algorithms. This is all true.<br />
However, we prioritized the simplicity and clarity of the implementation and the reusability<br />
aspect higher than per<strong>for</strong>mance here. 28<br />
We have now all we need to put the matrix inversion together. As above we start we checking<br />
the squareness.<br />
dense2D inline inverse(dense2D const& A)<br />
{<br />
const unsigned n= num rows(A);<br />
assert(num cols(A) == n); // Matrix must be square<br />
Then we per<strong>for</strong>m the LU factorization. For per<strong>for</strong>mance reasons this function does not return<br />
the result but takes its arguments as mutable references and factorizes in place. Thus, we need<br />
a copy of a matrix to pass and a permutation vector of appropriate size.<br />
dense2D PLU(A);<br />
dense vector Pv(n);<br />
lu(PLU, Pv);<br />
The upper triangular factor PU of the permuted A is stored in the upper triangle of PLU. The<br />
lower triangular factor PL is partly stored in the strict lower triangle of PLU while the unit<br />
diagonal is omitted. We there<strong>for</strong>e need to add it be<strong>for</strong>e inversion (or alternatively handle the<br />
unit diagonal implicitly in the inversion).<br />
dense2D PU(upper(PLU)), PL(strict lower(PLU) + matrix::identity(n, n));<br />
The inversion of a square matrix according to Equation (2.1) can then be per<strong>for</strong>med in one<br />
single line: 29<br />
return dense2D(inverse upper(PU) ∗ inverse lower(PL) ∗ permutation(Pv));<br />
During this section you have seen that you have always alternatives to implement the same<br />
behavior, most likely you already made this experience be<strong>for</strong>e. Despite we suggested <strong>for</strong> every<br />
choice we made that it is the most appropriate, there is not always THE single best solution and<br />
even while trading off pro and cons of the alternatives, one might not come to a final conclusion<br />
and just pick one. We also illustrated that the choices depend on the goals, <strong>for</strong> instance the<br />
implementation would look different if per<strong>for</strong>mance were the primary goal.<br />
The section shall show as well that that non-trivial programs are not written in a single sweep<br />
by an ingenious mind — exceptions might prove the rule — but are the result of a gradually<br />
improving development. Experience will make this journey shorter and directer but we will not<br />
write the perfect program at the first glance.<br />
28 People that care about per<strong>for</strong>mance do not use matrix inversion in the first place.<br />
29 The explicit conversion can probably be omitted in later versions of MTL4.