Resolución de sistemas lineales

Contenido

Vamos a resolver sistemas de ecuaciones lineales con el mismo número de ecuaciones que de incógnitas con matriz de coeficientes no singular que, por lo tanto, tiene solución única.

Dados los números $a_{ij}$ y $b_{j}$ para $i,j=1,2,\ldots,n$ se trata de hallar los números $x_{1},x_{2},\ldots,x_{n}$ que verifican las $n$ ecuaciones lineales

$$ \begin{array}{cll} a_{11}x_{1}+a_{12}x_{2}+\ldots+a_{1n}x_{n} & = & b_{1},\\ a_{21}x_{1}+a_{22}x_{2}+\ldots+a_{2n}x_{n} & = & b_{2},\\ \vdots\\ a_{n1}x_{1}+a_{n2}x_{2}+\ldots+a_{nn}x_{n} & = & b_{n}. \end{array} $$

Con from __future__ import division obligamos a que el resultado de la división con / sea siempre float. Si no lo incluímos, la división de dos enteros con / sería también un entero.

Importamos los módulos numpy y pprint. El módulo pprint proporciona una forma de imprimir datos más ordenada.

In [1]:
from __future__ import division

import numpy as np
import pprint

Métodos directos

Sustitución progresiva

Para el sistema $$ L\mathbf{x}=\mathbf{b}, $$ con $L$ de la forma $$ L=\left(\begin{array}{ccccc} l_{11} & 0 & 0 & \ldots & 0\\ l_{21} & l_{22} & 0 & \ldots & 0\\ l_{31} & l_{32} & l_{33} & \ldots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ l_{n1} & l_{n2} & l_{n3} & \ldots & l_{nn} \end{array}\right) $$ la ecuación $i$-ésima es, para $i=1,2,\ldots,n$, $$ l_{i1}x_{1}+l_{i2}x_{2}+\cdots+l_{ii}x_{i}=b_{i}. $$

Por lo tanto, para $i=1,2,\ldots,n$, si $l_{ii}$ es no nulo, entonces $$ x_{i}=\frac{b_{i}-l_{i1}x_{1}-\cdots-l_{ii-1}x_{i-1}}{l_{ii}}= \frac{1}{l_{ii}}\left(b_{i}-\sum_{j=1}^{i-1}l_{ij}x_{j}\right). $$

Algoritmo

  • Si $l_{11}=0$, acabar.
  • En caso contrario, $x_{1}=\dfrac{b_{1}}{l_{11}}$
  • Para $i=2,\ldots,n$
  • Si $l_{ii}= 0$, acabar.

  • En caso contrario $$ x_{i}=\frac{1}{l_{ii}}\left(b_{i}-\sum_{j=1}^{i-1}l_{ij}x_{j}\right). $$


Ejercicio 1

Escribir una función sust_prog(L,b) cuyo argumento de salida $x$ es la solución del sistema $Lx=b$, con L una matriz triangular inferior y b una matriz columna.

Usarla para resolver el sistema

$$\left(\begin{array}{rrr} 2 & 0 & 0\\ 1 & 2 & 0\\ 1 & 1 & 2 \end{array}\right) \left(\begin{array}{c} x_1\\ x_2\\ x_3 \end{array}\right)= \left(\begin{array}{r} 2\\ -1\\ 0 \end{array}\right) $$

Comprobar la solución calculando $Lx$ y comparándolo con $b$.

In [2]:
# define las matrices A y b usando arrays numpy
L = np.array([[2, 0, 0], [1, 2, 0], [1, 1, 2]])
b = np.array([2, -1, 0])

Comprobar que la función también funciona correctamente con el sistema $Lx=b$ de matrices $L$ y $b$ generadas de la siguiente forma

In [3]:
n = 5
np.random.seed(1)           # para que los números aleatorios se repitan
L = np.random.random((n,n)) # genera una matriz aleatoria nxn
L = np.tril(L)              # hacer cero los elementos por encima de la diagonal
b = np.random.random((n,))  # genera un vector aleatorio de dimensión n

print 'L'
pprint.pprint(L)
print 'b' 
pprint.pprint(b)
L
array([[ 0.417022  ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.09233859,  0.18626021,  0.        ,  0.        ,  0.        ],
       [ 0.41919451,  0.6852195 ,  0.20445225,  0.        ,  0.        ],
       [ 0.67046751,  0.4173048 ,  0.55868983,  0.14038694,  0.        ],
       [ 0.80074457,  0.96826158,  0.31342418,  0.69232262,  0.87638915]])
