s1Eva_IIIT2007_T3 Factorar polinomio

Ejercicio: 1Eva_IIIT2007_T3 Factorar polinomio

P_3(x) = 2x^3-5x^2 + 3x-0.1

la gráfica se obtuvo con Python, con lo que se puede observar la primera raíz…

# 1ra Eval III Término 2007
# Tema 3. Factorar polinomio
import numpy as np
import matplotlib.pyplot as plt
def newtonraphson(funcionx, fxderiva, c, tolera):
    tramo = abs(2*tolera)
    while (tramo>=tolera):
        xnuevo = c - funcionx(c)/fxderiva(c)
        tramo = abs(xnuevo-c)
        c = xnuevo
    return(c)

# Literal a)
p3 = lambda x: 2*x**3 - 5*x**2 + 3*x -0.1
dp3 = lambda x: 6*x**2 - 10*x +3
a = 0
b = 2
pasos = 100
c = 2
tolera = 0.0001

# PROCEDIMIENTO
xi = np.linspace(a,b,pasos+1)
p_i = p3(xi)

raiz1 = newtonraphson(p3, dp3, c, tolera)

# SALIDA
print('primera raiz: ',raiz1)
plt.plot(xi,p_i)
plt.axhline(0)
plt.show()

para el literal b)
se añade:

# Literal b)
# PROCEDIMIENTO
p2 =  lambda x: (2*x**3 - 5*x**2 + 3*x -0.1)/(x-raiz1)
# SALIDA
pol2 = p2(xi)
plt.plot(xi,pol2)
plt.show()

s1Eva_IIIT2007_T2_AN Función Cobb-Douglas

Ejercicio: 1Eva_IIIT2007_T2 Función Cobb-Douglas

usando los algoritmos para encontrar los polinomios de lagrange y búsqueda de raíz por la bisección, se obtiene:

 **** literal a:
Polinomio de Lagrange
[0, 6.16333333333368e-5*x**3 - 0.00527800000000012*x**2 + 0.254746666666668*x + 11.0, 0.00010365*x**3 - 0.008876*x**2 + 0.428425*x + 18.4997, 0.000140483333333337*x**3 - 0.0120304999999998*x**2 + 0.580686666666667*x + 25.0746]
Puntos f[25]:
[0, 15.0329375000000, 25.2823562500000, 34.2677562500002]
Polinoio con f[25]:
0.000586583333333373*x**3 - 0.0415150937500013*x**2 + 1.85978635416668*x
Estimado de [la,ka]:
29.7130898437501
 **** Literal b
La raiz se encuentra en:  25.3295898438

Revisar el algoritmo por partes: literal a y literal b.

# Interpolacion de Lagrange
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp

def lagrange(xi,fi):
    n = len(xi)
    x = sp.Symbol('x')
    # Polinomio
    polinomio = 0
    for i in range(0,n,1):
        # Termino de Lagrange
        termino = 1
        for j  in range(0,n,1):
            if j!=i:
                termino = termino*(x-xi[j])/(xi[i]-xi[j])
        polinomio = polinomio + termino*fi[i]
    # Expande el polinomio
    px = polinomio.expand()
    return(px)

# INGRESO , Datos de prueba
M = np.array([[0, 0, 0, 0],
              [11.0000, 13.0813, 14.4768, 15.5563],
              [18.4997, 22.0000, 24.3470, 26.1626],
              [25.0746, 29.8189, 33.0000, 35.4608]])
li = np.array([0, 10, 20, 30])
kj = np.array([10, 20, 30, 40])

la = 25
ka = 25

# PROCEDIMIENTO
tamano = np.shape(M)
n = tamano[0]
m = tamano[1]
x = sp.Symbol('x')
poli = []
for i in range(0,n,1):
    xi = li
    fi = M[i,:]
    p = lagrange(xi,fi)
    poli.append(p)
# literal a, evalua en la
f_la =[]
for i in range(0,n,1):
    puntola = poli[i].subs(x,la)
    f_la.append(puntola)
poli_la = lagrange(li,f_la)
# literal a, evalua en ka
puntolaka = poli_la.subs(x,ka)

# SALIDA
print(' **** literal a:')
print('Polinomio de Lagrange')
print(poli)
print('Puntos f['+str(la)+']:')
print(f_la)
print('Polinoio con f['+str(ka)+']:')
print(poli_la)
print('Estimado de [la,ka]:')
print(puntolaka)


# ------------------------------------
# literal b, usa f_ka con resultado 30

def biseccion(funcionx,a,b,tolera,iteramax = 20):
    '''
    Algoritmo de Bisección
    Los valores de [a,b] son seleccionados
    desde la gráfica de la función
    error = tolera
    '''
    fa = funcionx(a)
    fb = funcionx(b)

    itera = 0
    tramo = np.abs(b-a)
    while (tramo>=tolera and itera<=iteramax):
        c = (a+b)/2
        fc = funcionx(c)
        cambia = np.sign(fa)*np.sign(fc)
        if (cambia<0):
            b = c
            fb = fc
        else:
            a = c
            fa = fc
        tramo = np.abs(b-a)
        itera = itera + 1
    respuesta = c
    # Valida respuesta
    if (i>=iteramax):
        respuesta = np.nan
    return(respuesta)


# INGRESO
a = kj[0]
b = kj[m-1]
tolera = 0.01

# PROCEDIMIENTO
# Busca raiz
fx = sp.lambdify(x,poli_la - 30)
fxi = fx(kj)

raiz = biseccion(fx,a,b,tolera)

# SALIDA
print(' **** Literal b')
print('La raiz se encuentra en: ',raiz)

# GRAFICA
plt.plot(kj,fxi)
plt.axhline(0)
plt.show()

s1Eva_IIIT2007_T1_AN Container: Refrigeradoras y Cocinas

Ejercicio: 1Eva_IIIT2007_T1 Container: Cocinas y Refrigeradoras

