Está en la página 1de 12

Programación Para Ciencia y Tecnología (PPCT)

Práctica 1: Sistemas de Ecuaciones


Lineales

Curso 2022/23

En esta práctica se debe completar el fichero prac1.py, que inicialmente contiene solo
algunas funciones auxiliares que utilizaremos. Tras hacer la práctica, se espera que el fichero
contenga las funciones que se pide hacer en los distintos ejercicios. Como con el resto de
prácticas, el fichero se usará en algunas de las pruebas de evaluación de la asignatura, por lo
que solo debes escribir en él las funciones que se pide implementar en este boletín, sin otras
anotaciones o aclaraciones.

1. Objetivos
El objetivo de esta práctica es implementar y aplicar métodos para resolver sistemas de
ecuaciones lineales y calcular inversas de matrices, así como conocer las herramientas que
para ello nos proporciona el paquete scipy.linalg.
En primer lugar, utilizaremos las herramientas que nos proporciona el paquete scipy.linalg
para trabajar con sistemas de ecuaciones lineales. A continuación, replicaremos parte de la
funcionalidad de dicho paquete, desarrollando y utilizando nuestras propias funciones para:
Resolver sistemas triangulares, tanto inferiores como superiores.

Calcular la descomposición LU con pivotación de una matriz.

Resolver sistemas lineales generales, usando la descomposición LU y la resolución de


sistemas triangulares.

Resolver sistemas lineales cuya matriz es simétrica y definida positiva, usando la des-
composición de Cholesky y la resolución de sistemas triangulares.
Por último, se podrá comprobar que no todos los sistemas lineales se pueden resolver.

1
2. Entorno de trabajo de las prácticas
Utilizaremos el entorno Spyder para las prácticas de la asignatura, así como las librerías
numpy y scipy. Aunque seguramente ya conoces numpy, revisaremos aquí los aspectos básicos
de la librería, que necesitaremos utilizar en las diferentes prácticas.

2.1. La librería numpy


En todas las prácticas de la asignatura utilizaremos la librería numpy, por lo que será
preciso hacer el import correspondiente:
import numpy as np

numpy permite trabajar con arrays multidimensionales, que nos servirán para representar
matrices y vectores. Se pueden crear arrays a partir de la lista de sus elementos, utilizando
listas anidadas si el array tiene dos o más dimensiones. Por ejemplo, las siguientes órdenes
definen un vector b y una matriz A (la marca >>> al principio de una línea indica que se trata
de una orden que escribimos en una terminal de Python; el resto de líneas son la respuesta
que obtenemos de Python):
>>> b = np.array([3,2,1]) nº enteros
>>> b
array([3, 2, 1])
>>> x = np.array([3.,2,1]) nº reales
>>> x
array([3., 2., 1.])
>>> A = np.array([[1,2],[3,4]],dtype='float')
>>> A nº reales
array([[1., 2.],
[3., 4.]])

Observa que hay una sutil diferencia entre los vectores b y x: el vector x contiene números
reales (se muestran con un punto decimal), mientras que el vector b contiene números enteros.
Esto es así porque, al construir x, hemos puesto punto decimal en uno de los elementos. Otra
forma de forzar que el array sea de números reales es añadir el argumento dtype='float'
de np.array, como se ha hecho al definir la matriz A.
La función np.zeros permite crear matrices o vectores de determinado tamaño cuyos
elementos valgan cero. La función np.ones es similar, pero con elementos igual a uno. En
ambos casos, serán números reales por defecto:
>>> np.zeros((2,3))
array([[0., 0., 0.],
[0., 0., 0.]])
>>> np.zeros(4) nº reales
por defecto
array([0., 0., 0., 0.])
>>> np.ones(3)*5
array([5., 5., 5.])

2
También podemos crear una matriz identidad con la función np.eye:
>>> np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])

Los operadores aritméticos básicos se pueden aplicar sobre arrays:


>>> A=np.array([[1,2,3],[4,5,6]])
>>> A+1
array([[2, 3, 4], +1 a cada elemento
[5, 6, 7]])
>>> A*3
array([[ 3, 6, 9], x3 cada elemento
[12, 15, 18]])
>>> B=np.array([[1,1,1],[2,2,2]])
>>> A+B
array([[2, 3, 4], suma matrices
[6, 7, 8]])
>>> A*B
array([[ 1, 2, 3], multiplicación elemento a elemento
[ 8, 10, 12]])