b
array([ 0.89460666,  0.08504421,  0.03905478,  0.16983042,  0.8781425 ])
In [4]:
%run Ejercicio1.py
------------- Sistema 1 -------------

 x
array([ 1, -1,  0])

 Lx
array([ 2, -1,  0])

 b
array([ 2, -1,  0])

------------- Sistema 2 -------------

 x
array([ 0.23583128,  2.1439431 , -2.98378361,  8.17298166, -7.18403614])

 Lx
array([ 0.09834683,  0.42110763,  0.95788953,  0.53316528,  0.69187711])

 b
array([ 0.09834683,  0.42110763,  0.95788953,  0.53316528,  0.69187711])

Sustitución regresiva

Análogamente, para el sistema

$$ U\mathbf{x}=\mathbf{b}' $$

con $U$ de la forma

$$ U=\left(\begin{array}{ccccc} u_{11} & u_{12} & u_{13} & \ldots & u_{1n}\\ 0 & u_{22} & u_{23} & \ldots & u_{2n}\\ 0 & 0 & u_{33} & \ldots & u_{3n}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & 0 & u_{nn} \end{array}\right) $$

la $i$-ésima ecuación es, para $i=1,2,\ldots,n$,

$$ u_{ii}x_{i}+u_{ii+1}x_{i+1}+\cdots+u_{in}x_{n}=b_{i} $$

Por lo tanto, para $i=1,2,\ldots,n$, si $l_{ii}$ no se anula

$$ x_{i}=\frac{b_{i}-u_{ii+1}x_{i+1}-\cdots-u_{in}x_{n}}{u_{ii}}= \frac{1}{u_{ii}}\left(b_{i}-\sum_{j=i+1}^{n}u_{ij}x_{j}\right), $$

Algoritmo

  • Si $u_{11}=0$, acabar.
  • Caso contrario, $x_{n}=\dfrac{b_{n}}{u_{nn}}$
  • Para $i=n-1,\ldots,1$
    • Si $u_{ii}=0$, acabar.
    • Caso contrario,
$$ x_{i}=\frac{1}{u_{ii}}\left(b_{i}-\sum_{j=i+1}^{n}u_{ij}x_{j}\right). $$

Ejercicio 2

Escribir una función sust_regre(U,b) cuyo argumento de salida $x$ es la solución del sistema $Ux=b$, con U una matriz triangular superior y b una matriz columna.

Usarla para resolver el sistema

$$\left(\begin{array}{rrr} 2 & 1 & 1\\ 0 & 2 & 1\\ 0 & 0 & 2 \end{array}\right) \left(\begin{array}{c} x_1\\ x_2\\ x_3 \end{array}\right)= \left(\begin{array}{r} 9\\ 4\\ 4 \end{array}\right) $$
  • Comprobar la solución calculando $Ux$ y comparándolo con $b$.
  • Comprobar que la función también funciona bien con el sistema $Ux=b$ de matrices $L$ y $b$ generadas como sigue
In [5]:
n = 5
np.random.seed(2)           
U = np.random.random((n,n)) 
U = np.triu(U)              # Haz cero los elementos bajo la diagonal
b = np.random.random((n,))  

print 'U'
pprint.pprint(U)
print 'b' 
pprint.pprint(b)
U
array([[ 0.4359949 ,  0.02592623,  0.54966248,  0.43532239,  0.4203678 ],
       [ 0.        ,  0.20464863,  0.61927097,  0.29965467,  0.26682728],
       [ 0.        ,  0.        ,  0.13457995,  0.51357812,  0.18443987],
       [ 0.        ,  0.        ,  0.        ,  0.84656149,  0.07964548],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.12715997]])
b
array([ 0.59674531,  0.226012  ,  0.10694568,  0.22030621,  0.34982629])
In [6]:
%run Ejercicio2.py
------------- Sistema 1 -------------

 x
array([3, 1, 2])

 Ux
array([9, 4, 4])

 b
array([9, 4, 4])

------------- Sistema 2 -------------

 x
array([  2.08436952e+00,   6.53605274e+00,  -2.98103215e+00,
         1.41246173e-03,   2.75107237e+00])

 Ux