x: cantidad de refrigeradoras
y: cantidad de cocinas

ecuaciones:

200 x + 100  y = 1000
  2 x + 1.05 y =   10.4

literal a)
Nota: se han omitido los pasos para la solución del sistema, usando la función gauss desarrollada en python.

Si las matrices son:
A = np.array([[200, 100],
              [2,1.05]])

B = np.array([[1000],
              [10.4]])

el vector solución X es:
[ 1.  8.]
verificar que A.X sea igual a B
[ 1000.     10.4]

literal b)

>>> 
el vector solución X es:
[ 3.  4.]
verificar que A.X sea igual a B
[ 1000.     10.4]
>>> 

literal c)

Observación: el pequeño cambio de volumen de la cocina no es consistente con los resultados.

El asunto es que la forma de la refrigeradora o cocina no se adapta al volumen disponible, pues son objetos rígidos. Por lo que el sistema de ecuaciones estaría mal planteado.
Las ecuaciones tendrían sentido si esta diseñando el mejor «tamaño» para que entren la mayor cantidad dentro de un container, sin embargo los tamaños de las refrigeradoras y cocinas se encuentran estandarizados.

Revisamos el número de condición, que resulta ser del orden de 104, lo que confirma que el sistema está mal condicionado.

Usando la el valor de 1.05

>>> C = np.concatenate((A,B),axis=1)
>>> C
array([[  200. ,   100. ,  1000.  ],
       [    2. ,     1.05,    10.4]])
>>> np.linalg.cond(C)
12926.000640466344

s1Eva_IIT2007_T3 Interpolación inversa

Ejercicio: 1Eva_IIT2007_T3 Interpolación inversa

f(0.50) = 1.648
f(0.65) = 1.915
f( x  ) = 2.117
f(0.80) = 2.225
f(0.95) = 2.5857

Para el algoritmo se intercambian las variables previo a usarlo.
Luego se evalua en el punto buscado, en éste caso: fi=2.117, obteniendo que x es: 0.750321134121361

fi = np.array([0.50 , 0.65 , 0.80,  0.95   ])
x = np.array([1.648, 1.915, 2.225, 2.5857 ])
Polinomio de Lagrange
0.924124055152463*(-3.74531835205992*x + 7.17228464419475)*(x - 2.5857)*(x - 2.225) + 3.12624749298999*(x - 2.5857)*(x - 2.225)*(3.74531835205992*x - 6.17228464419475) - 7.15454716188057*(x - 2.5857)*(x - 1.915)*(1.73310225303293*x - 2.85615251299827) + 3.92689380344011*(x - 2.225)*(x - 1.915)*(1.06643915964594*x - 1.75749173509651)
Expandiendo: 
0.0358848473081501*x**3 - 0.342756582990887*x**2 + 1.44073214117566*x - 1.10404634485226
>>> px
0.0358848473081501*x**3 - 0.342756582990887*x**2 + 1.44073214117566*x - 1.10404634485226
>>> px.subs(x,2.117)
0.750321134121361

El algortmo modificado usado es:

# Interpolacion de Lagrange
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp

# INGRESO , Datos de prueba
fi = np.array([0.50 , 0.65 , 0.80,  0.95   ])
xi = np.array([1.648, 1.915, 2.225, 2.5857 ])

# PROCEDIMIENTO
n = len(xi)
x = sp.Symbol('x')
# Polinomio
polinomio = 0
for i in range(0,n,1):
    # Termino de Lagrange
    termino = 1
    for j  in range(0,n,1):
        if j!=i:
            termino = termino*(x-xi[j])/(xi[i]-xi[j])
    polinomio = polinomio + termino*fi[i]
    
# Expande el polinomio
px = polinomio.expand()

# Salida
print('Polinomio de Lagrange')
print(polinomio)
print('Expandiendo: ')
print(px)

para visualizar el resultado, intercambiando nuevamente los ejes:

>>> px
0.0358848473081501*x**3 - 0.342756582990887*x**2 + 1.44073214117566*x - 1.10404634485226
>>> px.subs(x,2.117)
0.750321134121361
>>> px
0.0358848473081501*x**3 - 0.342756582990887*x**2 + 1.44073214117566*x - 1.10404634485226

para revisar con la gráfica, se añaden las líneas,

# GRAFICA
polinomio = sp.lambdify(x,px)
y = np.linspace(1,3,100)
pyi= polinomio(y)
plt.plot(pyi,y)
plt.show()

s1Eva_IIT2007_T2 Aplicar Gauss-Seidel

Ejercicio: 1Eva_IIT2007_T2 Aplicar Gauss-Seidel

Probando solución con Jacobi, enviado como tarea

Desarrrollo Analítico

– Verificar que la matriz es diagonal dominante

No es necesario realizar el pivoteo por filas, ya la matriz tiene la diagonal dominante.

A = [[7.63, 0.30, 0.15,  0.50, 0.34, 0.84],
     [0.38, 6.40, 0.70,  0.90, 0.29, 0.57],
     [0.83, 0.19, 8.33,  0.82, 0.34, 0.37],
     [0.50, 0.68, 0.86, 10.21, 0.53, 0.70],
     [0.71, 0.30, 0.85,  0.82, 5.95, 0.55],
     [0.43, 0.54, 0.59,  0.66, 0.31, 9.25]]

B = [ -9.44, 25.27, -48.01, 19.76, -23.63, 62.59]

– revisar el número de condición

cond(A) = || A||.||A-1||

El número de condición no es «muy alto»,  los valores de la diagonal son los mayores en toda la fila, por lo que el sistema converge.

>>> np.linalg.cond(A)
2.0451853966291011

– realizar iteraciones

Dado que no se establece en el enunciado el vector inicial, se usará el vector cero. La tolerancia requerida es 10-5
X0 = [ 0. 0. 0. 0. 0. 0.]

iteración 1

