Laboratorio de Cálculo Numérico MA-33A Sesión: Derivación Numérica Introducción Los objetivos de esta sesión son Implementar la técnica de derivación numérica de funciones y obtener fórmulas de alta precisión. Visualizar el efecto de la precisión de la fórmula de derivación cuando se usan para resolver ecuaciones diferenciales ordinarias con condiciones de borde. 1. Actividad 1 (Fórmulas de derivación numérica) En esta primera parte del laboratorio buscaremos fórmulas de derivación numérica para calcular la segunda derivada de una función en un punto x0 de su dominio. Es decir, aproximaremos L(f ) = f 00 (x0 ) mediante una fórmula numérica L̃(f ) 1.1. Breve Teorı́a: En general, las fórmulas de derivación (o de integración) numérica se obtienen aproximando la función f mediante su polinomio de interpolación Pf en una malla {x0 , x1 , . . . , xn } y derivando (o respectivamente integrando) dicho polinomio. Es decir f ≈ Pf y L(f ) ≈ L̃(f ) = L(Pf ). Usando esta idea general, se demuestra teoricamente, que siempre las fórmulas quedan expresadas en la forma n X C̃i f (xi ), L̃(f ) = i=0 donde C̃i son constantes. En este Laboratorio usaremos mallas equespaciadas (de paso h), como la que se muestra en la figura. x0 − 3h x0 − 2h x0 − h x0 x0 + h x0 + 2h x0 + 3h Por esta razón, para hacer el cálculo independiente del punto x0 y del paso de la malla, haremos el siguiente cambio de variable: g(t) = f (x0 + th), o sea x = x0 + th. Con esto, la malla de puntos xi se transformará en una malla de puntos ti del tipo {. . . , −2, −1, 0, 1, 2, . . .}. Además, el cambio de variable anterior implica que g 00 (t) = h2 f 00 (x0 + th) por lo tanto la derivada buscada de f en x0 se reduce a la derivada correspondiente de g en t0 = 0 siguiente f 00 (x0 ) = 1 1 00 g (0). h2 Con este cambio nos concentraremos en buscar una fórmula de derivación numérica para g 00 (0) del tipo g 00 (0) ≈ md X (1) Ci g(i), i=−mi donde hemos denotado por mi > 0 y md > 0 a la cantidad de puntos de la malla que están a la izquierda y a la derecha de 0. Por ejemplo, la malla de la figura siguiente, tiene 2 puntos a la izquierda y 3 a la derecha de 0. md =3 mi =2 z −2 }| { }| z −1 0 1 2 { 3 Para el cálculo de las constantes Ci usaremos una forma explı́cita (obtenida en el curso), que consiste en usar los polinomios de la base de Lagrange {`i (x)} asociados a la malla {ti }. Haciendo esto, se sabe que Ci = `00i (0). Una vez encontrada (con el computador) la fórmula de derivación para g, basta con dividirla por h2 para recuperar la fórmula de derivación de f . Es decir Ci C̃i = 2 , h y md 1 X L̃(f ) = 2 Ci f (x0 + hi). h i=−mi El método entonces para encontrar una fórmula de derivación numérica es: Primero definir la malla (o sea cuantos puntos se van a usar), Luego calcular los polinomios de la base de Lagrange y Finalmente derivar dichos polinomios. 1.2. Programación Nos concentraremos en obtener la fórmula de derivación numérica para la función g. Comience por abrir su editor de SCILAB y allı́ escribir un nuevo programa llamado derivacion.sce. En ese archivo programe la técnica de derivación detallada en el recuerdo teórico siguiendo los siguientes pasos: Para programar la malla {ti } = {−mi , . . . , −1, 0, 1, . . . , md } defina las variables mi y md con los valores 2 y 3 respectivamente (más tarde cambiaremos estos valores). Usando estas variables, defina la malla como el vector fila t=(-mi):md; Para calcular los polinomios de Lagrange, usaremos una función preprogramada por el profesor y disponible en el archivo funciones preprogramadas.sci. La función se llama Lagrange(). Para poder usar esa función: Baje el archivo funciones preprogramadas.sci de la página del Labotarorio Al principio de su programa agrege la instrucción getf("funciones preprogramadas.sci"); 2 Donde corresponda en su programa, use la instrucción L=Lagrange(t); para obtener los polinomios de la base de Lagrange para su malla. Antes de seguir avanzando, investigue un poco esta función Lagrange. Para ello digite en la ventana SCILAB (¡no en su programa!) las instrucciones siguientes: Lagrange(0) enter Lagrange([0 1]) enter Lagrange([0 1 2]) enter Lagrange([0 1 -1]) enter Abra un archivo de texto usando word (u otro procesador de testo de su elección) de nombre informe.doc e indique allı́ que polinomios se obtienen al ejecutar las instrucciones anteriores. En particular diga cuantos polinomios hay en cada caso, que grado son y cuales son (en lenguaje matemático, no computacional). Para derivar (una vez) un polinomio en SCILAB se usa la instrucción derivat. Por lo tanto, para derivar dos veces el vector de polinomios L, agregue en su programa la instrucción Lsegunda=derivat(derivat(L)); Finalmente, para evaluar un polinomio en SCILAB, se usa la instrucción horner(‘‘polinomio’’,’’punto’’). Por lo tanto, las constantes buscadas se calculan fácilmente con la instrucción C=horner(Lsegunda,0); Ejecute su programa e investigue la variable C en la ventana SCILAB. Anote los resultados en informe.doc. En particular evalúe en la ventana SCILAB las siguientes instrucciones y anote sus resultados en el informe.doc --> C [enter] --> C’ [enter] --> C’*12 [enter] Habrá notado que las constantes C fueron calculadas como un vector columna, por eso, para los informes es mejor visualizar C’. Además, los numeros obtenidos presentan decimales periodicos, por esa razón es mejor sacar el mı́nimo común multiplo 12, multiplicando todas las constantes por ese valor. La última linea es útil para guardar la variable C en un informe, ya que al trasponerlo se puede escribir en una linea y al multiplicarlo por 12 desaparecen los decimales. Con esto su programa calcula las constantes de la fórmula de derivación numérica para la función g y la malla {−2, −1, 0, 1, 2, 3}. Verifique si su programa está bien, comparando sus constantes con las definidas por la instrucción CC= [ -1 6 -30 -16 0]’/12; Ahora que el programa funciona bien y entiende lo que hace, ejecútelo para las diferentes mallas definidas por los siguientes valores. Malla 1: mi = md = 1 (O sea un punto a cada lado de x0 ) Malla 2: mi = md = 2 (O sea dos puntos a cada lado de x0 ) Malla 3: mi = 1 y md = 3 (O sea un punto a la izquierda de x0 y tres puntos a la derecha de x0 ). Malla 4: mi = 1 y md = 4. Pruebe también el caso mi = 4 y md = 1 y comente lo observado en informe.doc. Para cada caso, anote en su informe.doc los valores obtenidos de las constantes en el formato SCILAB siguiente: 3 Para la Malla 1 se obtiene: C1=[ xxx xxx xxx]’; Para la malla 2 se obtiene: C2=[ xxx xxx xxx]’ / 12; De este este modo, cuando más tarde necesite las constantes calculadas, las pueda recuperar fácilmente de su informe sin necesidad de calcularlas. 2. Actividad 2 (Precisión) En esta actividad, calcularemos la precisión de las diferentes fórmulas de derivación encontradas en la actividad 1. 2.1. Recuerdo teórico: Definición. La precisión de una fórmula de derivación numérica es el valor del número natural m tal que la fórmula es exacta para todos los polinomios de grado ≤ m y deja de ser exacta para polinomios de grado superior. Observación. Si la precisión de la fórmula de derivación es m entonces el error teórico de aproximación depende de la derivada f (m+1) (x). Por ejemplo, si una fórmula deriva exactamente a todos los polinomios de grado inferior o igual a 5, pero no a los de grado 6, entonces, se dice que su precisión es 5. En este caso, el error de derivación es de la forma f 00 (x0 ) = L̃(f ) + Kf (6) (ξ)hp . O sea depende de la sexta derivada de la función f y tiende a cero si h → 0. Observación. Claramente, si la malla tiene k puntos, la fórmula de derivación debe ser exacta para polinomios de grado ≤ (k − 1). Por lo tanto la precisión de la fórmula debe ser ≥ (k − 1). Esto cosntituye una cota inferior de la precisión. Comience por anotar en su informe.doc cuales son las cotas inferiores para la precisión de cada una de las fórmulas de derivación encontradas al final de la actividad 1 (donde se usaron diferentes mallas). Teóricamente, para encontrar la precisión de una fórmula, se pueden tomar las funciones f (x) = xn para n = 0, 1, 2 . . . calcular su segunda derivada exacta (que llamaremos Dex en el programa), su derivada numérica (que llamaremos Dnum en el programa) y ver si la diferencia es o no es cero. Sin embargo, en el computador existen los errores de redondeo los que perturban los resultados. Antes de seguir avanzando, piense en lo siguiente: Que pasa si para f (x) = x4 en x0 = 2 se obtiene Dex =24.00001 y Dnum=24.00003 ¿Significa esto que la fórmula de derivación no es exacta? o ¿sı́ es exacta, pero al evaluarla hubo un error de redondeo? Como no es posible dar una u otra respuesta con este cálculo, realizaremos los siguiente “truquito”: evaluaremos la fórmula para diferentes valores de h y haremos un gráfico del error ER (Dex,Dnum). Si 4 el error de evaluación es producido por la fórmula, este error debiera tener un gráfico que muestra que cuando h → 0 el error también. Si no, es porque el error es de redondeo (De hecho este último tiende a ∞ cuando h → 0. 2.2. Programación Guarde su programa derivadas.sce con el nombre precision.sce (save as). No borre ninguna linea, ya que la precisión será calculada para las diferentes mallas. Agregue la definición de todos los valores de h que se usarán para hacer el gráfico: h=logspace(-8,0,300)’; //matriz de 300 × 1 Ahora defina las variables n=10; y x0=2; que representan el grado del polinomio a probar y el punto de derivación. En el archivo funciones preprogramadas.sci, ya se han programado, con los nombres f0 y f2 las funciones f (x) = xn y f 00 (x) = n(n − 1)xn−2 respectivamente. Por lo tanto puede calcular inmediatamente Dex como f2(x0). Ahora el problema es calcular la derivada numérica. Recordemos que para cada valor de hk se debe calcular L̃(f, hk ) = 1 X Ci f (x0 + ti hk ). h2 i La sumatoria de esta fórmula se evalua en SCILAB como un producto matricial. En efecto, observemos que: h es una matriz de 300 × 1 y t es una matriz de 1 × m (m representa el largo de la malla). Por lo tanto la matriz h*t es de tamaño 300 × m y en la posición (i, j) contiene los valores (hi tj ) Como x0 es una constante, f0(x0+h*t) será una matriz del mismo tamaño 300 × m. Las constantes C están guardadas en una matriz columna de m × 1. Por lo tanto la sumatoria es implı́cita en el producto matricial f0(x0+h*t)*C, que entregará un vector fila de 300 × 1. Finalmente, para encontrar las 300 derivadas numéricas (una por cada hk ) basta con dividir, componente a componente, el vector anterior por h.^2. O sea Dnum= ( ) ./ h.^2; Una vez programada la derivada numérica Dnum, calcule el error relativo de la aproximación como Err=abs( (Dnum-Dex)/Dex ) + 1e-15; Grafique el error relativo producido por la derivada numérica en función de h mediante xselect();plot( log10(h) , log10(Err) ); Grabe el gráfico obtenido en grafico n10.gif. Agregue este gráfico en su informe.doc e indique donde se ven claramente las dos fuentes de error (truncación y redondeo) en el cálculo de la derivada numérica de x10 en x0 = 2. Note que el error de truncación (que no es cero, ya que n es muy grande) tiene un aspecto suave y disminuye cuando h decrece. A partir de un cierto instante aparece el error de redondeo el cual se caracteriza por su forma errática. 5 Grafique nuevamente el error relativo pero ahora cambie el valor de n a n = 2. Como n es pequeño, se sabe que no debiera haber error de truncación, sin embargo observará que en el gráfico si lo hay y crece cuando h tiende a cero. Esta es nuevamente la presencia del error de redondeo. Exporte el gráfico como grafico n2.gif e incorpórelo en su informe.doc. Anote las diferencias conceptuales entre los dos gráficos anteriores (es decir, donde están los dos errores). A partir de esto, indique en su informe (mirando el gráfico anterior) cuando hay o no error de truncación, es decir, como saber si la fórmula es “matemáticamente” exacta o no. Con esto detalle la estrategia a seguir para encontrar numéricamente la precisión de las diferentes fórmulas de derivación numérica. Use la estrategia anterior y encuentre las precisiones de las 4 fórmulas de derivación obtenidas en la actividad 1. Anote todo en su informe.doc. 3. Actividad 3. Ecuación diferencial de segundo orden con valores en los lı́mites En esta segunda parte del laboratorio usaremos las diferentes fórmulas de derivación numérica para resolver numéricamente la ecuación diferencial siguiente: Dadas, la función f : [a, b] → R y las constantes ua y ub ∈ R se desea encontrar la función u: [a, b] → R continua en [a, b] y dos veces derivable en (a, b) de modo que d2 u − 2 = f (x), ∀x ∈ (a, b) (2) dx u(a) = ua , u(b) = ub Realizaremos la experiencia numérica en el caso particular en que a = 0, b = π, f (x) = sin(x), ua = 0 y ub = 0. Este caso es interesante ya que la solución exacta de la ecuación es conocida e igual a u(x) = sin(x). Por lo tanto podremos ver si el método numérico es capaz de encontrar este resultado con un error pequeño. 3.1. Teorı́a de resolución numérica Comenzamos por dividir el intervalo [0, π] mediante una partición equiespaciada de N + 1 intervalos de largo h = N 1+1 . 0 h x0 x1 2h x2 ih Nh xi xN π xN +1 En cada punto xi = ih, i = 1, . . . , N de la malla calcularemos aproximaciones ui de la solución u(xi ). Usando las condiciones de borde del problema es útil definir u0 = 0, uN +1 = 0. Ası́, las incógnitas del problema son u1 , . . . , uN , es decir, un vector de RN . Se llama ecuación discretizada de (??) a la que resulta de usar una fórmula de derivación numérica que aproxime u00 (xi ) en términos de las incógnitas uj . La fórmula de derivación mas sencilla (y más usada) es aquella que usa un solo vecino de cada lado de x (mi=md=1). Recordará qu esta fórmula es u00 (x) ≈ u(x − h) − 2u(x) + u(x + h) h2 6 (Caso de la malla t=[-1 0 1]). En este caso, la ecuación discretizada se obtiene reemplazando esta fórmula desde el punto x1 hasta el xN . Es decir x1 1 0 0 1 u0 u1 u2 0 1 0 1 0 x2 1 0 1 u1 u2 u3 0 1 x3 0 1 0 1 0 1 se impone z}|{ = h2 f1 −h2 u00 (x1 ) ≈ − u0 +2u1 − u2 |{z} − h2 u00 (x2 ) ≈ −u1 + 2u2 − u3 = h2 f2 − h2 u00 (x3 ) ≈ −u2 + 2u3 − u4 = h2 f3 .. . .. . .. . = h2 fN . (=0) u2 u3 u4 1 0 0 1 0 1 0 un−1un u1 n+1 xn − h2 u00 (xN ) ≈ −uN −1 + 2uN − uN +1 | {z } (=0) Ordenando estas aproximaciones se obtiene un 2 −1 0 −1 2 −1 .. . A= 0 −1 2 . . .. .. 0 0 −1 sistema de ecuaciones Au = B donde 0 f1 0 f2 .. . 2 y B = h . fN −1 −1 fN 2 Es decir en lenguaje SCILAB: A=2*diag( ones(N,1) ) - diag( ones(N-1,1) , 1) - diag( ones(N-1,1), -1); b=h*h*f(x); Programación: Usando el método de derivación numérica de tres puntos, escriba un programa (actividad3.sce) que le permita resolver numéricamente la ecuación diferencial (??) según el método numérico anterior. Comience con N = 10. Indicación: N=10; h=%pi / (N+1); x=linspace(0,%pi,N+2)’; b=h*h* sin(x(2:N+1)); A=.....//ver lineas más arriba u=A\b ; Grafique la diferencia en valor absoluto entre la solución numérica y la solución exacta. Indicación: uex= sin(x); u = [0 ; u ; 0]; err= abs(u-uex); max(err) xbasc();xselect(); plot(x,err);xgrid(3); Aumente el valor de N según la progresión 20, 40, 80, etc. de modo de encontrar aquel N tal que el máximo error (max(err)) sea inferior a 10−8 En la medida que N crezca, para almacenar la matriz A será necesario aumentar el tamaño del stack de SCILAB, el cual es originalmente 1e6 (o sea, inicialmente se puede almacenar hasta un millón de datos). Para ello, al principio de su programa escriba alguna de las 4 lineas siguientes 7 clear;stacksize(2e6) //stack de 2 millones de números (16Mb) clear;stacksize(10e6) //stack de 10 millones de números (80Mb) clear;stacksize(20e6) //stack de 20 millones de números (160Mb) clear;stacksize(.....e6) //stack tan grande como su PC lo permita. Cada vez que pruebe con un valor de N registre en su informe.doc el valor de max(err) y del tiempo que demora el cálculo. Este tiempo puede tomarlo usando su reloj de pulsera o también puede agregar en su programa, antes de comenzar el cálculo, la instrucción timer(); (con ;) y después del cálculo la instrucción timer() (sin ;). Esta instrucción le mostrará los segundos usados por el PC para resolver el problema. Construya una tabla del tipo N max(err) Tiempo (seg) Cuando haya llegado a N entre 4000 y 5000, use la tabla anterior para estimar cual debiera ser el buen valor de N y cuanto se demorarı́a su PC en alcanzar el error mı́nimo requerido. Puede usar SCILAB como una calculadora, escribiendo algo ası́ como: NN =[4000 4500 5000 10000]; Merr=[1e-4 1e-5 1e-6 1e-8 ]; plot(N,log10(Merr)); donde en la variable NN va poniendo los N con que probó y en Merr los errores obtenidos. Con estos datos, comente en su informe respecto a la posibilidad de encontrar una solución numérica con error pequeño en tiempo razonable. 8