array([ 0.59674531,  0.226012  ,  0.10694568,  0.22030621,  0.34982629])

 b
array([ 0.59674531,  0.226012  ,  0.10694568,  0.22030621,  0.34982629])

Gaussian elimination

La idea del método de Gauss es transformar el sistema original en un sistema con matriz de coeficientes triangular superior que tenga la misma solución. Para ello, usaremos las siguientes operaciones:

  • Sumamos una fila multiplicada por una constante a otra $f_i\rightarrow f_i +\lambda f_i,\quad i\ne j$
  • Intercambiamos filas.

Una vez que la matriz del sistema es triangular, podemos resolver el sistema por sustitución regresiva.

En general, el método debe incluir el intercambio de filas, pero empezaremos escribiendo el código sin intercambio de filas.

Algoritmo

  • Para $k=2,\ldots,n$
    • Si $a_{kk}=0$, acabar.
    • Caso contrario, $i=k+1,\ldots,n,\quad \quad b_{i}=b_{i}-\dfrac{a_{ik}}{a_{kk}}b_{k}. $
      • Para $i=k+1,\ldots,n, \quad a_{ij}=a_{ij}-\dfrac{a_{ik}}{a_{kk}}a_{ik}. $

Ejercicio 3

Escribir una función triang(A,b) cuyos argumentos de salida son la matriz triangular superior U y el vector c, obtenidos a partir de la matriz del sistema A y su término independiente b.

Usarla con las matrices del sistem $Ax=b$

$$\left(\begin{array}{rrr} 2 & 1 & 1\\ 1 & 2 & 1\\ 1 & 1 & 2 \end{array}\right) \left(\begin{array}{c} x_1\\ x_2\\ x_3 \end{array}\right)= \left(\begin{array}{r} 2\\ 4\\ 6 \end{array}\right) $$
  • Escribir los argumentos de salida U y c.
  • Resolver el sistema equivalente $Ux=c$ y comprobar que la solución del sistema es correcta, calculando $Ax$ y comparándolo con $b$.
  • Comprobar que el código también funciona correctamente para resolver el sistema $Ax=b$ cuyas matrices $A$ y $b$ han sido generadas de la manera siguiente
In [7]:
n = 5
np.random.seed(3)           
A = np.random.random((n,n)) 
b = np.random.random((n,))  

print '\n A \n'
pprint.pprint(A)
print '\n b \n' 
pprint.pprint(b)
 A 

array([[ 0.5507979 ,  0.70814782,  0.29090474,  0.51082761,  0.89294695],
       [ 0.89629309,  0.12558531,  0.20724288,  0.0514672 ,  0.44080984],
       [ 0.02987621,  0.45683322,  0.64914405,  0.27848728,  0.6762549 ],
       [ 0.59086282,  0.02398188,  0.55885409,  0.25925245,  0.4151012 ],
       [ 0.28352508,  0.69313792,  0.44045372,  0.15686774,  0.54464902]])

 b 

array([ 0.78031476,  0.30636353,  0.22195788,  0.38797126,  0.93638365])
In [8]:
%run Ejercicio3.py
-------------TRIANGULARIZACIÓN-------------

 U
array([[ 2.        ,  1.        ,  1.        ],
       [ 0.        ,  1.5       ,  0.5       ],
       [ 0.        ,  0.        ,  1.33333333]])

 c
array([ 2.,  3.,  4.])

------------- Sistema 1 -------------

 x
array([-1.,  1.,  3.])

 Ax
array([ 2.,  4.,  6.])

 b
array([ 2.,  4.,  6.])

------------- Sistema 2 -------------

 x
array([ 0.94759503,  2.02175037,  0.70006481,  1.30635509, -2.28937578])

 Ax
array([ 0.78031476,  0.30636353,  0.22195788,  0.38797126,  0.93638365])

 b
array([ 0.78031476,  0.30636353,  0.22195788,  0.38797126,  0.93638365])

Factorización LU

Expresaremos $A$ como el producto de dos matrices: una matriz triangular inferior, $L$, y una matriz triangular superior, $U$,

$$ A=LU. $$

Si tenemos el sistema

$$ A\mathbf{x}=\mathbf{b}, $$

donde $A$ admite la factorización $LU$

$$ A\mathbf{x}=\mathbf{b}\Longleftrightarrow LU\mathbf{x}=\mathbf{b} $$