x0 = (-9.44 -0.30(0) -0.15(0) 
      -0.50(0) -0.34(0) -0.84(0))/7.63 
   = -9.44/7.63 = -1.23722149
x1 = (25.27 -0.38(0) -0.70(0) 
      -0.90(0) -0.29(0) -0.57(0))/6.40 
   = 25.27/6.40 = 3.9484375
x2 = (-48.01 -0.83(0) -0.19(0) -0.82(0)
      -0.34(0) -0.37(0))/8.33 
   = -48.01/8.33 = -5.7635054
x3 = (19.76 -0.50(0) -0.68(0) -0.86(0)
      -0.53(0) -0.70(0))/10.21 
   = 19.76/10.21 = 1.93535749
x4 = (-23.63 - 0.71(0) -0.30(0) -0.85(0)
      -0.82(0) -0.55(0))/5.95 
   = -23.63/5.95 = -3.97142857
x5 = (62.59 - 0.43(0) -0.54(0) -0.59(0)
      -0.66(0) -0.31(0))/9.25 
   = 62.59/9.25 = 6.76648649
X1 = [-1.23722149  3.9484375  -5.7635054   1.93535749 -3.97142857  6.76648649]
diferencia = X1 - X0 = X1
errado = max(|diferencia|) = 6.76648649

iteración 2

x0 = (-9.44 -0.30(3.9484375) -0.15(-5.7635054) 
      -0.50(1.93535749) -0.34(-3.97142857) -0.84(6.76648649))/7.63 
   = -9.44/7.63 = -1.23722149
x1 = (25.27 -0.38(-1.23722149) -0.70(-5.7635054) 
      -0.90(1.93535749) -0.29(-3.97142857) -0.57(6.76648649))/6.40 
   = 25.27/6.40 = 3.9484375
x2 = (-48.01 -0.83(-1.23722149) -0.19(3.9484375)
      -0.82(1.93535749) -0.34(-3.97142857) -0.37(6.76648649))/8.33 
   = -48.01/8.33 = -5.7635054
x3 = (19.76 -0.50(-1.23722149) -0.68(3.9484375)
      -0.86(-5.7635054) -0.53(-3.97142857) -0.70(6.76648649))/10.21 
   = 19.76/10.21 = 1.93535749
x4 = (-23.63 - 0.71(-1.23722149) -0.30(3.9484375) 
      -0.85(-5.7635054) -0.82(1.93535749) -0.55(6.76648649))/5.95 
   = -23.63/5.95 = -3.97142857
x5 = (62.59 - 0.43(-1.23722149) -0.54(3.9484375) 
      -0.59(-5.7635054) -0.66(1.93535749) -0.31(-3.97142857))/9.25 
   = 62.59/9.25 = 6.76648649
X1 = [-1.97395113  3.95743644 -6.05925771  1.96068604 -4.09171178  6.95612152]
diferencia = X1 - X0 = [-0.73672964,  0.00899894, -0.29575231,  0.02532855, -0.12028321, 0.18963504]
errado = max(|diferencia|) = 0.736729635697

iteración 3

x0 = (-9.44 -0.30(3.95743644) -0.15(-6.05925771) 
      -0.50(1.96068604) -0.34(-4.09171178) -0.84(6.95612152))/7.63 
   = -9.44/7.63 = -1.23722149
x1 = (25.27 -0.38(-1.97395113) -0.70(-6.05925771) 
      -0.90(1.96068604) -0.29(-4.09171178) -0.57(6.95612152))/6.40 
   = 25.27/6.40 = 3.9484375
x2 = (-48.01 -0.83(-1.97395113) -0.19(3.95743644) 
      -0.82(1.96068604) -0.34(-4.09171178) -0.37(6.95612152))/8.33 
   = -48.01/8.33 = -5.7635054
x3 = (19.76 -0.50(-1.97395113) -0.68(3.95743644) 
     -0.86(-6.05925771) -0.53(-4.09171178) -0.70(6.95612152))/10.21 
   = 19.76/10.21 = 1.93535749
x4 = (-23.63 - 0.71(-1.97395113) -0.30(3.95743644) 
      -0.85(-6.05925771) -0.82(1.96068604) -0.55(6.95612152))/5.95 
   = -23.63/5.95 = -3.97142857
x5 = (62.59 - 0.43(-1.97395113) -0.54(3.95743644) 
      -0.59(-6.059257710) -0.66(1.96068604) -0.31(-4.09171178))/9.25 
   = 62.59/9.25 = 6.76648649
X1 = [-1.98566781  4.0185268  -5.9920623   2.01431955 -3.98302285  7.01093224]
diferencia = X1 - X0 = [-0.01171668,  0.06109037,  0.0671954 ,  0.05363351,  0.10868893, 0.05481072]
errado = max(|diferencia|) = 0.108688931048

Desarrollo numérico con Python

Se verifica el resultado obtenido realizando A.Xi y comparando con el vecto B
en la tabla se usa el signo de errado para la gráfica.

X0:  [ 0.  0.  0.  0.  0.  0.]
Xi:  [-1.23722149  3.9484375  -5.7635054   1.93535749 -3.97142857  6.76648649]
errado:  6.76648648649
Xi:  [-1.97395113  3.95743644 -6.05925771  1.96068604 -4.09171178  6.95612152]
errado:  -0.736729635697
Xi:  [-1.98566781  4.0185268  -5.9920623   2.01431955 -3.98302285  7.01093224]
errado:  0.108688931048
Xi:  [-2.00378293  3.99452422 -6.00443878  1.99576482 -4.0067623   6.9961552 ]
errado:  -0.0240025781157
Xi:  [-1.99869529  4.00195452 -5.99863447  2.00153846 -3.99769932  7.00130746]
errado:  0.00906298532211
Xi:  [-2.00045097  3.99933614 -6.00047801  1.99948184 -4.00078219  6.99955127]
errado:  -0.00308287453133
Xi:  [-1.99984629  4.00022733 -5.99983706  2.00017793 -3.99973154  7.00015339]
errado:  0.0010506528253
Xi:  [-2.00005265  3.9999222  -6.00005579  1.99993915 -4.00009178  6.9999475 ]
errado:  -0.0003602430897
Xi:  [-1.99998199  4.00002662 -5.99998091  2.00002082 -3.99996859  7.00001796]
errado:  0.000123195668206
Xi:  [-2.00000616  3.99999089 -6.00000653  1.99999287 -4.00001075  6.99999385]
errado:  -4.21623029112e-05

