3.9.2 Método de Gauss-Jordan para matriz Inversa con Python



1. Ejercicio

Referencia: Chapra 10.2 p292, Burden 6.3 p292, Rodríguez 4.2.5 Ejemplo 1 p118

Obtener la inversa de una matriz usando el método de Gauss-Jordan, a partir de la matriz:

\begin{pmatrix} 4 & 2 & 5 \\ 2 & 5 & 8 \\ 5 & 4 & 3 \end{pmatrix}
A = [[4,2,5],
     [2,5,8],
     [5,4,3]]


2. Desarrollo analítico

Para el procedimiento, se crea la matriz aumentada de A con la identidad I.

AI = A|I \begin{pmatrix} 4 & 2 & 5 & 1 & 0 & 0\\ 2 & 5 & 8 & 0 & 1 & 0 \\ 5 & 4 & 3 & 0 & 0 & 1 \end{pmatrix}
[[  4.,    2.,    5.,   1.,    0.,    0., ]
 [  2.,    5.,    8.,   0.,    1.,    0., ]
 [  5.,    4.,    3.,   0.,    0.,    1., ]]

Con la matriz aumentada AI  se repiten los procedimientos aplicados en el método de Gauss-Jordan:

  • pivoteo parcial por filas
  • eliminación hacia adelante
  • eliminación hacia atrás

De la matriz aumentada resultante, se obtiene la inversa A-1 en la mitad derecha de AI, lugar que originalmente correspondía a la identidad.

el resultado buscado es:

la matriz inversa es:
[[ 0.2        -0.16470588  0.10588235]
 [-0.4         0.15294118  0.25882353]
 [ 0.2         0.07058824 -0.18823529]]
\begin{pmatrix} 0.2 & -0.16470588 & 0.10588235 \\ -0.4 & 0.15294118 & 0.25882353 \\ 0.2 & 0.07058824 & -0.18823529 \end{pmatrix}

Verifica resultado

El resultado se verifica realizando la operación producto punto entre A y la inversa, que debe resultar la matriz identidad.

A.A-1 = I

El resultado de la operación es una matriz identidad. Observe que los valores del orden de 10-15 o menores se consideran como casi cero o cero.

 A.inversa = identidad
[[ 1.00000000e+00 -1.38777878e-17 -1.38777878e-16]
 [ 2.22044605e-16  1.00000000e+00 -2.22044605e-16]
 [ 5.55111512e-17 -9.71445147e-17  1.00000000e+00]]


3. Algoritmo en Python

El algoritmo que describe el proceso en python:

# Matriz Inversa con Gauss-Jordan
# AI es la matriz aumentada A con Identidad
import numpy as np

# INGRESO
A = [[4,2,5],
[2,5,8],
[5,4,3]]

# PROCEDIMIENTO
# B = matriz_identidad
n,m = np.shape(A)
identidad = np.identity(n)

np.set_printoptions(precision=4) # 4 decimales en print
casicero = 1e-15 # redondear a cero

# Matrices como arreglo, numeros reales
A = np.array(A,dtype=float)
B = np.array(identidad,dtype=float)

def pivoteafila(A,B,vertabla=False):
'''
Pivoteo parcial por filas, entrega matriz aumentada AB
Si hay ceros en diagonal es matriz singular,
Tarea: Revisar si diagonal tiene ceros
'''

A = np.array(A,dtype=float)
B = np.array(B,dtype=float)
# Matriz aumentada
nB = len(np.shape(B))
if nB == 1:
B = np.transpose([B])
AB = np.concatenate((A,B),axis=1)

if vertabla==True:
print('Matriz aumentada')
print(AB)
print('Pivoteo parcial:')

# Pivoteo por filas AB
tamano = np.shape(AB)
n = tamano[0]
m = tamano[1]

# Para cada fila en AB
pivoteado = 0
for i in range(0,n-1,1):
# columna desde diagonal i en adelante
columna = np.abs(AB[i:,i])
dondemax = np.argmax(columna)

# dondemax no es en diagonal
if (dondemax != 0):
# intercambia filas
temporal = np.copy(AB[i,:])
AB[i,:] = AB[dondemax+i,:]
AB[dondemax+i,:] = temporal

pivoteado = pivoteado + 1
if vertabla==True:
print(' ',pivoteado,
'intercambiar filas: ',i,
'con', dondemax+i)
if vertabla==True:
if pivoteado==0:
print(' Pivoteo por filas NO requerido')
else:
print(AB)
return(AB)

def gauss_eliminaAdelante(AB,vertabla=False,
lu=False,casicero = 1e-15):
''' Gauss elimina hacia adelante
tarea: verificar términos cero
'''

tamano = np.shape(AB)
n = tamano[0]
m = tamano[1]
if vertabla==True:
print('Elimina hacia adelante:')
for i in range(0,n,1):
pivote = AB[i,i]
adelante = i+1
if vertabla==True:
print(' fila i:',i,' pivote:', pivote)
for k in range(adelante,n,1):
if (np.abs(pivote)>=casicero):
factor = AB[k,i]/pivote
AB[k,:] = AB[k,:] - factor*AB[i,:]
for j in range(0,m,1): # casicero revisa
if abs(AB[k,j])<casicero:
AB[k,j]=0
if vertabla==True:
print(' fila k:',k,
' factor:',factor)
else:
print(' pivote:', pivote,'en fila:',i,
'genera division para cero')
if vertabla==True:
print(AB)
respuesta = np.copy(AB)
if lu==True: # matriz triangular A=L.U
U = AB[:,:n-1]
respuesta = [AB,L,U]
return(respuesta)