Una vez factorizada la matriz $A$ solucionaremos el sistem $Ax=b$ en dos pasos

  • Resolver $L\mathbf{y}=\mathbf{b}$, con sustitución progresiva para obtener $\mathbf{y}$.
  • Resolver $U\mathbf{x}=\mathbf{y}$, con sustitución regresiva para obtener $\mathbf{x}$.

De momento, no estamos considerando el intercambio de filas.


Ejercicio 4

Usar la factorización $LU$ de $A$ para resolver el sistem $Ax=b$, donde

$$ A=\left(\begin{array}{rrr} 2 & 1 & 1\\ 1 & 2 & 2\\ 1 & 1 & 2 \end{array}\right)\quad\quad b=\left(\begin{array}{c} 2\\ 4\\ 6 \end{array}\right) $$
  • Crear la función LU(A) que da la factorización $LU$ de $A$.
  • Obtener y escribir las matrices $L$ y $U$.
  • Usar las funciones sust_regre y sust_prog para resolver los sistemas resultantes.
  • Comprobar la solución calculando $Ax$ y comparándolo con $b$.
  • Comprobar que la función funciona bien con el sistema $Ax=b$ cuyas matrices $A$ y $b$ se generan de la forma siguiente
In [9]:
n = 5
np.random.seed(4)           # for the random numbers to be repeatable
A = np.random.random((n,n)) # generate a random nxn matrix
b = np.random.random((n,))  # generate a random vector of dimension n

print '\n A \n'
pprint.pprint(A)
print '\n b \n' 
pprint.pprint(b)
 A 

array([[ 0.96702984,  0.54723225,  0.97268436,  0.71481599,  0.69772882],
       [ 0.2160895 ,  0.97627445,  0.00623026,  0.25298236,  0.43479153],
       [ 0.77938292,  0.19768507,  0.86299324,  0.98340068,  0.16384224],
       [ 0.59733394,  0.0089861 ,  0.38657128,  0.04416006,  0.95665297],
       [ 0.43614665,  0.94897731,  0.78630599,  0.8662893 ,  0.17316542]])

 b 

array([ 0.07494859,  0.60074272,  0.16797218,  0.73338017,  0.40844386])
In [10]:
%run Ejercicio4.py
U 

array([[ 2.        ,  1.        ,  1.        ],
       [ 0.        ,  1.5       ,  0.5       ],
       [ 0.        ,  0.        ,  1.33333333]])
L 

array([[ 1.        ,  0.        ,  0.        ],
       [ 0.5       ,  1.        ,  0.        ],
       [ 0.5       ,  0.33333333,  1.        ]])

------------- Sistema 1 -------------

 x
array([-1.,  1.,  3.])

 Ax
array([ 2.,  4.,  6.])

 b
array([ 2.,  4.,  6.])

------------- Sistema 2 -------------

 x
array([ 2.72783402,  0.59462753, -2.25221917,  0.34238196, -0.70146043])

 Ux
array([ 0.52790882,  0.93757158,  0.52169612,  0.10819338,  0.15822341])

 b
array([ 0.52790882,  0.93757158,  0.52169612,  0.10819338,  0.15822341])

Métodos iterativos

Los métodos iterativos son, en general, más eficientes que los métodos directos para resolver sistemas de ecuaciones lineales poco densos (con muchos elementos de la matriz de coeficientes igual a cero).

Reescribimos el sistema

$$ A\mathbf{x}=\mathbf{b}\Longleftrightarrow\mathbf{x}=B\mathbf{x}+\mathbf{c} $$

donde $B$ es una matriz de orden $n$ y $c$ es un vector columna de dimensión $n$.

Entonces, si $\mathbf{x}^{(0)}$ es el punto inicial, para $k=1,2,\ldots$

$$ \mathbf{x}^{(k)}=B\mathbf{x}^{(k-1)}+\mathbf{c} $$

Método de Jacobi

Algoritmo

  • Elegir un punto inicial $\mathbf{x}^{(0)}$
  • Para $k=1,2,\ldots,MaxIter$
    • Para $i=1,2,\ldots,n$ calcular $$ x_{i}^{(k)}=\frac{1}{a_{ii}}(b_{i}-\sum_{j=1}^{i-1}a_{ij}x_{j}^{(k-1)}-\sum_{j=i+1}^{n}a_{ij}x_{j}^{(k-1)}) $$
    • Si se cumple el criterio de parada, tomar $\mathbf{x}^{(k)}$ como solución aproximada.