Hay que tener en cuenta que el operador * no corresponde a la multiplicación matricial, sino a
la multiplicación elemento a elemento. Para la multiplicación matricial se utiliza el operador
@:
>>> A=np.array([[1,2,3],[4,5,6]])
>>> B=np.array([[1,2],[1,2],[1,2]])
>>> A@B multiplicación matricial
array([[ 6, 12],
[15, 30]])

La operación de transposición se puede obtener mediante la propiedad T del array:


>>> A=np.array([[1,2,3],[4,5,6]])
>>> A.T traspuesta
array([[1, 4],
[2, 5],
[3, 6]])

Podemos obtener el número de filas y columnas de una matriz mediante la propiedad shape
del array. En general, shape devuelve una tupla de enteros que indican el número de elementos
correspondientes a cada dimensión del array:
>>> A=np.array([[1,2,3],[4,5,6]])
>>> b=np.array([1,2,3,4])

3
>>> A.shape (nº filas, nº columnas)
(2, 3)
>>> b.shape
(4,)
La propiedad size de un array devuelve el número de elementos del mismo (producto de los
elementos de shape). Por ejemplo, para los arrays A, b, anteriores:
>>> A.size
nº elementos
6
>>> b.size
4
Podemos acceder a elementos individuales o a secciones/bloques de vectores y matrices uti-
lizando índices, como haríamos con listas Python:
>>> b=np.array([1,2,3,4])
>>> b[0:2] pos 0 a pos 1
array([1, 2])
>>> b[-1] última posición
4
>>> A=np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> A[0,2] elemento de la fila 0, columna 2
3
>>> A[0:2,:] filas --> de la 0 a la 1
array([[1, 2, 3], columnas --> todas
[4, 5, 6]])
Finalmente, disponemos de distintas funciones para calcular sumas, máximos, mínimos, etc.
Por ejemplo, con la variable A anterior:
>>> A.sum()
suma de todos los elementos de A
45
>>> A[:,0].sum() suma de 'algunos' elementos de A
12
>>> b=np.array([1,2,3])
>>> np.sum(A[0,:]*b) suma del resultado de esa operación
14
>>> A.min()
1
>>> A.max()
9

3. Resolución de sistemas de ecuaciones con scipy.linalg


El subpaquete linalg de scipy contiene funciones para resolver problemas de álgebra
lineal, entre los cuales se encuentran los sistemas de ecuaciones lineales, de los que nos
ocupamos en esta práctica. Lo importamos mediante la orden:

4
from scipy import linalg

Podemos resolver un sistema lineal fácilmente usando la función linalg.solve. Por ejemplo,
dado el sistema de ecuaciones:
2x1 + 8x2 + 6x3 = 36
x1 − 3x2 + 5x3 = 10
−6x1 + 2x2 + 7x3 = 19

podemos introducir el sistema y resolverlo de esta manera:


>>> A=np.array([[2,8,6],[1,-3,5],[-6,2,7]])
>>> b=np.array([36,10,19])
>>> linalg.solve(A,b)
array([1., 2., 3.])

También podemos calcular la inversa de una matriz, con la función linalg.inv, o su deter-
minante, mediante la función linalg.det. Por ejemplo, para la matriz del sistema anterior:
>>> linalg.inv(A)
array([[ 0.06828194, 0.0969163 , -0.1277533 ],
[ 0.0814978 , -0.11013216, 0.00881057],
[ 0.03524229, 0.11453744, 0.030837 ]])
>>> linalg.det(A)
-454.0

Las funciones presentadas en este apartado se basan en la descomposición de la matriz en


producto de matrices triangulares. Por defecto se usa la descomposición LU, pero la función
linalg.solve permite especificar si la matriz es simétrica y definida positiva, en cuyo caso
se usa la descomposición de Cholesky.

Ejercicio 1.
Resuelve el sistema A1 x = b1, donde
   
4 3 1 1.5
A1 = −2 7 3, b1 = −1.5 .
  

5 −6 −9 −3.5

Comprueba que A1 x − b1 es un vector de elementos muy cercanos a cero.

Ejercicio 2.
Calcula el determinante y la inversa de la matriz A1 usando las funciones correspon-
dientes de linalg.

5
4. Resolución de sistemas triangulares
Una de las tareas que debe hacer la función linalg.solve es resolver sistemas triangu-
lares. En este apartado se pide que hagas tus propias funciones para ello.
Empezaremos por los sistemas triangulares superiores. Como se ha visto en las clases de
teoría, este tipo de sistemas se puede resolver mediante el método de sustitución inversa o
regresiva (ver Algoritmo 1), que aplica la fórmula:
n
X
bi − aij xj
j=i+1
xi = , i = n, n − 1, · · · , 1
aii