def gauss_eliminaAtras(AB, vertabla=False,
inversa=False,
casicero = 1e-14):
''' Gauss-Jordan elimina hacia atras
Requiere la matriz triangular inferior
Tarea: Verificar que sea triangular inferior
'''

tamano = np.shape(AB)
n = tamano[0]
m = tamano[1]

ultfila = n-1
ultcolumna = m-1
if vertabla==True:
print('Elimina hacia Atras:')

for i in range(ultfila,0-1,-1):
pivote = AB[i,i]
atras = i-1 # arriba de la fila i
if vertabla==True:
print(' fila i:',i,' pivote:', pivote)

for k in range(atras,0-1,-1):
if np.abs(AB[k,i])>=casicero:
factor = AB[k,i]/pivote
AB[k,:] = AB[k,:] - factor*AB[i,:]

# redondeo a cero
for j in range(0,m,1):
if np.abs(AB[k,j])<=casicero:
AB[k,j]=0
if vertabla==True:
print(' fila k:',k,
' factor:',factor)
else:
print(' pivote:', pivote,'en fila:',i,
'genera division para cero')
AB[i,:] = AB[i,:]/AB[i,i] # diagonal a unos

if vertabla==True:
print(AB)

respuesta = np.copy(AB[:,ultcolumna])
if inversa==True: # matriz inversa
respuesta = np.copy(AB[:,n:])
return(respuesta)

AB = pivoteafila(A,identidad,vertabla=True)
AB = gauss_eliminaAdelante(AB,vertabla=True)
A_inversa = gauss_eliminaAtras(AB,inversa=True,
vertabla=True)
A_verifica = np.dot(A,A_inversa)
# redondeo a cero
for i in range(0,n,1):
for j in range(0,m,1):
if np.abs(A_verifica[i,j])<=casicero:
A_verifica[i,j]=0

# SALIDA
print('A_inversa: ')
print(A_inversa)
print('verifica A.A_inversa = Identidad:')
print(A_verifica)

el resultado buscado es:

Matriz aumentada
[[4. 2. 5. 1. 0. 0.]
 [2. 5. 8. 0. 1. 0.]
 [5. 4. 3. 0. 0. 1.]]
Pivoteo parcial:
  1 intercambiar filas:  0 con 2
[[5. 4. 3. 0. 0. 1.]
 [2. 5. 8. 0. 1. 0.]
 [4. 2. 5. 1. 0. 0.]]
Elimina hacia adelante:
 fila i: 0  pivote: 5.0
  fila k: 1  factor: 0.4
  fila k: 2  factor: 0.8
[[ 5.   4.   3.   0.   0.   1. ]
 [ 0.   3.4  6.8  0.   1.  -0.4]
 [ 0.  -1.2  2.6  1.   0.  -0.8]]
 fila i: 1  pivote: 3.4
  fila k: 2  factor: -0.3529411764705883
[[ 5.      4.      3.      0.      0.      1.    ]
 [ 0.      3.4     6.8     0.      1.     -0.4   ]
 [ 0.      0.      5.      1.      0.3529 -0.9412]]
 fila i: 2  pivote: 5.0
[[ 5.      4.      3.      0.      0.      1.    ]
 [ 0.      3.4     6.8     0.      1.     -0.4   ]
 [ 0.      0.      5.      1.      0.3529 -0.9412]]
Elimina hacia Atras:
 fila i: 2  pivote: 5.0
  fila k: 1  factor: 1.3599999999999999
  fila k: 0  factor: 0.6
[[ 5.      4.      0.     -0.6    -0.2118  1.5647]
 [ 0.      3.4     0.     -1.36    0.52    0.88  ]
 [ 0.      0.      1.      0.2     0.0706 -0.1882]]
 fila i: 1  pivote: 3.4
  fila k: 0  factor: 1.1764705882352942
[[ 5.      0.      0.      1.     -0.8235  0.5294]
 [ 0.      1.      0.     -0.4     0.1529  0.2588]
 [ 0.      0.      1.      0.2     0.0706 -0.1882]]
 fila i: 0  pivote: 5.0
[[ 1.      0.      0.      0.2    -0.1647  0.1059]
 [ 0.      1.      0.     -0.4     0.1529  0.2588]
 [ 0.      0.      1.      0.2     0.0706 -0.1882]]
A_inversa: 
[[ 0.2    -0.1647  0.1059]
 [-0.4     0.1529  0.2588]
 [ 0.2     0.0706 -0.1882]]
verifica A.A_inversa = Identidad:
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

Observe que el algoritmo se pude reducir si usan los procesos de Gauss-Jordan como funciones.

Tarea: Realizar el algoritmo usando una función creada para Gauss-Jordan



4. Función en librería Numpy

La función en la librería Numpy es np.linalg.inv():

>>> np.linalg.inv(A)
array([[ 0.2       , -0.16470588,  0.10588235],
       [-0.4       ,  0.15294118,  0.25882353],
       [ 0.2       ,  0.07058824, -0.18823529]])
>>> 



Unidades