Ejercicio 5

Escribir una jacobi(A,b,tol) para resolver $Ax=b$ por el método de Jacobi.

  • Resolver $$ \begin{cases} 5x_{1}+x_{2}-x_{3}-x_{4} & =1\\ x_{1}+4x_{2}-x_{3}+x_{4} & =1\\ x_{1}+x_{2}-5x_{3}-x_{4} & =1\\ x_{1}+x_{2}+x_{3}-4x_{4} & =1 \end{cases} $$ por el método de Jacobi, usando una tolerancia absoluta tol = 1.e-6 con norma 2. Es decir, usaremos como criterio de parad np.linalg.norm(x-xant) < tol, con x la solución aproximada en esta iteración y xant la solución aproximada en la iteración anterior. Tomar como punto inicial $\mathbf{x^{(0)}=0}.$
  • Como argumento de salida, dar la solución x y el número de iteraciones num_iter.
  • Comprobar que la solución es correcta comparándola con xs = np.linalg.solve(A,b).
  • Comprobar que también funciona correctamente para resolver el sistema $Ax=b$ de matrices $A$ y $b$ generadas de la forma siguiente
In [11]:
n = 5
np.random.seed(5)         
A = np.random.random((n,n)) + 2*np.eye(n) 
b = np.random.random((n,))  

print '\n A \n'
pprint.pprint(A)
print '\n b \n' 
pprint.pprint(b)
 A 

array([[ 2.22199317,  0.87073231,  0.20671916,  0.91861091,  0.48841119],
       [ 0.61174386,  2.76590786,  0.51841799,  0.2968005 ,  0.18772123],
       [ 0.08074127,  0.7384403 ,  2.44130922,  0.15830987,  0.87993703],
       [ 0.27408646,  0.41423502,  0.29607993,  2.62878791,  0.57983781],
       [ 0.5999292 ,  0.26581912,  0.28468588,  0.25358821,  2.32756395]])

 b 

array([ 0.1441643 ,  0.16561286,  0.96393053,  0.96022672,  0.18841466])
In [12]:
%run Ejercicio5.py
------------- Sistema 1 -------------

num_iter =  17

x 
array([ 0.09374986,  0.24999988, -0.09374986, -0.18749994])

xs 
array([ 0.09375,  0.25   , -0.09375, -0.1875 ])

------------- Sistema 2 -------------

num_iter =  40

x 
array([-0.10353572, -0.02483661,  0.37396675,  0.33155212,  0.02860954])

xs 
array([-0.1035359 , -0.02483673,  0.37396662,  0.33155201,  0.02860942])

Método de Gauss-Seidel

Algoritmo

  • Elegir el punto inicial $\mathbf{x}^{(0)}$
  • Para $k=1,2,\ldots,MaxIter$
    • Para $i=1,2,\ldots,n$ calcular $$ x_{i}^{(k)}=\frac{1}{a_{ii}}(b_{i}-\sum_{j=1}^{i-1}a_{ij}x_{j}^{(k)}-\sum_{j=i+1}^{n}a_{ij}x_{j}^{(k-1)}) $$
    • Si se satisface el criterio de parada, tomar $\mathbf{x}^{(k)}$ como solución aproximada

Ejercicio 6

Escribir una función gauss_seidel(A,b,tol) para resolver $Ax=b$ por el método de Gauss-Seidel.

  • Resolver los mismos sistemas del ejercicio anterior usando Gauss-Seidel con la misma tolerancia y criterio de parada.
  • Escribir las mismos argumentos de salida que en el ejercicio anterior y comparar el número de iteraciones.
In [13]:
%run Ejercicio6.py
------------- Sistema 1 -------------

num_iter =  7

x 
array([ 0.09375005,  0.24999998, -0.09375003, -0.1875    ])

xs 
array([ 0.09375,  0.25   , -0.09375, -0.1875 ])

------------- Sistema 2 -------------

num_iter =  9

x 
array([-0.10353581, -0.02483669,  0.37396662,  0.331552  ,  0.02860939])

xs 
array([-0.1035359 , -0.02483673,  0.37396662,  0.33155201,  0.02860942])