Algoritmo 1: sustitucion_inversa
Entrada: A: matriz del sistema lineal, triangular superior
b: vector de términos independientes
Resultado: x: solución del sistema
1 para i ∈ invertido(rango(n)) hacer
2 s=0
3 para j ∈ rango(i + 1, n) hacer
4 s = s + aij xj
5 fin para
6 si aii = 0 entonces
7 error: el sistema no se puede resolver
8 fin si
bi − s
9 xi =
aii
10 fin para

Ejercicio 3.
Implementa una función, llamada sustitucion_inversa, para resolver un sistema
triangular superior. Si alguno de los elementos de la diagonal de la matriz es igual a cero,
se debe generar una excepción.
A continuación, utiliza la función para resolver el sistema A2 x = b2, siendo:
   
9 3 −2 −64
A2 = 0 −6 4  , b2 =  38  .
   

0 0 7 56

Comprueba que el resultado es el mismo que el que se obtiene con linalg.solve.

6
En el caso de sistemas triangulares inferiores, se utiliza el método de sustitución directa
o progresiva, que como sabemos aplica la fórmula:
i−1
X
bi − aij xj
j=1
xi = , i = 1, 2, · · · , n
aii

Ejercicio 4.
Implementa una función, llamada sustitucion_directa, para resolver sistemas trian-
gulares inferiores, con los siguientes datos de entrada y resultados:
Entrada: A: matriz del sistema lineal, triangular inferior
b: vector de términos independientes
Resultado: x: solución del sistema

Si alguno de los elementos de la diagonal de la matriz es igual a cero, se debe generar


una excepción.
A continuación, utiliza la función para resolver el sistema A3 x = b3, siendo:
   
3 0 0 6
A3 = 5 1 0  , b3 = 14 .
   

9 4 −8 26

Comprueba que el resultado coincide con el de linalg.solve.

5. Descomposición LU con pivotación parcial


La función linalg.lu calcula la descomposición LU con pivotación parcial de una matriz.
Dada una matriz A, la función devuelve las matrices P (de permutación), L (triangular
inferior unidad) y U (triangular superior), tales que:

A = P LU.

Observa que esta forma de la descomposición es ligeramente distinta de la que vemos en


clase de teoría, donde tenemos que P A = LU . Ambas formas son válidas, siendo la matriz P
de un caso la transpuesta de la del otro caso.

Ejercicio 5.
Utiliza la función linalg.lu para calcular la descomposición LU con pivotación de
la matriz A1 (del ejercicio 1). Comprueba que se cumple la igualdad correspondiente a
la descomposición.

7
El siguiente ejercicio consiste en hacer nuestra propia implementación de la función lu,
de acuerdo con el algoritmo visto en las clases de teoría (Algoritmo 2).

Algoritmo 2: lu
Entrada: A: matriz a descomponer, de n filas y n columnas
Resultado: P, L, U , tales que P A = LU
1 hacer una copia de A para no modificar la matriz de entrada
2 P =I
3 para k ∈ rango(n − 1) hacer
4 s = busca_posmax(A, k)
5 si s ̸= k entonces
6 cambiofila(A, P, k, s)
7 fin si
8 si akk ̸= 0 entonces
9 para i ∈ rango(k + 1, n) hacer
aik
10 α=
akk
11 aik = α
12 para j ∈ rango(k + 1, n) hacer
13 aij = aij − αakj
14 fin para
15 fin para
16 fin si
17 fin para
18 L =parte triangular inferior estricta de A, con unos en la diagonal
19 U =parte triangular superior de A

Comentaremos a continuación cómo hacer algunas de las operaciones del algoritmo ante-
rior:

La función empezará haciendo una copia de la matriz A, sobre la cual trabajará, para
no modificar la matriz de entrada. Podemos hacerlo de la siguiente manera:
A=np.array(A,dtype='float')

Añadimos el argumento dtype='float' para asegurarnos de que la matriz resultante


contiene números reales, incluso si la matriz inicial fuera de enteros.

Podemos construir una matriz identidad para la matriz P con la función np.eye. Por
ejemplo:

8
>>> np.eye(4)
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])

Las funciones busca_posmax y cambiofila se proporcionan como material de la prác-


