Additional links:
- Original class material
<< Previous lecture | Next lecture >>
Introduction
In the following we want to study how to use numpy
and scipy
to solve Linear Systems with Python. Most of the functions in numpy
and scipy
for Linear Algebra are contained in the sub-packages np.linalg
and scipy.linalg
, as you will see in the following.
To fix the notation, given a matrix and a vector , solving a linear system means finding (when exists) a vector such that it solves
This is not hard to do in numpy
, since it implements a function np.linalg.solve
, taking as input a 2-dimensional array A
and a 1-dimensional array y
, and returns the solution x
to the linear system. In particular:
Testing the accuracy
When the matrix is ill-conditioned, the solution of a linear system wonβt be correct, since the small perturbations on introduced by the floating point system will be amplified and the corresponding solution will be dramatically distant to the true solution. To check how accurate our computed solution is to the true solution of the system (i.e. to quantify the amplification of the perturbation on the data), it is common to use the relative error, which is defined as
Clearly, the problem is that if our algorithm fails in recovering the true solution due to the ill-conditioning of the system matrix , how can we compute the true solution , required to compute ? The solution is to build a test problem.
Creating a Test Problem
Consider a matrix and assume we want to test the accuracy of an algorithm solving systems involving . Fix an -dimensional vector , and compute . Clearly, this procedure defines a linear system
of which we know that is a solution, since we built the term accordingly. Now, when we apply our algorithm to that linear system, we get a solution , approximately solving . Given that, we can always compute the relative error associated to the solution obtained by the algorithm. Using numpy
, this can be simply done as
Condition number
You should already know that the conditioning of an matrix can be quantified by a term called condition number which, whenever is invertible, is defined as
where identifies the norm with respect to which the condition number is computed (hence the term -condition number).
An invertible matrix is said to be ill-conditioned when its condition number grows exponentially with the dimension of the problem, .
The condition number is related to the accuracy of the computed solution of a linear system by the following inequality
which implies that the relative error on the computed solution is big whenever is big. Moreover, note that as a consequence of the formula above, the accuracy of a computed solution is partially a property of the condition number of itself, meaning that no algorithm is able to compute an accurate solution to an ill-conditioned system.
Computing the -condition number of a matrix in numpy
is trivial: just using the function np.linalg.cond(A, p)
to compute does the job.
Solving Linear System by Matrix Splitting
As you should know, when the matrix is unstructured, the linear system can be efficiently solved by using LU Decomposition. In particular, with Gaussian elimination algorithm, one can factorize any non-singular matrix into:
where is a lower-triangular matrix, is an upper-triangular matrix with all ones on the diagonal and is a permutation matrix (i.e. a matrix obtained by permutating the rows of the identity matrix). If the decomposition is computed without pivoting, the permutation matrix equals the identity. Note that the assumption that is non-singular is not restrictive, since it is a necessary condition for the solvability of .
Since is an orthogonal matrix, , thus
Since linear systems of the form
can be efficiently solved by the Forward (Backward) substitution, and the computation of the LU factorization by Gaussian elimination is pretty fast ( floating point operations), we can use that to solve the former linear system. Indeed,
then, by Forward-Backward substitution, this system can be solved by subsequently solve
whose solution is a solution for .
Even if this procedure is automatically performed by the np.linalg.solve
function, we can unroll it with the functions scipy.linalg.lu(A)
and scipy.linalg.solve_triangular(A, b)
, whose documentation can be found here and here.
Exercise
Write a function
solve(A,y)
that takes as input a non-singular matrix and a vector and returns the solution of without usingnp.linalg.lu
.
Visualize solution