Newton Raphson
-
Upload
anthony-hope-condori-duenas -
Category
Documents
-
view
9 -
download
1
description
Transcript of Newton Raphson
Newton-raphson en pythonMAYO 2, 2011Una vez vista un poco por encima la teoria, vamos al turrón.
En este caso vamos a implementar una clase que contenga un sistema de ecuaciones no lineales, y una serie de métodos que permitan su resolución.
Vamos a utilizar para ello python 2.6.6 y numpy 1.4.1.
Todo el código fuente se puede descargar desde esta página.
La clase Senl será una clase contenedora de un sistema de ecuaciones no lineales. Este sistema vendrá dado por una función que define las distintas ecuaciones del mismo, de manera que cada ecuación tendrá la forma:
1234567
class Senl: def __init__(self): pass
def llamada_funcion(self,x,a): resultado=self.funcion(x,a) return numpy.array(resultado)
Deberemos asociar la función que define el sistema al método Senl.funcion.
El método llamada_funcion devuelve un objeto de tipo numpy.array, de manera que cada entrada de este objeto corresponde al valor de cada una de las ecuaciones que definen el sistema, para los valores indicados por las listas x y a. x será la lista que contenga los valores de las incognitas y a será la lista que contenga los valores de las constantes si procede.
Una vez definida la forma del sistema, necesitamos una manera de calcular su matriz jacobiana. Para ello
vamos a utilizar la definición de derivada y utilizarla en su forma de diferencia finita. así:
Definimos ahora el método Senl.jacobiano:12345678910111213141516
def jacobiano(self,x,a,tol=0.001): res=[] xtemp=numpy.array(x)
x1=xtemp.copy() for i in range(len(x1)): x2=x1.copy() x2[i]+=tol r=(self.llamada_funcion(x2,a)-self.llamada_funcion(x1,a))/tol res.append(r)
jac=numpy.array(res[0]) for i in range(len(res)-1): jac=numpy.vstack((jac,numpy.array(res[i+1])))
return jac.transpose()
En este método lo primero que hacemos es crear una lista res que contendrá las columnas de la matriz jacobiana. Creamos un objeto nparray a partir de la lista x que contiene los valores de las distintas incognitas. x1 y x2 serán copias de xtemp. por cada posicion en x, al vector x2 sumamos el valor tol en esa posición. Aplicando ahora la expresión de diferencias finitas obtenemos r, columna iesima de la matriz jacobiana. Para terminar de ensamblar la matriz recorremos cada una de las columnas obtenidas y las unimos mediante el método numpy.vstack. Una vez traspuesta, ya tenemos la matriz jacobiana.
Finalmente debemos definir el método Senl.solver_newton que resolverá el sistema de ecuaciones.12345
def solver_newton(self,x0,a,max_iter=50,tol=0.0001): x1=numpy.array(x0) e=1.0 iteracion=0
while iteracion < max_iter and e > tol:
67891011121314151617
A=self.jacobiano(x1,a) B=self.llamada_funcion(x1,a) res=numpy.linalg.solve(A,B) x1=x1-res e1=abs(res.max()) e2=abs(res.min()) e=max([e1,e2]) print "error: ", e print "Nº iteracion: ",iteracion iteracion+=1 return x1
El método es definido a partir de x0, una estimación inicial de la solución, a, lista de las constantes, max_iter, número máximo de iteraciones y tol, error permitido.
A partir de estos valores, por cada nueva iteración, construimos la matriz jacobiana A gracias al método jacobiano, y el vector B. Resolvemos el sistema lineal mediante el método definido en numpy, y obtenemos así una nueva estimación de la solución x1. Calculamos el error cometido en esta iteración y lo alojamos en e. Cuando se cumplan las condiciones del bucle while, devolvemos la solución de esa última iteración.
Veamos ahora como emplear esta clase con un ejemplo:123456789101112
def f(x,a): r=[0.0]*2
r[0]=x[0]*x[1]-a[0] r[1]=x[0]+x[1]-a[1]
return r sistema=Senl()sistema.funcion=f
print sistema.solver_newton(x0=[1.0,0.0],a=[12.0,7.0])
Y ahora el código completo:123
#!/USR/BIN/ENV PYTHON#CODING:UTF-8
import numpy
4567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
class Senl: ''' CLASE QUE DEFINE UN SISTEMA DE ECUACIONES NO LINEALES Y DIFERENTES METODOS PARA HALLAR SU SOLUCION ''' def __init__(self): pass
def newton(self,paso,numero): return 0 def llamada_funcion(self,x,a): resultado=self.funcion(x,a) return numpy.array(resultado) def jacobiano(self,x,a,tol=0.001): res=[] xtemp=numpy.array(x)
x1=xtemp.copy() for i in range(len(x1)): x2=x1.copy() x2[i]+=tol r=(self.llamada_funcion(x2,a)-self.llamada_funcion(x1,a))/tol res.append(r)
jac=numpy.array(res[0]) for i in range(len(res)-1): jac=numpy.vstack((jac,numpy.array(res[i+1])))
return jac.transpose() def solver_newton(self,x0,a,max_iter=50,tol=0.0001): x1=numpy.array(x0) e=1.0 iteracion=0
while iteracion < max_iter and e > tol: A=self.jacobiano(x1,a) B=self.llamada_funcion(x1,a) res=numpy.linalg.solve(A,B) x1=x1-res e1=abs(res.max()) e2=abs(res.min()) e=max([e1,e2]) print "error: ", e print "Nº iteracion: ",iteracion iteracion+=1 return x1 if __name__ == '__main__': def f(x,a): r=[0.0]*2
r[0]=x[0]*x[1]-a[0]
545556575859606162636465666768697071727374757677787980818283848586
r[1]=x[0]+x[1]-a[1]
return r def drag(x,a): ''' FUNCION PARA DETERMINAR EL COEFICIENTE DE RODADURA DE UN COCHE X[0] SERA EL COEFICIENTE DE RODADURA A[0] SERA EL PRODUCTO DEL COEFICIENTE AERODINAMICO POR LA SUPERFICIE FRONTAL A[1] SERA LA VELOCIDAD MAXIMA DEL COCHE A[2] SERA LA MASA DEL COCHE A[3] SERA LA POTENCIA MAXIMA DEL COCHE ''' r=[0.0]*2 rho=1.204
r[0]=0.5*rho*a[0]*a[1]**3+x[0]*a[2]*9.81*a[1]-a[3] r[1]=x[1]-x[0] return r sistema=Senl() sistema.funcion=drag
print sistema.solver_newton(x0=[1.0,0.0],a=[0.61,56.67,1340.0,90000.0])