respuesta de A.X=B : 
[-2.00000616  3.99999089 -6.00000653  1.99999287 -4.00001075  6.99999385]
iteraciones:  10

A.Xi:  [ -9.44006312  25.26992175 -48.01007303  19.75990236 -23.63008584
  62.58992368]
   B: [ -9.44 25.27 -48.01 19.76 -23.63 62.59]

el gráfico de los errores vs iteraciones es:


Aplicando Gauss-Seidel

la tabla de aproximaciones sucesivas para el vector X es:

Tabla de iteraciones con AX=B: 
[[ 0.          0.          0.          0.          0.          0.        ]
 [-1.23722149  4.02189753 -5.73196479  2.21089228 -3.51242077  6.91477852]
 [-2.0322951   3.92844105 -6.03202587  1.98957766 -3.97864919  7.00774962]
 [-1.9976784   4.00317297 -6.00049341  1.99807691 -4.00081785  6.99990294]
 [-1.99994191  4.00036665 -5.99978715  2.00000392 -4.00004739  6.99996363]
 [-2.00001274  3.99998231 -5.99999516  2.00000635 -3.99999579  7.00000072]
 [-2.00000008  3.99999833 -6.00000078  1.99999991 -3.99999985  7.00000015]
 [-1.99999994  4.00000007 -6.00000001  1.99999997 -4.00000002  7.        ]]
>>> 

que se obtiene aplicando la función de Gauss-Seidel, tomando como vector inicial el vector de ceros.
Tarea: X=TX+C

# Algoritmo Gauss-Seidel
# solución de matrices
# métodos iterativos
# Referencia: Chapra 11.2, p.310, pdf.334
#      Rodriguez 5.2 p.162
import numpy as np

def gauss_seidel_tabla(A,B,tolera,X = [0], itermax=100):
    tamano = np.shape(A)
    n = tamano[0]
    m = tamano[1]
    if (len(X)==n):
        X = np.zeros(n, dtype=float)
    diferencia = np.ones(n, dtype=float)
    errado = np.max(diferencia)
    tabla = [np.copy(X)]
        
    itera = 0
    while (errado>tolera or itera>itermax):
        for i in range(0,n,1):
            xi = B[i]
            for j in range(0,m,1):
                if (i!=j):
                    xi = xi-A[i,j]*X[j]
            xi = xi/A[i,i]
            diferencia[i] = np.abs(xi-X[i])
            X[i] = xi
        errado = np.max(diferencia)
        itera = itera + 1
        tabla.append(np.copy(X))

    tabla = np.array(tabla)
        
    # No converge
    if (itera>itermax):
        X=0
    return(tabla)

# Programa de prueba #######
# INGRESO
A = np.array([[7.63, 0.30, 0.15,  0.50, 0.34, 0.84],
              [0.38, 6.40, 0.70,  0.90, 0.29, 0.57],
              [0.83, 0.19, 8.33,  0.82, 0.34, 0.37],
              [0.50, 0.68, 0.86, 10.21, 0.53, 0.70],
              [0.71, 0.30, 0.85,  0.82, 5.95, 0.55],
              [0.43, 0.54, 0.59,  0.66, 0.31, 9.25]])

B = np.array([[ -9.44],
              [ 25.27],
              [-48.01],
              [ 19.76],
              [-23.63],
              [ 62.59]])

tolera = 0.00001

# PROCEDIMIENTO
n = len(A)
X = np.zeros(n, dtype=float)
respuesta = gauss_seidel_tabla(A,B, tolera, X)

# SALIDA
print('Tabla de iteraciones con AX=B: ')
print(respuesta)

En el caso de la norma infinito, para la matriz A, se puede usar el algoritmo desarrollado en clase.
Como valor para verificar su algoritmo, se obtuvo:

>>> np.linalg.norm(A, np.inf)
13.479999999999999

Tarea: incluir la norma infinito para T

s1Eva_IIT2007_T1 Distribución binomial acumulada

Ejercicio: 1Eva_IIT2007_T1 Distribución binomial acumulada

Dado F=0.4, dado que n=5 y k=1

Con lo que la fórmula para el objetivo se convierte en:

F = \Bigg( \begin{array}{c} 5 \\ 0 \end{array} \Bigg) p ^0 (1-p)^{(5-0)} + \Bigg( \begin{array}{c} 5 \\ 1 \end{array} \Bigg) p ^1 (1-p)^{(5-1)} = 0.4

para buscar la raíz:

f(p) = (1-p)^{5} + 5p (1-p)^{4} - 0.4

Los valores de las combinatorias se calculan como:

>>> import scipy.special as sts
>>> sts.comb(5,0,repetition=False)
1.0
>>> sts.comb(5,1,repetition=False)
5.0
>>> 

como referencia se revisa la gráfica para f(p)

# 1ra Eval II Término 2007
# Tema 1. Distribución binomial acumulada
import numpy as np
import matplotlib.pyplot as plt
import scipy.special as sts

fp = lambda p: (1-p)**5 + 5*p*((1-p)**4) - 0.4

a = 0
b = 1
pasos = 100

# PROCEDIMIENTO
xi = np.linspace(a,b,pasos+1)
p_i = fp(xi)

