3.4 Método de Gauss-Jordan con Python

[ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
..


1. Método de Gauss-Jordan

Referencia: Chapra 9.7 p277, Burden 9Ed Ex6.1.12 p370, Rodríguez 4.2 p106

El método de Gauss-Jordan presenta un procedimiento alterno al de "sustitución hacia atrás" realizado para el método de Gauss. Luego de obtener la "matriz triangular superior", aplica el procedimiento de "Eliminación hacia atrás".

\left( \begin{array}{rrr|r} a_{0,0} & a_{0,1} & a_{0,2} & b_{0} \\ 0 & a_{1,1} & a_{1,2} & b_{1} \\ 0 & 0 & a_{2,2} & b_{2} \end{array} \right)
  • Eliminación hacia atrás

Eliminación hacia atras grafico animadoDesde la última fila,
para i = n-1, n-2, ...
sobre las filas k = i-1 superiores

a_{k} = a_{k} -a_{i}\frac{a_{ki}}{a_{ii}}

Se mantienen al inicio los procedimientos para:
matriz aumentada,
pivoteo parcial por filas,
eliminación hacia adelante desarrollados anteriormente.

[ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
..


2. Ejercicio

Referencia: Rodríguez 4.0 p105,  1Eva_IT2010_T3_MN Precio artículos

\begin{cases} 4x_1+2x_2+5x_3 = 60.70 \\ 2x_1+5x_2+8x_3 = 92.90 \\ 5x_1+4x_2+3x_3 = 56.30 \end{cases}

Matriz Diagonal superiorSe continúa con el ejercicio desarrollado para el método de Gauss desde la "matriz triangular superior",
luego de eliminación hacia adelante:

[[ 5.    4.    3.   56.3 ]
 [ 0.    3.4   6.8  70.38]
 [ 0.    0.    5.   40.5 ]]

[ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
..


3. Eliminación hacia atrás

El procedimiento es semejante al realizado para "eliminación hacia adelante", con la diferencia que se inicia en la última fila hacia la primera. Para el ejercicio presentado se tiene que:

utlfila = n-1 = 3-1 = 2
ultcolumna = m-1 = 4-1 = 3

iteración 1, operación fila 3 y 2

Se aplica desde la última fila i, para las otras filas k que se encuentran hacia atrás.Eliminación hacia Atras i=2,j=1

i = ultfila = 2
pivote = AB[2,2] = 5
k = i-1 # hacia atrás

se realizan las operaciones entre las filas i y la fila j

         [0.  3.4  6.8    70.38]
-(6.8/5)*[0.  0.   5.     40.5 ]
_______________________________
       = [0.0 3.4  8.8e-16 15.3]

para reemplazar los valores de la segunda fila en la matriz aumentada

[[5.0    4.0    3.0      56.3]
 [0.0    3.4    8.8e-16  15.3]
 [0.0    0.0    5.0      40.5]]

Observe que hay un valor muy pequeño del orden de 8.8x10-16, que para las otras magnitudes se puede considerar como casi cero.

iteración 2, operación fila 3 y 1

Se calculan los nuevos valores de índice kEliminacion hacia Atras i=2, j=0

k = k-1 = 2-1 = 1 # hacia atrás

se realizan las operaciones entre las filas i y la fila j

       [5.0    4.0    3.0    56.3]
-(3/5)*[0.0    0.0    5.0    40.5]
__________________________________
     = [5.0    4.0    0.0    32.0]

que al actualizar la matriz aumentada se tiene:

[[5.0    4.0    0.0      32.0]
 [0.0    3.4    8.8e-16  15.3]
 [0.0    0.0    5.0      40.5]]}

Al haber terminado las filas hacia arriba, Eliminacion hacia Atras i=2,j2, pivote=1
se puede así determinar el valor de x3 al dividir la fila 3 para el pivote

[[5.0    4.0    0.0      32.0]
 [0.0    3.4    8.8e-16  15.3]
 [0.0    0.0    1.0       8.1]]}

iteración 3, operación fila 2 y 1Eliminación hacia Atras i=1,j=0

se actualizan los valores de los índices:

i = i-1 = 2-1 = 1
k = i-1 = 1-1 = 0

se pueden realizar operaciones en una sola fila hacia atrás, por lo que el resultado hasta ahora es:

         [5.0    4.0    0.0     32.0]
-(4/3.4)*[0.0    3.4    8.8e-16 15.3]
__________________________________
       = [5.0    0.0   -1.04e-15 14.0]

[[ 5.0    0.0   -1.04e-15  14.0]
 [ 0.0    3.4    8.8e-16   15.3]
 [ 0.0    0.0    1.0        8.1]]

Eliminacion hacia Atras i=1,j=1, pivote=1

Se obtiene el valor de x2,
dividiendo para el valor del pivote,

[[ 5.0    0.0   -1.04e-15  14.0]
 [ 0.0    1.0    2.6e-16    4.5]
 [ 0.0    0.0    1.0        8.1]]

iteración 4, operación fila 1Eliminación hacia atras, pivote=1

No hay otras filas con las que iterar,
por lo que solo se obtiene el valor de x1 al dividir para el pivote.

[[ 1.0    0.0   -2.08e-15  2.8]
 [ 0.0    1.0    2.6e-16   4.5]
 [ 0.0    0.0    1.0       8.1]]

La solución del sistema de ecuaciones se presenta como una matriz identidad concatenada a un vector columna de constantes.

solución X: 
[2.8, 4.5, 8.1]
X= [2.8, 4.5 , 8.1 ]

Observación: en la matriz hay unos valores del orden de 10-16, que corresponden a errores de operaciones en computadora (truncamiento y redondeo) que pueden ser descartados por ser casi cero. Hay que establecer entonces un parámetro para controlar los casos en que la diferencia entre los ordenes de magnitud son por ejemplo menores a 15 ordenes de magnitud 10-15. e implementarlo en los algoritmos.

[ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
..


4. Algoritmo en Python

Esta sección reutiliza el algoritmo desarrollado para el Método de Gauss, por lo que los bloques de procedimiento son semejantes hasta eliminación hacia adelante. Se añade el procedimiento de eliminación hacia atrás para completar la solución al sistema de ecuaciones.

Instrucciones en Python

# Método de Gauss-Jordan
# Sistemas de Ecuaciones A.X=B
import numpy as np

# INGRESO
A = [[4,2,5],
     [2,5,8],
     [5,4,3]]
B = [60.70, 92.90, 56.30]

# PROCEDIMIENTO
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(B,dtype=float)

# Matriz aumentada AB
B_columna = np.transpose([B])
AB  = np.concatenate((A,B_columna),axis=1)

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

# Para cada fila en AB
for i in range(0,n-1,1):
    # columna desde diagonal i en adelante
    columna = abs(AB[i:,i])
    dondemax = np.argmax(columna)
    
    if (dondemax !=0): # NO en diagonal
        # intercambia filas
        temporal = np.copy(AB[i,:])
        AB[i,:]  = AB[dondemax+i,:]
        AB[dondemax+i,:] = temporal
print('Pivoteo parcial por filas AB: ----')
print(AB)

# Eliminación hacia adelante
print('Eliminación hacia adelante: ------')
for i in range(0,n-1,1): # una fila
    pivote   = AB[i,i]
    adelante = i + 1
    for k in range(adelante,n,1): # diagonal adelante
        factor  = AB[k,i]/pivote
        AB[k,:] = AB[k,:] - AB[i,:]*factor

        print('i:',i,'k:',k, 'factor:',factor)
    print(AB)

# Eliminación hacia atras
print('Eliminación hacia atras: ------')
ultfila = n-1
ultcolumna = m-1
for i in range(ultfila,0-1,-1): # una fila
    pivote   = AB[i,i]
    print('i:',i,' pivote:',pivote)
    
    atras = i - 1
    for k in range(atras,0-1,-1): # diagonal adelante
        factor  = AB[k,i]/pivote
        AB[k,:] = AB[k,:] - AB[i,:]*factor
        for j in range(0,m,1): # casicero revisa
            if abs(AB[k,j])<casicero:
                AB[k,j]=0
        
        print(' k:',k, 'factor:',factor)
    print(AB)
    
    AB[i,:] = AB[i,:]/AB[i,i] # diagonal a unos
    
print('AB:')
print(AB)
X = np.copy(AB[:,ultcolumna])

# SALIDA
print('Método de Gauss-Jordan')
print('solución X: ')
print(X)

El resultado del algoritmo es:

Pivoteo parcial por filas AB: ----
[[ 5.   4.   3.  56.3]
 [ 2.   5.   8.  92.9]
 [ 4.   2.   5.  60.7]]
Eliminación hacia adelante: ------
i: 0 k: 1 factor: 0.4
i: 0 k: 2 factor: 0.8
[[ 5.    4.    3.   56.3 ]
 [ 0.    3.4   6.8  70.38]
 [ 0.   -1.2   2.6  15.66]]
i: 1 k: 2 factor: -0.3529411764705883
[[ 5.    4.    3.   56.3 ]
 [ 0.    3.4   6.8  70.38]
 [ 0.    0.    5.   40.5 ]]
Eliminación hacia atras: ------
i: 2  pivote: 5.0
 k: 1 factor: 1.3599999999999999
 k: 0 factor: 0.6
[[ 5.   4.   0.  32. ]
 [ 0.   3.4  0.  15.3]
 [ 0.   0.   5.  40.5]]
i: 1  pivote: 3.4
 k: 0 factor: 1.1764705882352942
[[ 5.   0.   0.  14. ]
 [ 0.   3.4  0.  15.3]
 [ 0.   0.   1.   8.1]]
i: 0  pivote: 5.0
[[ 5.   0.   0.  14. ]
 [ 0.   1.   0.   4.5]
 [ 0.   0.   1.   8.1]]
AB:
[[1.  0.  0.  2.8]
 [0.  1.  0.  4.5]
 [0.  0.  1.  8.1]]
Método de Gauss-Jordan
solución X: 
[2.8 4.5 8.1]

[ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]
..


5. Algoritmo como función en Python

El algoritmo considera que valores con magnitud menores a "casicero" se redondean a 0. Se aplica recorriendo la fila de referencia k, por cada elemento j.

# redondeo a cero
for j in range(0,m,1): 
    if np.abs(AB[k,j])<=casicero:
        AB[k,j]=0

Adicionalmente se añade el parámetro "inversa", que se usa para encontrar A-1 como se indica en Matriz Inversa.

Con el algoritmo se obtiene el siguiente resultado:

Matriz aumentada
[[ 4.   2.   5.  60.7]
 [ 2.   5.   8.  92.9]
 [ 5.   4.   3.  56.3]]
Pivoteo parcial:
  1 intercambiar filas:  0 y 2
[[ 5.   4.   3.  56.3]
 [ 2.   5.   8.  92.9]
 [ 4.   2.   5.  60.7]]
Elimina hacia adelante:
 fila i: 0  pivote: 5.0
  fila k: 1  factor: 0.4
  fila k: 2  factor: 0.8
[[ 5.    4.    3.   56.3 ]
 [ 0.    3.4   6.8  70.38]
 [ 0.   -1.2   2.6  15.66]]
 fila i: 1  pivote: 3.4
  fila k: 2  factor: -0.3529411764705883
[[ 5.    4.    3.   56.3 ]
 [ 0.    3.4   6.8  70.38]
 [ 0.    0.    5.   40.5 ]]
 fila i: 2  pivote: 5.0
[[ 5.    4.    3.   56.3 ]
 [ 0.    3.4   6.8  70.38]
 [ 0.    0.    5.   40.5 ]]
Elimina hacia Atrás:
 fila i: 2  pivote: 5.0
  fila k: 1  factor: 1.3599999999999999
  fila k: 0  factor: 0.6
[[ 5.   4.   0.  32. ]
 [ 0.   3.4  0.  15.3]
 [ 0.   0.   1.   8.1]]
 fila i: 1  pivote: 3.4
  fila k: 0  factor: 1.1764705882352942
[[ 5.   0.   0.  14. ]
 [ 0.   1.   0.   4.5]
 [ 0.   0.   1.   8.1]]
 fila i: 0  pivote: 5.0
[[1.  0.  0.  2.8]
 [0.  1.  0.  4.5]
 [0.  0.  1.  8.1]]
solución X: 
[2.8 4.5 8.1]

Instrucciones en Python

# Método de Gauss-Jordan
# Sistemas de Ecuaciones A.X=B
import numpy as np

def gauss_eliminaAtras(AB, vertabla=False,
                       inversa=False,
                       casicero = 1e-15):
    ''' Gauss-Jordan elimina hacia atrás
    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 Atrás:')
        
    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)

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 pivoteafila(A,B,vertabla=False):
    '''
    Pivotea parcial por filas
    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,'y', dondemax+i)
    if vertabla==True:
        if pivoteado==0:
            print('  Pivoteo por filas NO requerido')
        else:
            print('AB:')
            print(AB)
    return(AB)

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

B = [60.70,92.90,56.30]

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

AB = pivoteafila(A,B,vertabla=True)

AB = gauss_eliminaAdelante(AB,vertabla=True)

X = gauss_eliminaAtras(AB,vertabla=True)

# SALIDA
print('solución X: ')
print(X)

Tarea
implementar caso cuando aparecen ceros en la diagonal para dar respuesta, convertir a funciones cada parte

[ Gauss-Jordan ] [ Ejercicio ] [ Eliminación atrás ] [ Algoritmo ] [ función ]