03.12.2012 Views

C++ for Scientists - Technische Universität Dresden

C++ for Scientists - Technische Universität Dresden

C++ for Scientists - Technische Universität Dresden

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

56 CHAPTER 2. <strong>C++</strong> BASICS<br />

A function computing the inverse must return the same value and also pass the test agains<br />

identity:<br />

Matrix A inverse(inverse(A));<br />

cout ≪ ”inverse(A) is \n” ≪ A inverse ≪ ”A ∗ AI is\n” ≪ Matrix(A inverse ∗ A);<br />

assert(one norm(Matrix(A inverse ∗ A − I)) < 0.1);<br />

After establishing tests <strong>for</strong> all components of our calculation we start with their implementations.<br />

The first function we program is the inversion of an upper triangular matrix. This function<br />

takes a dense matrix as argument and returns another matrix:<br />

dense2D inline inverse upper(dense2D const& A) {<br />

}<br />

Since we do not need another copy of the input matrix we pass it as reference. The argument<br />

shall not be changed so we can pass it as const. The constancy has several advantages:<br />

• We improve the reliability of our program. Arguments passed as const are guaranteed<br />

not to change, if we accidentally modify them the compiler will tell us and abort the<br />

compilation. There is a way to remove the constancy but this should only be used as<br />

last resort, e.g. <strong>for</strong> interfacing obsolete libraries written by others. Everything you write<br />

yourself can be realized without eliminating the constancy of arguments.<br />

• Compilers can optimize better when the objects are guaranteed not to alter.<br />

• In case of references, the function can be called with expressions. Non-const references<br />

require to store the expression into a variable and pass the variable to the function.<br />

Another comment, people might tell you that it is too expensive to return containers as results<br />

and it is more efficient to use references. This is true — in principle. For the moment we accept<br />

this extra cost and pay more attention to clarity and convenience. Later in this book we will<br />

introduce techniques how to minimize the cost of returning containers from functions.<br />

So much <strong>for</strong> the function signature, let us now turn our attention to the function body. The<br />

first thing we do is verifying that our argument is valid. Obviously the matrix must be square:<br />

const unsigned n= num rows(A);<br />

assert(num cols(A) == n); // Matrix must be square<br />

The number of rows is needed several times in this function and is there<strong>for</strong>e stored in a variable,<br />

well constant. Another prerequisite is that the matrix has no zero entries in the diagonal. We<br />

leave this test to the triangular solver.<br />

Speaking of which, we can get our inverse triangular matrix with a triangular solver of a linear<br />

system, which we find in MTL4, more precisely the k-th vector of U −1 is the solution of<br />

Ux = ek<br />

where ek is the k-th unit vector. First we define a temporary variable <strong>for</strong> the result.<br />

dense2D Inv(n, n);<br />

Then we iterate over the columns of Inv:

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!