# SALIDA
plt.plot(xi,p_i)
plt.axhline(0)
plt.show()
f(p) = (1-p)^5 + 5p(1-p)^4 - 0.4 = (1-p)^4 (1 - p + 5p) - 0.4 = (1-p)^4 (1 + 4p) - 0.4 = (1-p)^2 (1-p)^2 (1 + 4p) - 0.4 = (1-2p+p^2) (1-2p+p^2) (1 + 4p) - 0.4 = (1 - 4p + 6p^2 - 4p^3 +p^4 ) (1 + 4p) - 0.4 = 1 - 10p^2 + 20p^3 + 15p^4 + 4p^5 - 0.4 = 0.6 - 10p^2 + 20p^3 + 15p^4 + 4p^5

y su derivada:

f'(p) = - 20p + 60p^2 + 60p^3 +20p^4
con lo que se puede desarrollar Newton-Raphson…

Verificando el polinomio a usar con python:

>>> import sympy as sp
>>> p = sp.Symbol('p')
>>> poli = (1-p)**5 + 5*p*((1-p)**4) - 0.4
>>> pol = poli.expand()
>>> pol
4*p**5 - 15*p**4 + 20*p**3 - 10*p**2 + 0.6
>>> pol.diff(p,1)
20*p**4 - 60*p**3 + 60*p**2 - 20*p

Tarea: con lo que puede continuar con el procedimiento para encontrar la raiz…

verificar con raiz: 0.3649852264049102


Newton-Raphson

# Método de Newton-Raphson
# Ejemplo 1 (Burden ejemplo 1 p.51/pdf.61)
import numpy as np

def newtonraphson(funcionx, fxderiva, c, tolera):
    tramo = abs(2*tolera)
    while (tramo>=tolera):
        xnuevo = c - funcionx(c)/fxderiva(c)
        tramo = abs(xnuevo-c)
        c = xnuevo
    return(c)


# PROGRAMA #######################
import matplotlib.pyplot as plt

funcionx = lambda p: 4*p**5 - 15*p**4 + 20*p**3 - 10*p**2 + 0.6
fxderiva = lambda p: 20*p**4 - 60*p**3 + 60*p**2 - 20*p

# INGRESO
c = 0.2
tolera = 0.0000001

# PROCEDIMIENTO
raiz = newtonraphson(funcionx, fxderiva, c, tolera)

# SALIDA
print('raiz en: ', raiz)

el resultado es:

raiz en:  0.3649852264049102
>>> funcionx(0.3649852264049102)
1.4099832412739488e-14
>>> 

7.3 EDP hiperbólicas

Referencia:  Chapra PT8.1 p.860 pdf.884,  Rodriguez 10.4 p.435

Las Ecuaciones Diferenciales Parciales tipo hiperbólicas semejantes a la mostrada, para un ejemplo en particular, representa la ecuación de onda de una dimensión u[x,t], que representa el desplazamiento vertical de una cuerda.

\frac{\partial ^2 u}{\partial t^2}=c^2\frac{\partial ^2 u}{\partial x^2}

Los extremos de la cuerda de longitud unitaria están sujetos y referenciados a una posición 0 a la izquierda y 1 a la derecha.

u[x,t] , 0<x<1, t≥0
u(0,t) = 0 , t≥0
u(1,t) = 0 , t≥0

Al inicio, la cuerda está estirada por su punto central:

u(x,0) = \begin{cases} -0.5x &, 0\lt x\leq 0.5 \\ 0.5(x-1) &, 0.5\lt x \lt 1 \end{cases}

Se suelta la cuerda, con velocidad cero desde la posición inicial:

\frac{\partial u(x,0)}{\partial t} = 0

La solución se realiza de forma semejante al procedimiento para EDP parabólicas y elípticas. Se cambia a la forma discreta  usando diferencias finitas divididas:

\frac{u_{i,j+1}-2u_{i,j}+u_{i,j-1}}{(\Delta t)^2} =c^2 \frac{u_{i+1,j}-2u_{i,j}+u_{i-1,j}}{(\Delta x)^2}

El error es del orden O(\Delta x)^2 + O(\Delta t)^2.
se reagrupa de la forma:

u_{i,j+1}-2u_{i,j}+u_{i,j-1} = \frac{c^2 (\Delta t)^2}{(\Delta x)^2} \big( u_{i+1,j}-2u_{i,j}+u_{i-1,j} \big)

El término constante, por facilidad se simplifica con el valor de 1

\lambda = \frac{c^2 (\Delta t)^2}{(\Delta x)^2} =1

si c = 2 y Δx = 0.2, se deduce que Δt = 0.1

que al sustituir en la ecuación, se simplifica anulando el término u[i,j]:

u_{i,j+1}+u_{i,j-1} = u_{i+1,j}+u_{i-1,j}

en los que intervienen solo los puntos extremos. Despejando el punto superior del rombo:

u_{i,j+1} = u_{i+1,j}-u_{i,j-1}+u_{i-1,j}

Convergencia:

\lambda = \frac{c^2 (\Delta t)^2}{(\Delta x)^2} \leq 1

para simplificar aún más el problema, se usa la condición velocidad inicial de la cuerda igual a cero

\frac{\delta u_{i,0}}{\delta t}=\frac{u_{i,1}-u_{i,-1}}{2\Delta t} = 0 u_{i,-1}=u_{i,1}

que se usa para cuando el tiempo es cero, permite calcular los puntos para t[1]:

j=0

u_{i,1} = u_{i+1,0}-u_{i,-1}+u_{i-1,0} u_{i,1} = u_{i+1,0}-u_{i,1}+u_{i-1,0} 2 u_{i,1} = u_{i+1,0}+u_{i-1,0} u_{i,1} = \frac{u_{i+1,0}+u_{i-1,0}}{2}

Aplicando solo cuando j = 0

que al ponerlos en la malla se logra un sistema explícito para cada u[i,j], con lo que se puede resolver con un algoritmo:

Algoritmo en Python:

# Ecuaciones Diferenciales Parciales
# Hiperbólica. Método explicito
import numpy as np