tica en el fichero prac1.py.

Podemos obtener la parte triangular inferior de una matriz mediante la función np.tril,
y la triangular superior mediante np.triu:
>>> M=np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> np.tril(M)
array([[1, 0, 0],
[4, 5, 0],
[7, 8, 9]])
>>> np.triu(M)
array([[1, 2, 3],
[0, 5, 6],
[0, 0, 9]])

Para obtener la parte triangular inferior estricta (sin la diagonal):


>>> np.tril(M,-1) inferior sin la diagonal
array([[0, 0, 0],
[4, 0, 0],
[7, 8, 0]])

donde el argumento −1 indica que se quiere tomar desde la primera subdiagonal infe-
rior. Si queremos que la diagonal esté formada por unos, podemos sumarle una matriz
identidad:
>>> np.tril(M,-1)+np.eye(3) triangular inferior con diagonal de 1s
array([[1., 0., 0.],
[4., 1., 0.],
[7., 8., 1.]])

Ejercicio 6.
Implementa una función, llamada lu, que calcule la descomposición LU con pivotación
parcial de una matriz, de acuerdo con el Algoritmo 2.
A continuación, utiliza dicha función para calcular la descomposición LU con pivota-
ción de la matriz A1 (ejercicio 1). Comprueba que se cumple la igualdad correspondiente
a la descomposición. Observa que la matriz P obtenida con nuestra función lu es la

9
transpuesta de la que se obtiene con la función linalg.lu, mientras que la L y la U
coinciden.

Ejercicio 7.
Obtén ahora la descomposición de estas dos matrices:
   
1 1 1 1 0.7 5
A4 = −2 −2 −2 , A5 = −2 −1.4 −8 .
   

1 2 3 10 7 7

Observa la diagonal de U que se obtiene al calcular la descomposición de las matrices


A4 y A5. ¿Qué nos dice eso sobre los determinantes de esas matrices? ¿Tienen inversa
esas matrices?

Ejercicio 8.
Escribe una función, con el nombre resuelve, con los siguientes datos de entrada y
resultados, que resuelva un sistema de ecuaciones lineales mediante la descomposición
LU con pivotación de la matriz del sistema:
Entrada: A: matriz del sistema lineal
b: vector de términos independientes
Resultado: x: solución del sistema

Para la descomposición, utiliza la función lu que has implementado en el ejercicio 6.


A continuación, resuelve el sistema A1 x = b1, donde A1 y b1 son los del ejercicio 1.
Comprueba que el resultado es correcto comparándolo con el resultado obtenido al usar
linalg.solve.

Ejercicio 9.
Trata ahora de resolver los sistemas siguientes mediante la función resuelve:
 
3
a) A4 x = b4, siendo b4 = 2 .
 

6
¿Qué crees que puede estar ocurriendo?
 
−5
b) A5 x = b5, siendo b5 =  4 .
 

−9
¿Es correcta la solución proporcionada? (calcula el resultado de la operación A5 x−b5).
¿A qué crees que es debido? ¿Evitamos el problema si resolvemos el sistema con la

10
función linalg.solve?

6. Descomposición de Cholesky para matrices simétri-


cas y definidas positivas
La función cholesky de linalg calcula la descomposición de Cholesky para matrices
simétricas y definidas positivas. La función recibe la matriz a descomponer como dato de
entrada y devuelve una matriz U , triangular superior, tal que

A = U T U.

Alternativamente, si se añade el argumento lower=True, la función devolverá la matriz


U transpuesta, es decir, una matriz G, triangular inferior, tal que

A = GGT .

Ejercicio 10.
Utiliza la función linalg.cholesky para obtener la matriz G de la descomposición
de la siguiente matriz. Comprueba que se cumple la igualdad anterior.
 
9 15 27
A6 = 15 26 49 
 

27 49 161

Ejercicio 11.
Escribe una función, con el nombre resuelve_simpos y los siguientes datos de entrada
y resultados, que resuelva un sistema de ecuaciones cuya matriz es simétrica y definida
positiva, mediante la descomposición de Cholesky.
Entrada: A: matriz del sistema lineal, simétrica y definida positiva
b: vector de términos independientes
Resultado: x: solución del sistema

A continuación, utiliza la función para resolver el sistema A6 x = b6, donde


 
3
b6 =  7  .
 

17

Comprueba que se obtiene el mismo resultado que al usar la función resuelve o la


función linalg.solve.

11
12

También podría gustarte