Hola, siguiendo con el artículo de La Bisección con Python he añadido dos nuevos métodos para aproximar raíces de funciones. He añadido los métodos del Punto Fijo y el de la Secante. Como el código lo que tiene de nuevo respecto al anterior es aprender en Python a hacer un menú me he decidido a comentarlo un poco.
Quisiera dejar claro que éste artículo no va a tratar sobre una explicación de estos métodos iterativos con profundidad, ya que considero que hay mucho material escrito sobre ello y se puede encontrar fácilmente en cualquier biblioteca pública universitaria de ciencias, en librerías y en artículos gratuitos en formato pdf en la red. Además dichos métodos no contienen ningún misterio.
Bien, pasemos a hablar un poco del código que he realizado, el cual se compone de 6 ficheros con extensión .py. El primero es el archivo principal del proyecto, el cual he llamado Metodos.py y cuyo código es:
#!/usr/bin/python
# coding: latin-1
#import os, sys
import Menu
from Numeric import *
Menu.elmenu()
Este código no tiene ningún misterio, lo único que hace es cargar python con codificación de latin. Nos importa el fichero Menu.py que hemos implementado nosotros mismos, y de Menu.py llamamos a la función elmenu() con la instrucción Menu.elmenu()
Pasemos a ver el código del fichero Menu.py:
#!/usr/bin/python
# coding: latin-1
from math import *
import Biseccion
import PuntoFijo
import Secante
def op1 ():
a = float(input("Introduce el extremo inferior del intervalo\n"))
b = float(input("Introduce el extremo superior del intervalo\n"))
TOL = float(input("Introduce la tolerancia del metodo\n"))
Biseccion.biseccion(a, b, TOL, 100)
Biseccion.dibujar(a, b, TOL, 100)
def op2 ():
po = float(input("Introduce el valor inicial\n"))
TOL = float(input("Introduce la tolerancia del metodo\n"))
PuntoFijo.puntofijo(po, TOL, 100)
PuntoFijo.dibujar(po, TOL, 100)
def op3 ():
po = float(input("Introduce el primer valor inicial\n"))
p1 = float(input("Introduce el segundo valor inicial\n"))
TOL = float(input("Introduce la tolerancia del metodo\n"))
Secante.secante(po, p1, TOL, 100)
Secante.dibujar(po, p1, TOL, 100)
def errhandler ():
print "Tu eleccion no ha sido la correcta\n"
#menu es un diccionario que nos ayudara para hacer un menu por terminal
def elmenu ():
menu = {"1": op1, "2": op2, "3": op3}
opcion = raw_input("Por favor introduce la opcion numerica que desees\n")
menu.get(opcion, errhandler)()
Lo primero que hacemos es importar la librería matemática “math” de Python y los métodos de la Bisección, Punto Fijo y Secante, los cuales los he escrito en tres ficheros .py diferentes, lo hacemos con el trozo de código:
from math import *
import Biseccion
import PuntoFijo
import Secante
Seguidamente pasamos a definir las cosas que realizarán cada una de las opciones de que se compone nuestro menú, por ejemplo, con la opción 1 pediremos por terminal los valores de a, b y TOL, además mandamos que se ejecuten las funciones bisección y dibujar que se encuentran en Biseccion.py, el trozo de código correspondiente es:
def op1 ():
a = float(input("Introduce el extremo inferior del intervalo\n"))
b = float(input("Introduce el extremo superior del intervalo\n"))
TOL = float(input("Introduce la tolerancia del metodo\n"))
Biseccion.biseccion(a, b, TOL, 100)
Biseccion.dibujar(a, b, TOL, 100)
De igual forma se procede con op2() y op3(), sólo hay que tener en cuenta de anteponer la palabra clave def. He añadido una opción de salida del menú en caso de error:
def errhandler ():
print "Tu eleccion no ha sido la correcta\n"
Finalmente definimos la función elmenu(), la cual es la que hemos llamado en Metodos.py. Esta función se compone de un diccionario llamado menu, así pues, un menú en Python lo podemos definir mediante un diccionario como el que se ha definido en este caso. Luego la función se compone de una toma de las distintas opciones del menú mediante raw_input y menu.get. El trozo de código es:
def elmenu ():
menu = {"1": op1, "2": op2, "3": op3}
opcion = raw_input("Por favor introduce la opcion numerica que desees\n")
menu.get(opcion, errhandler)()
Seguidamente viene el código de Biseccion.py, el cual es:
#!/usr/bin/python
import Evaluar
from pylab import *
from Numeric import *
def biseccion(a, b, TOL, N):
Evaluar.dicc_seguro['x']=a
fa = eval(Evaluar.funcion, {"__builtins__":None}, Evaluar.dicc_seguro)
vectorx = zeros(N, Float64)
vectory = zeros(N, Float64)
i = 1
while i<=N :
p = (a+b)/2.0
vectorx[i-1] = p
Evaluar.dicc_seguro['x']=p
fp = eval(Evaluar.funcion, {"__builtins__":None}, Evaluar.dicc_seguro)
vectory[i-1]=fp
if (fp == 0.0) or ( (b-a)/2.0)<tol:
break
i = i+1
if (fa*fp)>0 :
a = p
else :
b = p
print "La raiz buscada es: ",p, "con", i-1,"iteraciones"
return [vectorx, vectory]
def dibujar(a,b,TOL, N):
x = arange(a,b,0.1)
vectores=biseccion(a, b, TOL, N)
subplot(211)
plot(x, eval(Evaluar.funcion), linewidth=1.0)
xlabel('Abcisa')
ylabel('Ordenada')
title('Metodo Biseccion con f(x)=' + Evaluar.funcion)
grid(True)
axhline(linewidth=1, color='r')
axvline(linewidth=1, color='r')
subplot(212)
plot(vectores[0], vectores[1], 'k.')
xlabel('Abcisa')
ylabel('Ordenada')
grid(True)
axhline(linewidth=1, color='r')
axvline(linewidth=1, color='r')
show()
Este código ya lo expliqué en el anterior artículo, se compone de dos funciones, en una de ellas realizamos el método de la bisección y en la otra función dibujamos la gráfica de la función y sus aproximaciones.
De igual forma he escrito el método del punto fijo con PuntoFijo.py
#!/usr/bin/python
import Evaluar
from pylab import *
from Numeric import *
def puntofijo(po,TOL, N):
vectorx = zeros(N, Float64)
vectory = zeros(N, Float64)
i = 1
while i<=N :
vectorx[i-1] = po
Evaluar.dicc_seguro['x']=po
fp = eval(Evaluar.funcion, {"__builtins__":None}, Evaluar.dicc_seguro)
vectory[i-1]=fp
if fabs(po-fp)<tol:
print "La raiz buscada es: ",po, "con", i-1, "iteraciones"
break
i = i+1
po = fp
return [vectorx, vectory]
def dibujar(po,TOL, N):
x = arange(po-2,po+2,0.1)
vectores=puntofijo(po, TOL, N)
subplot(211)
plot(x, eval(Evaluar.funcion), linewidth=1.0)
xlabel('Abcisa')
ylabel('Ordenada')
title('Metodo Punto Fijo con f(x)= x - ' + Evaluar.funcion)
grid(True)
axhline(linewidth=1, color='r')
axvline(linewidth=1, color='r')
subplot(212)
plot(vectores[0], vectores[1], 'k.')
xlabel('Abcisa')
ylabel('Ordenada')
grid(True)
axhline(linewidth=1, color='r')
axvline(linewidth=1, color='r')
show()
Este código hace lo mismo que Biseccion.py pero con el método del punto fijo. Para el de la secante lo he puesto en Secante.py y su código es:
#!/usr/bin/python
import Evaluar
from pylab import *
from Numeric import *
def secante(po, p1, TOL, N):
Evaluar.dicc_seguro['x']=po
qo = eval(Evaluar.funcion, {"__builtins__":None}, Evaluar.dicc_seguro)
Evaluar.dicc_seguro['x']=p1
q1 = eval(Evaluar.funcion, {"__builtins__":None}, Evaluar.dicc_seguro)
vectorx = zeros(N, Float64)
vectorx1 = zeros(N, Float64)
vectory = zeros(N, Float64)
vectory1 = zeros(N, Float64)
i = 2
while i<=N :
p = p1-(q1*(p1-po)/(q1-qo))
vectorx[i-2] = po
vectorx1[i-2] = p1
Evaluar.dicc_seguro['x']=p
fp = eval(Evaluar.funcion, {"__builtins__":None}, Evaluar.dicc_seguro)
vectory[i-2]=qo
vectory1[i-2]=q1
if fabs(po-p1)<tol :
print "La raiz buscada es: ",p, "con", i-2,"iteraciones"
break
i = i+1
po = p1
qo = q1
p1 = p
q1 = fp
return [vectorx, vectory, vectorx1, vectory1]
def dibujar(po, p1, TOL, N):
x = arange(po-2,po+2,0.1)
vectores=secante(po, p1, TOL, N)
subplot(211)
plot(x, eval(Evaluar.funcion), linewidth=1.0)
xlabel('Abcisa')
ylabel('Ordenada')
title('Metodo Secante con f(x)= ' + Evaluar.funcion)
grid(True)
axhline(linewidth=1, color='r')
axvline(linewidth=1, color='r')
subplot(212)
plot(vectores[0], vectores[1], 'r.', vectores[2], vectores[3], 'b.')
xlabel('Abcisa')
ylabel('Ordenada')
grid(True)
axhline(linewidth=1, color='r')
axvline(linewidth=1, color='r')
show()
Y lo que hace el código pues idem de idem.
Finalmente queda el código de Evaluar.py, que es:
from math import *
lista_segura = ['math','acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'de grees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
dicc_seguro = dict([ (k, locals().get(k, None)) for k in lista_segura ])
print"METODOS ITERATIVOS PARA APROXIMAR RAICES."
print "________________________________________\n"
print "1. Metodo de la Biseccion\n"
print "2. Metodo del Punto Fijo\n"
print "3. Metodo de la Secante\n"
funcion = raw_input("Introduce la funcion para la cual vas a aplicar uno de los metodos\n")
Con dicho código establec emos primero una lista de las principales funciones y constantes matemáticas para que el usuario cuando las introduzca por terminal puedan ser interpretadas correctamente por nuestro programa, es decir, que si nuestro usuario introduce por ejemplo:

Pues que lo interprete nuestro código como la fracción entre cos(x) y x, cuando le pasamos ello a la variable funcion con raqw_input.
Bueno os dejo un pantallazo de cómo quedaría el resultado del programa utilizando la función cos(x)-x con el método de la secante, usando como puntos iniciales 
Saludos :-h
Comentarios