def cuerdainicio(xi):
    n = len(xi)
    y = np.zeros(n,dtype=float)
    for i in range(0,n,1):
        if (xi[i]<=0.5):
            y[i]=-0.5*xi[i]
        else:
            y[i]=0.5*(xi[i]-1)
    return(y)

# INGRESO
x0 = 0
xn = 1 # Longitud de cuerda
y0 = 0
yn = 0 # Puntos de amarre
t0 = 0
c = 2
# discretiza
tramosx = 16
tramost = 32
dx = (xn-x0)/tramosx 
dt = dx/c

# PROCEDIMIENTO
xi = np.arange(x0,xn+dx,dx)
tj = np.arange(0,tramost*dt+dt,dt)
n = len(xi)
m = len(tj)

u = np.zeros(shape=(n,m),dtype=float)
u[:,0] = cuerdainicio(xi)
u[0,:] = y0
u[n-1,:] = yn
# Aplicando condición inicial
j = 0
for i in range(1,n-1,1):
    u[i,j+1] = (u[i+1,j]+u[i-1,j])/2
# Para los otros puntos
for j in range(1,m-1,1):
    for i in range(1,n-1,1):
        u[i,j+1] = u[i+1,j]-u[i,j-1]+u[i-1,j]

# SALIDA
np.set_printoptions(precision=2)
print('xi =')
print(xi)
print('tj =')
print(tj)
print('matriz u =')
print(u)

con lo que se obtienen los resultados numéricos, que para mejor interpretación se presentan en una gráfica estática y otra animada.

# GRAFICA
import matplotlib.pyplot as plt

for j in range(0,m,1):
    y = u[:,j]
    plt.plot(xi,y)

plt.title('EDP hiperbólica')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

# **** GRÁFICO CON ANIMACION ***********
import matplotlib.animation as animation

# Inicializa parametros de trama/foto
retardo = 70   # milisegundos entre tramas
tramas  = m
maximoy = np.max(np.abs(u))
figura, ejes = plt.subplots()
plt.xlim([x0,xn])
plt.ylim([-maximoy,maximoy])

# lineas de función y polinomio en gráfico
linea_poli, = ejes.plot(xi,u[:,0], '-')
plt.axhline(0, color='k')  # Eje en x=0

plt.title('EDP hiperbólica')
# plt.legend()
# txt_x = (x0+xn)/2
txt_y = maximoy*(1-0.1)
texto = ejes.text(x0,txt_y,'tiempo:',
                  horizontalalignment='left')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()

# Nueva Trama
def unatrama(i,xi,u):
    # actualiza cada linea
    linea_poli.set_ydata(u[:,i])
    linea_poli.set_xdata(xi)
    linea_poli.set_label('tiempo linea: '+str(i))
    texto.set_text('tiempo['+str(i)+']')
    # color de la línea
    if (i<=9):
        lineacolor = 'C'+str(i)
    else:
        numcolor = i%10
        lineacolor = 'C'+str(numcolor)
    linea_poli.set_color(lineacolor)
    return linea_poli, texto

# Limpia Trama anterior
def limpiatrama():
    linea_poli.set_ydata(np.ma.array(xi, mask=True))
    linea_poli.set_label('')
    texto.set_text('')
    return linea_poli, texto

# Trama contador
i = np.arange(0,tramas,1)
ani = animation.FuncAnimation(figura,
                              unatrama,
                              i ,
                              fargs=(xi,u),
                              init_func=limpiatrama,
                              interval=retardo,
                              blit=True)
# Graba Archivo video y GIFAnimado :
# ani.save('EDP_hiperbólica.mp4')
ani.save('EDP_hiperbolica.gif', writer='imagemagick')
plt.draw()
plt.show()

Una vez realizado el algoritmo, se pueden cambiar las condiciones iniciales de la cuerda y se observan los resultados.

Se recomienda realizar otros ejercicios de la sección de evaluaciones para EDP Hiperbólicas y observar los resultados con el algoritmo modificado.

7.2.2 EDP Elípticas método implícito

con el resultado desarrollado en EDP elípticas para:

\frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{ \partial y^2} = 0

y con el supuesto que: \lambda = \frac{(\Delta y)^2}{(\Delta x)^2} = 1

se puede plantear que:

u_{i+1,j}-4u_{i,j}+u_{i-1,j} + u_{i,j+1} +u_{i,j-1} = 0

con lo que para el método implícito, se plantea un sistema de ecuaciones para determinar los valores en cada punto desconocido.

j=1, i =1

u_{2,1}-4u_{1,1}+u_{0,1} + u_{1,2} +u_{1,0} = 0 u_{2,1}-4u_{1,1}+Ta + u_{1,2} +Tc= 0 -4u_{1,1}+u_{2,1}+u_{1,2} = -(Tc+Ta)

j=1, i =2

u_{3,1}-4u_{2,1}+u_{1,1} + u_{2,2} +u_{2,0} = 0 u_{3,1}-4u_{2,1}+u_{1,1} + u_{2,2} +Tc = 0 u_{1,1}-4u_{2,1}+u_{3,1}+ u_{2,2}= -Tc

j=1, i=3

u_{4,1}-4u_{3,1}+u_{2,1} + u_{3,2} +u_{3,0} = 0 Tb-4u_{3,1}+u_{2,1} + u_{3,2} +Tc = 0 u_{2,1} -4u_{3,1} + u_{3,2} = -(Tc+Tb)

j=2, i=1

u_{2,2}-4u_{1,2}+u_{0,2} + u_{1,3} +u_{1,1} = 0 u_{2,2}-4u_{1,2}+Ta + u_{1,3} +u_{1,1} = 0 -4u_{1,2}+u_{2,2}+u_{1,1}+u_{1,3} = -Ta

j = 2, i = 2

u_{1,2}-4u_{2,2}+u_{3,2} + u_{2,3} +u_{2,1} = 0

j = 2, i = 3

