Newton Raphson

6
Newton-raphson en python MAYO 2, 2011 Una 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: 1 2 3 4 5 6 7 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

description

Programacion de newton raphson para python

Transcript of Newton Raphson

Page 1: 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

Page 2: Newton Raphson

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:

Page 3: Newton Raphson

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

Page 4: Newton Raphson

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]

Page 5: Newton Raphson

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])