u_{4,2}-4u_{3,2}+u_{2,2} + u_{3,3} +u_{3,1} = 0 Tb-4u_{3,2}+u_{2,2} + u_{3,3} +u_{3,1} = 0 u_{2,2} -4u_{3,2}+ u_{3,3} +u_{3,1} = -Tb

j=3, i = 1

u_{2,3}-4u_{1,3}+u_{0,3} + u_{1,4} +u_{1,2} = 0 u_{2,3}-4u_{1,3}+Ta + Td +u_{1,2} = 0 -4u_{1,3}+u_{2,3}+u_{1,2} = -(Td+Ta)

j=3, i = 2

u_{3,3}-4u_{2,3}+u_{1,3} + u_{2,4} +u_{2,2} = 0 u_{3,3}-4u_{2,3}+u_{1,3} + Td +u_{2,2} = 0 +u_{1,3} -4u_{2,3}+u_{3,3} +u_{2,2} = -Td

j=3, i=3

u_{4,3}-4u_{3,3}+u_{2,3} + u_{3,4} +u_{3,2} = 0 Tb-4u_{3,3}+u_{2,3} + Td +u_{3,2} = 0 u_{2,3}-4u_{3,3}+u_{3,2} = -(Td+Tb)

con las ecuaciones se arma una matriz:

A = np.array([
    [-4, 1, 0, 1, 0, 0, 0, 0, 0],
    [ 1,-4, 1, 0, 1, 0, 0, 0, 0],
    [ 0, 1,-4, 0, 0, 1, 0, 0, 0],
    [ 1, 0, 0,-4, 1, 0, 1, 0, 0],
    [ 0, 1, 0, 1,-4, 1, 0, 1, 0],
    [ 0, 0, 1, 0, 1,-4, 0, 0, 1],
    [ 0, 0, 0, 1, 0, 0,-4, 1, 0],
    [ 0, 0, 0, 0, 1, 0, 1,-4, 1],
    [ 0, 0, 0, 0, 0, 1, 0, 1,-4],
    ])
B = np.array([-(Tc+Ta),-Tc,-(Tc+Tb),
                  -Ta,   0,    -Tb,
              -(Td+Ta),-Td,-(Td+Tb)])

que al resolver el sistema de ecuaciones se obtiene:

>>> Xu
array([ 56.43,  55.71,  56.43,  60.  ,  60.  ,  60.  ,  63.57,  64.29,
        63.57])

ingresando los resultados a la matriz u:

xi=
[ 0.   0.5  1.   1.5  2. ]
yj=
[ 0.    0.38  0.75  1.12  1.5 ]
matriz u
[[ 60.    60.    60.    60.    60.  ]
 [ 50.    56.43  60.    63.57  70.  ]
 [ 50.    55.71  60.    64.29  70.  ]
 [ 50.    56.43  60.    63.57  70.  ]
 [ 60.    60.    60.    60.    60.  ]]
>>>

Algoritmo usado para resolver el problema:

# Ecuaciones Diferenciales Parciales
# Elipticas. Método implícito
import numpy as np

# INGRESO
# Condiciones iniciales en los bordes
Ta = 60
Tb = 60
Tc = 50
Td = 70
# dimensiones de la placa
x0 = 0
xn = 2
y0 = 0
yn = 1.5
# discretiza, supone dx=dy
tramosx = 4
tramosy = 4
dx = (xn-x0)/tramosx 
dy = (yn-y0)/tramosy 
maxitera = 100
tolera = 0.0001

A = np.array([
    [-4, 1, 0, 1, 0, 0, 0, 0, 0],
    [ 1,-4, 1, 0, 1, 0, 0, 0, 0],
    [ 0, 1,-4, 0, 0, 1, 0, 0, 0],
    [ 1, 0, 0,-4, 1, 0, 1, 0, 0],
    [ 0, 1, 0, 1,-4, 1, 0, 1, 0],
    [ 0, 0, 1, 0, 1,-4, 0, 0, 1],
    [ 0, 0, 0, 1, 0, 0,-4, 1, 0],
    [ 0, 0, 0, 0, 1, 0, 1,-4, 1],
    [ 0, 0, 0, 0, 0, 1, 0, 1,-4],
    ])
B = np.array([-(Tc+Ta),-Tc,-(Tc+Tb),
              -Ta,0,-Tb,
              -(Td+Ta),-Td,-(Td+Tb)])


# PROCEDIMIENTO
# Resuelve sistema ecuaciones
Xu = np.linalg.solve(A,B)
[nx,mx] = np.shape(A)

xi = np.arange(x0,xn+dx,dx)
yj = np.arange(y0,yn+dy,dy)
n = len(xi)
m = len(yj)

u = np.zeros(shape=(n,m),dtype=float)
u[:,0]   = Tc
u[:,m-1] = Td
u[0,:]   = Ta
u[n-1,:] = Tb
u[1:1+3,1] = Xu[0:0+3]
u[1:1+3,2] = Xu[3:3+3]
u[1:1+3,3] = Xu[6:6+3]

# SALIDA
np.set_printoptions(precision=2)
print('xi=')
print(xi)
print('yj=')
print(yj)
print('matriz u')
print(u)

La gráfica de resultados se obtiene de forma semejante al ejercicio con método iterativo.

# Gráfica
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D

X, Y = np.meshgrid(xi, yj)
U = np.transpose(u) # ajuste de índices fila es x

figura = plt.figure()
ax = Axes3D(figura)
ax.plot_surface(X, Y, U, rstride=1, cstride=1, cmap=cm.Reds)

plt.title('EDP elíptica')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

Se podría estandarizar un poco más el proceso para que sea realizado por el algoritmo y sea más sencillo generar la matriz con más puntos. Tarea.

7.2.1 EDP Elípticas método iterativo

con el resultado desarrollado en EDP elípticas para:

\frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{ \partial y^2} = 0

y con el supuesto que: \lambda = \frac{(\Delta y)^2}{(\Delta x)^2} = 1

se puede plantear que:

u_{i+1,j}-4u_{i,j}+u_{i-1,j} + u_{i,j+1} +u_{i,j-1} = 0

que reordenando para un punto central desconocido se convierte a:

u_{i,j} = \frac{1}{4} \big[ u_{i+1,j}+u_{i-1,j} + u_{i,j+1} +u_{i,j-1} \big]

con lo que se interpreta que cada punto central es el resultado del promedio de los puntos alrededor del rombo formado en la malla.

El cálculo numerico se puede realizar de forma iterativa haciendo varias pasadas en la matriz, promediando cada punto. Para revisar las iteraciones se controla la convergencia junto con un máximo de iteraciones.

# Ecuaciones Diferenciales Parciales
# Elipticas. Método iterativo
import numpy as np

# INGRESO
# Condiciones iniciales en los bordes
Ta = 60
Tb = 60
Tc = 50
Td = 70
# dimensiones de la placa
x0 = 0
xn = 2
y0 = 0
yn = 1.5
# discretiza, supone dx=dy
dx = 0.25 
dy = 0.25 
maxitera = 100
tolera = 0.0001

# PROCEDIMIENTO
xi = np.arange(x0,xn+dx,dx)
yj = np.arange(y0,yn+dy,dy)
n = len(xi)
m = len(yj)
# Matriz u
u = np.zeros(shape=(n,m),dtype = float)
# valores en fronteras
u[0,:]   = Ta
u[n-1,:] = Tb
u[:,0]   = Tc
u[:,m-1] = Td

# valor inicial de iteración
promedio = (Ta+Tb+Tc+Td)/4
u[1:n-1,1:m-1] = promedio
# iterar puntos interiores
itera = 0
converge = 0
while not(itera>=maxitera or converge==1):
    itera = itera +1
    nueva = np.copy(u)
    for i in range(1,n-1):
        for j in range(1,m-1):
            u[i,j] = (u[i-1,j]+u[i+1,j]+u[i,j-1]+u[i,j+1])/4
    diferencia = nueva-u
    erroru = np.linalg.norm(np.abs(diferencia))
    if (erroru<tolera):
        converge = 1

# SALIDA
np.set_printoptions(precision=2)
print('converge = ', converge)
print('xi=')
print(xi)
print('yj=')
print(yj)
print('matriz u')
print(u)

Un ejemplo de resultados:

converge = 1
xi=
[ 0.    0.25  0.5   0.75  1.    1.25  1.5   1.75  2.  ]
yi=
[ 0.    0.25  0.5   0.75  1.    1.25  1.5 ]
matriz u
[[ 50.    60.    60.    60.    60.    60.    70.  ]
 [ 50.    55.6   58.23  60.    61.77  64.4   70.  ]
 [ 50.    54.15  57.34  60.    62.66  65.85  70.  ]
 [ 50.    53.67  56.97  60.    63.03  66.33  70.  ]
 [ 50.    53.55  56.87  60.    63.13  66.45  70.  ]
 [ 50.    53.67  56.97  60.    63.03  66.33  70.  ]
 [ 50.    54.15  57.34  60.    62.66  65.85  70.  ]
 [ 50.    55.6   58.23  60.    61.77  64.4   70.  ]
 [ 50.    60.    60.    60.    60.    60.    70.  ]]
>>>

Cuyos valores se interpretan mejor en una gráfica, en este caso 3D:

La gráfica de resultados requiere ajuste de ejes, pues el índice de filas es el eje x, y las columnas es el eje y. La matriz graficada se obtiene como la transpuesta de u

# Gráfica
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D

X, Y = np.meshgrid(xi, yj)
U = np.transpose(u) # ajuste de índices fila es x

figura = plt.figure()
ax = Axes3D(figura)
ax.plot_surface(X, Y, U,
                rstride=1,
                cstride=1,
                cmap=cm.Reds)

plt.title('EDP elíptica')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

7.2 EDP Elípticas

Referencia: Chapra 29.1 p866 pdf890, Rodriguez 10.3 p425, Burden 12.1 p694 pdf704

Las Ecuaciones Diferenciales Parciales tipo elípticas semejantes a la mostrada:

\frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{ \partial y^2} = 0

(ecuación de Laplace, Ecuación de Poisson con f(x,y)=0)

se interpreta como una placa metálica de dimensiones Lx y Ly, delgada con aislante que recubren las caras de la placa, y sometidas a condiciones en las fronteras:

Lx = dimensión x de placa metálica
Ly = dimensión y de placa metálica
u[0,y]  = Ta
u[Lx,y] = Tb
u[x,0]  = Tc
u[x,Ly] = Td

Para el planteamiento se usa una malla en la que cada nodo corresponden a los valores u[xi,yj]. Para simplificar la nomenclatura se usan los subíndices i para el eje de las x y j para el eje t, quedando u[i,j].

Se discretiza la ecuación usando diferencias divididas que se sustituyen en la ecuación, por ejemplo:

\frac{u_{i+1,j}-2u_{i,j}+u_{i-1,j}}{(\Delta x)^2} + \frac{u_{i,j+1}-2u_{i,j}+u_{i,j-1}}{(\Delta y)^2}=0

Se agrupan los términos de los diferenciales:

\frac{(\Delta y)^2}{(\Delta x)^2} \Big( u_{i+1,j}-2u_{i,j} +u_{i-1,j} \Big)+ u_{i,j+1}-2u_{i,j}+u_{i,j-1}=0

con lo que se simplifican los valores como uno solo \lambda = \frac{(\Delta y)^2}{(\Delta x)^2} = 1 . Por facilidad de lo que se realiza se supone que lambda tiene valor de 1 o los delta son iguales.

u_{i+1,j}-4u_{i,j}+u_{i-1,j} + u_{i,j+1} +u_{i,j-1} = 0

Obteniendo así la solución numérica conceptual. La forma de resolver el problema determina el nombre del método a seguir.