Practica_EDOs_2011_12

135 days ago by blapermar1

Introducción a las Ecuaciones Diferenciales Ordinarias

1. Motivación y nociones básicas

En las Ciencias y la Ingeniería se desarrollan modelos matemáticos para comprender mejor los fenómenos físicos. Muchos de estos modelos provienen de fenómenos de la vida real en los que una magnitud cambia de estado con el tiempo y proporcionan una ecuación que contiene alguna(s) derivada(s) de una función desconocida o incógnita. Esta ecuación es una ecuación diferencial. Si la ecuación contiene derivadas parciales de la función incógnita, la ecuación se denomina ecuación en derivadas parciales (EDP). Si en la ecuación solo aparecen derivadas de una función desconocida de una variable, la ecuación se denomina ecuación diferencial ordinaria. Nos vamos a centrar en este último tipo de ecuaciones.

Más precisamente, una  ecuación diferencial ordinaria (EDO, en adelante) es una ecuación que relaciona una función desconocida o incógnita, y(x), con su variable independiente, x, y con una o más de sus derivadas hasta un cierto orden. En muchos casos prácticos, la variable independiente (v.i.) es el tiempo y se denota por t. Nosotros utilizaremos ambas notaciones para la v.i.

Se llama orden de una EDO al orden de la mayor derivada de la función incógnita que aparece en la ecuación. 

 Ejemplo 1.  Las  ecuaciones diferenciales  

y'''(x) -3y''(x) + \frac{1}{x}y(x) =0,

(y'(x))^4 -3x y(x) = \cos x,

x^2y''(x) + 2x y'(x) + y(x) = e^x

son, respectivamente, de tercer, primer y segundo orden.

En adelante, denotaremos y=y(x), y'=y'(x), y''=y''(x),...

Resolver una EDO consiste en encontrar, si es posible, una función (o funciones) y=y(x) que verifique(n) la EDO para cualquier x en un cierto intervalo real I. Se dirá que dicha función (o funciones) es (son) solución (soluciones) de la EDO en el intervalo I. La resolución de una EDO conlleva el cálculo de alguna integral. Por ello, a la resolución de una EDO también se le llama integración de una EDO. Resaltar que hay EDOs que no tienen solución, como la EDO

1 + (y')^2 = 0.
 Y, en el caso de que una EDO tenga solución, tiene infinitas soluciones, debido a que en el proceso de integración aparece la constante de integración.

2. Un ejemplo sencillo

Ejemplo 2. Resolver (o integrar) la EDO de primer orden 

{\rm (ed)} \quad y' = 2 x.

Se trata de hallar una función y=y(x) tal que y'(x)  = 2x (o bien \displaystyle \frac{dy}{dx} = 2x) para cualquier x en algún intervalo real I. Es claro que la función y(x) = x^2 es una solución de la ecuación (ed) para cualquier x real. Pero también es solución de (ed) cualquier  función de la forma

x^2 +C, \mbox{ para cualquier constante real C}.

De hecho, para resolver (ed), basta con integrar

\int 2x \, dx = x^2 + C.

Esta fórmula, que contiene a las infinitas soluciones de (ed), se llama solución general de (ed). Para cada valor de la constante C se obtiene una solución diferente. Cada una de ellas se llama solución particular (o curva integral) de (ed).

Este ejemplo es un caso particular del tipo de EDOs que pasamos a estudiar.

3. La EDO y'=f(x)

\noindent
Consideramos la ecuación diferencial ordinaria
(1) \qquad y'=f(x),
donde f es una función continua en su dominio de definición D = Dom(f).
Una solución en un intervalo I \subset D de~(1) es cualquier función y=\phi(x), que verifique \phi\,'(x)=f(x),\, para cada
x \in I. La fórmula que proporciona el cálculo
integral de las infinitas primitivas de f
%
\phi(x,C)=\int\!f(x)\,dx+C, \quad \mbox{con } C \in \R,  
%
es la {\it solución general} de la
ecuación diferencial y contiene a las infinitas soluciones de (1). Para cada valor de la constante de integración C
se obtiene una única primitiva de f y una única {\it solución particular} de la EDO.
\vspace{-0.25\baselineskip}
\noindent
\begin{itemize}
\item[-] Las primitivas conocidas (que se expresan con un número finito de
funciones elementales) se obtienen con cualquier programa
\emph{razonable} de cálculo simbólico. En particular, cualquier 
\int\!f(x)\,dx\, inmediata.
\vspace{-0.25\baselineskip}
\item[-] ``Cada punto (x_0,y_0) adecuado'' del plano determina una única solución \emph{global},
\phi(x)=y_0+\int_{x_0}^x\!f(t)\,dt,  que pasa por el punto (x_0,y_0), es
decir, que verifica \phi(x_0)=y_0 (para convencerse de ello, basta integrar --respecto de t-- entre x_0 y x la expresión \phi\,'(t)=f(t), con x_0, x \in D).
\item[-] Si no hay fórmula para \displaystyle \int_{x_0}^x\!f(t)\,dt, se puede aproximar
integrando series de potencias, Fourier, etc.
\vspace{-0.25\baselineskip}
\item[-] Alternativamente, el valor \displaystyle \int_{x_0}^x\!f(t)\,dt se puede
aproximar con la regla del trapecio o de Simpson.
\end{itemize}

Consideramos la EDO de primer orden

(1) \qquad y'=f(x),

donde f es una función continua en su dominio de definición D = Dom \, (f). La fórmula que proporciona el cálculo

integral de las infinitas primitivas de f

\varphi(x,C)=\int\, f(x) \,dx+C, \quad \mbox{ para cualquier valor real de C},
 es la solución general de (1) y contiene a sus infinitas soluciones particulares (o curvas integrales). Para cada valor de la constante de integración C se obtiene una única primitiva de f y una única solución particular de la EDO.

Las primitivas conocidas (que se expresan con un número finito de funciones elementales) se obtienen con cualquier programa razonable de cálculo simbólico. En particular, también con Sage, como veremos.

4. La EDO de primer orden y' = f(x,y)

Las EDOs de primer orden son las más sencillas de estudiar.  Las podemos expresar en su forma implícita:

 F(x, y, y') = 0

o en su forma normal (o explícita):

 y' = f(x, y).

Ejemplo 3. La EDO 1 + y^2 + x y y' = 0 se puede escribir en forma normal (sin más que despejar y' de la expresión dada):   

y' =f(x,y)= - \displaystyle \frac{1+y^2}{xy}.

Nos centraremos en las EDOs de primer orden escritas en forma normal.

Una solución particular (o curva integral) de la EDO  

 (2) \qquad y' = f(x, y)
 en un intervalo real I  es cualquier función y=\varphi(x ), que verifique
\varphi'(x)=f(x,\varphi(x)) \qquad  \mbox{para cada } x \mbox{ del intervalo }I .
 Si (2) tiene solución, su solución general es una familia 
y=\varphi(x,C)
 de curvas del plano de tal manera que cada curva de la familia (que se obtiene dando un valor concreto a la constante C) es una solución particular de (2).

Ejercicio: Sin hacer uso del ordenador, compruébese que \varphi_1(x)=e^{-2x}+1-2x+2x^2 es una solución en toda la recta real de la EDO

y'+2y=4x^2
y que, de hecho, cualquier curva de la familia \varphi(x,C)=Ce^{-2x}+1-2x+2x^2 (donde C es una constante arbitraria) es solución de la EDO.

 

4.1 Obtención con Sage de la solución general de una EDO de primer orden

Los métodos de resolución de EDOs son muy limitados y, en general, no cabe esperar resolver de forma explícita una ecuación diferencial ordinaria cualquiera dada. Se conoce solo una colección finita de tipos de EDOs con método explícito de resolución, como las ecuaciones diferenciales de primer orden lineales (homogéneas y no homogéneas), las de Bernoulli, las exactas, las reducibles a exactas con factor integrante, las homogéneas y algunas reducibles a ellas... La mayoría de ellos están implementados en los programas usuales de cálculo simbólico.

Para resolver con Sage una EDO de primer orden, tenemos que:

  • declarar la variable independiente x;
  • declarar la función incógnita como una función que depende de x;
  • almacenar la ecuación diferencial en una variable (por ejemplo, de), utilizando la orden diff(y,x) para la derivada de y respecto de x;
  • resolver la ecuación diferencial utilizando la orden desolve La sintaxis de esta orden es:
desolve(de, [dvarivar]show_method=False)

donde:

  • de - es una expresión o ecuación que representa la EDO
  • dvar - es la variable dependiente (para nosotros será y)
  • ivar - (opcional) es la variable independiente (para nosotros será x)
  • show_method - (opcional) si es show_method=true, entonces Sage devuelve el par [solution, method], donde method es el método que se ha usado para resolver la ecuación.

Salida de Sage:

En la mayoría de los casos Sage devuelve la solución en forma implícita. Si el resultado es de la forma y(x)=... (cosa que ocurre para las ecuaciones lineales), devuelve solo el segundo miembro. Las posibles soluciones constantes de las EDOs separables son omitidas.

Observaciones:

a) Al almacenar la ecuación diferencial, póngase cuidado en no confundir la asignación "=" con el signo de igualdad "==".

b) Se pueden añadir otros atributos a la orden desolve.

c) Hay otros métodos de resolución de EDOs con Sage (como desolve_Laplace,...),  que no estudiaremos aquí.

 

4.2. Algunos ejemplos de resolución de EDOs de primer orden

Ejemplo 4. Comenzamos resolviendo la EDO 

y'=2x,
 que vimos como primer ejemplo.

x = var('x'); y = function('y',x) ED = diff(y,x) == 2*x desolve(ED, [y,x],show_method=true) 
       
[x^2 + c, 'linear']
[x^2 + c, 'linear']

También podemos resolver la ecuación anterior almacenándola en la forma

y' - 2x=0.

ED0 = diff(y, x) - 2*x == 0 desolve(ED0, [y,x],show_method=true) 
       
[x^2 + c, 'linear']
[x^2 + c, 'linear']
  1. Asimismo, podría usarse directamente la orden desolve sin almacenar previamente la EDO en una variable. Aquí no añadimos el atributo show_method, que era opcional.
desolve(diff(y,x) - 2*x == 0, [y,x]) 
       
x^2 + c
x^2 + c

Ejemplo 5. Es claro que cualquier función de la forma \frac{1}{2} e^{2x} +C es solución de la EDO y' = e^{2x} (de hecho, es su solución general). Lo comprobamos con Sage: 

ED00 = diff(y, x) == exp(2*x) desolve(ED00, [y,x]) 
       
c + 1/2*e^(2*x)
c + 1/2*e^(2*x)

Con desolve podemos resolver ecuaciones diferenciales ordinarias de primer orden, que no sean necesariamente de la forma y'=f(x).

Ejemplo 6. Resolvamos las siguientes EDOs de primer orden:

1) y'= y \qquad 2) y'= 7y\qquad 

(ejemplos de ecuaciones de primer orden lineales homogéneas).

ED1 = diff(y, x) ==y desolve(ED1, [y,x],show_method=true) 
       
[c*e^x, 'linear']
[c*e^x, 'linear']
ED2 = diff(y, x) == 7*y desolve(ED2, [y,x],show_method=true) 
       
[c*e^(7*x), 'linear']
[c*e^(7*x), 'linear']

3) 2y'+y=3 \qquad 4) y'-2xy=x

(ejemplos de ecuaciones de primer orden lineales no homogéneas)

ED3 = 2*diff(y, x) + y ==3 desolve(ED3, [y,x],show_method=true) 
       
[(c + 3*e^(1/2*x))*e^(-1/2*x), 'linear']
[(c + 3*e^(1/2*x))*e^(-1/2*x), 'linear']
ED4 = diff(y, x) - 2*x*y ==x desolve(ED4, [y,x],show_method=true) 
       
[1/2*(2*c - e^(-x^2))*e^(x^2), 'linear']
[1/2*(2*c - e^(-x^2))*e^(x^2), 'linear']

5) y' + y = x y^2 (ejemplo de ecuación de Bernoulli)

ED5 = diff(y, x) + y == x * y^2 desolve(ED5, [y,x],show_method=true) 
       
[e^(-x)/((x + 1)*e^(-x) + c), 'bernoulli']
[e^(-x)/((x + 1)*e^(-x) + c), 'bernoulli']

6) yy' + 3x=0 (ejemplo de ecuación de variables separables)

ED7 = diff(y, x) + y == x * y^2
desolve(ED7, [y,x])
ED6 = y*diff(y, x) +3* x ==0 desolve(ED6, [y,x],show_method=true) 
       
[-1/6*y(x)^2 == 1/2*x^2 + c, 'separable']
[-1/6*y(x)^2 == 1/2*x^2 + c, 'separable']

Si la EDO está en forma implícita, como es este caso, al almacenar la ecuación diferencial no es necesario explicitar en el segundo miembro que está igualada a 0. En efecto, podíamos haber hecho:

ED6 = y*diff(y, x) +3* x desolve(ED6, [y,x]) 
       
-1/6*y(x)^2 == 1/2*x^2 + c
-1/6*y(x)^2 == 1/2*x^2 + c

7) y^2y' + y =3 (ejemplo de ecuación autónoma: la v.i. no aparece de manera explícita).

ED7 = y^2*diff(y, x) + y ==3 desolve(ED7, [y,x],show_method=true) 
       
[-1/2*y(x)^2 - 9*log(y(x) - 3) - 3*y(x) == c + x, 'separable']
[-1/2*y(x)^2 - 9*log(y(x) - 3) - 3*y(x) == c + x, 'separable']

8) x+y+ (x-y) y'=0 (ejemplo de ecuación exacta: de la forma M(x,y) + N(x,y) y' = 0.)

ED8 = x + y + (x-y)*diff(y, x) ==0 desolve(ED8, [y,x],show_method=true) 
       
[1/2*x^2 + x*y(x) - 1/2*y(x)^2 == c, 'exact']
[1/2*x^2 + x*y(x) - 1/2*y(x)^2 == c, 'exact']

¡Ojo!

  • Obsérvese que en los tres últimos ejemplos, la familia solución viene expresada en forma implícita.
  • EDOs difíciles pueden producir error, como vemos al intentar resolver con Sage la EDO  
    \sqrt{y}y' + e^y +\cos x - {\rm sen} (x+y)=0.
desolve(sqrt(y)*diff(y,x)+e^(y)+cos(x)-sin(x+y)==0,y) 
       
Traceback (click to the left of this block for traceback)
...
NotImplementedError: Maxima was unable to solve this ODE. Consider to
set option contrib_ode to True.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_16.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("ZGVzb2x2ZShzcXJ0KHkpKmRpZmYoeSx4KStlXih5KStjb3MoeCktc2luKHgreSk9PTAseSk="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
  File "", line 1, in <module>
    
  File "/private/var/folders/p6/p6sKk2QtEEqQa5i2wU6DrE+++TI/-Tmp-/tmpeVIkF1/___code___.py", line 3, in <module>
    exec compile(u'desolve(sqrt(y)*diff(y,x)+e**(y)+cos(x)-sin(x+y)==_sage_const_0 ,y)
  File "", line 1, in <module>
    
  File "/tmp/sage-map-app/local/lib/python2.6/site-packages/sage/calculus/desolvers.py", line 353, in desolve
    raise NotImplementedError, "Maxima was unable to solve this ODE. Consider to set option contrib_ode to True."
NotImplementedError: Maxima was unable to solve this ODE. Consider to set option contrib_ode to True.
  • De hecho, en algunos casos, Sage no es capaz de distinguir si una EDO tiene solución o no, como es el caso de la EDO
    1 + (y')^2 = 0,
    que no tiene solución. Veámoslo con Sage.
desolve(1+(diff(y,x))^2==0,y) 
       
Traceback (click to the left of this block for traceback)
...
NotImplementedError: Maxima was unable to solve this ODE. Consider to
set option contrib_ode to True.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_17.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("ZGVzb2x2ZSgxKyhkaWZmKHkseCkpXjI9PTAseSk="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))
  File "", line 1, in <module>
    
  File "/private/var/folders/p6/p6sKk2QtEEqQa5i2wU6DrE+++TI/-Tmp-/tmpD5tCJu/___code___.py", line 3, in <module>
    exec compile(u'desolve(_sage_const_1 +(diff(y,x))**_sage_const_2 ==_sage_const_0 ,y)
  File "", line 1, in <module>
    
  File "/tmp/sage-map-app/local/lib/python2.6/site-packages/sage/calculus/desolvers.py", line 353, in desolve
    raise NotImplementedError, "Maxima was unable to solve this ODE. Consider to set option contrib_ode to True."
NotImplementedError: Maxima was unable to solve this ODE. Consider to set option contrib_ode to True.

 

4.3. Problemas de Valor Inicial

Al problema de encontrar una soluci\'on particular asociada a unas condiciones
iniciales de tipo local, se la llama Problema de Valores Iniciales  (PVI) \'o problema de Cauchy.
 En este caso ser\'ia 
resolver  el PVI: \D \left\{ \begin{array}{l} y' - 2x = 0 \\ y(1) = 3 \end{array} \right.
Se llama Problema de Valor Inicial relativo a la EDO y'=f(x,y) con condición inicial y(x_0)=y_0, y se denota por  
(PVI) \quad   \left\{ \begin{array}{l} y'=f(x,y)  \\ y(x_0)=y_0, \end{array} \right.  
al problema de encontrar, si existe, una solución particular de la EDO y'=f(x,y) que pase por el punto (x_0,y_0).
  • El (PVI) puede no tener solución y, en caso de tenerla, la solución puede o no ser única.
  • El Teorema de Picard afirma: "Si f (x,y) y \displaystyle \frac{\partial f}{\partial y}(x,y) son continuas en un recinto abierto \Omega= (a,b) \times (c,d) del plano, entonces por cada punto (x_0,y_0) de \Omega pasa una única solución del (PVI) definida en un intervalo [x_0-\delta,x_0+\delta] \subset (a,b) (con \delta >0 eventualmente pequeño)."
Para resolver con Sage un (PVI), se utiliza de nuevo la orden desolve, añadiendo el atributo ics. La sintaxis ahora es:

desolve(de, [dvar, ivar],ics=[x0,y0],show_method=False)
 

 donde:

  • de, dvar, ivar, sohw_method - como antes
  • ics - (opcional) es la condición inicial, donde hay que especificar los datos iniciales x0 e y0

Ejemplo 7. Resolver el problema de valor inicial

(PVI) \quad   \left\{ \begin{array}{l} 2y' + y =3,  \\ y(1)=3. \end{array} \right.  

desolve(2*diff(y,x) + y - 3, [y,x], ics=[1,3]) 
       
3
3

Se ha obtenido la solución constante y(x)=3, solución definida en toda la recta real. De hecho, la solución y(x)=3 es la única curva integral de la EDO 2y'+y=3 que pasa por el punto (1,3).

¡Ojo! Hay que tener cuidado pues Sage, como otros programas de cálculo simbólico, a veces, comete errores. Hay que pensar en estos programas como ayuda de cálculo, pero hay que utilizarlos con cuidado. 

Podemos ver ejemplos de (PVI) que no tienen solución única para los cuales Sage da una única salida como solución.

En efecto, pueden construirse infinitas soluciones del 

(PVI) \quad   \left\{ \begin{array}{l} y'  =y^{2/3} \\ y(0)=0, \end{array} \right.  

siendo una de ellas, la función constante y(x)=0 para cada x real, mientras que la salida de Sage es

2 \sqrt{y(x)} =x,

como comprobamos a continuación:

desolve(diff(y,x) - sqrt(y), y, ics=[0,0]) 
       
2*sqrt(y(x)) == x
2*sqrt(y(x)) == x

De hecho, puede demostrarse que cualquier (PVI) de la forma

(PVI) \quad   \left\{ \begin{array}{l} y'  =y^{\alpha} \\ y(x_0)=0, \end{array} \right.  

con \alpha \in (0,1), tiene infinitas soluciones (una de ellas la solución nula). No lo vemos aquí.

 

4.4. Dibujando curvas integrales

  • Si la familia de curvas integrales de una EDO está en forma explícita, \varphi(x,c), cortando y pegando la salida de Sage, se puede almacenar dicha solución general como una función en las variables x y c para su posterior representación gráfica.

Ejemplo 8. La solución general o familia de curvas integrales de la EDO \;y'=y\; es

\varphi(x,c)=ce^x.
En primer lugar, almacenamos la solución general en la función de dos variables f(x,c)= ce^x:

x=var('x');c=var('c') f(x,c)=c*e^x 
       

(nótese que hemos tenido que declarar la variable c). A continuación, como vimos en la Práctica 1, con el método .plot podemos representar varias curvas integrales, por ejemplo,

en el intervalo [-4,4], para los valores c=1,2,3,4,5 (por ejemplo) de la constante c.

dibujo1=f(x,1).plot(-4,4,color='green') dibujo2=f(x,2).plot(-4,4,color='blue') dibujo3=f(x,3).plot(-4,4,color='red') dibujo4=f(x,4).plot(-4,4,color='orange') dibujo5=f(x,5).plot(-4,4,color='black') dibujototal=dibujo1+dibujo2+dibujo3+dibujo4+dibujo5; show(dibujototal) 
       
  • Podemos dibujar soluciones particulares mediante el método append. Veámoslo con el siguiente ejemplo.

Ejemplo 9. Dibujamos algunas soluciones particulares de la EDO

xy' = 2y + x^3.

x = var('x'); y = function('y',x) DE = x*diff(y, x) == 2*y + x^3 desolve(DE, [y,x]) # answer : (c + x)*x^2 sol=[] for i in srange(-2, 2, 0.2): sol.append(desolve(DE, [y, x], ics=[1, i])) sol.append(desolve(DE, [y, x], ics=[-1, i])) g=plot(sol, x, -2, 2) g.show() 
       

Para apreciar mejor el comportamiento de las curvas integrales (o soluciones particulares) cerca del origen, podemos hacer un zoom y representar, por ejemplo, soluciones particulares con la variable dependiente y entre -10 y 10:

g.show(ymin=-10, ymax=10) 
       

O con un zoom mayor, por ejemplo, con y \in [-2,2]:

g.show(ymin=-2, ymax=2) 
       

4.5. Campo de direcciones

En general, las soluciones de una EDO de primer orden no se pueden
hallar de forma explícita, ni siquiera en el caso lineal (las
integrales involucradas no suelen tener primitivas elementales). Por
ello, se suelen utilizar \emph{esquemas gráficos}, para visualizar su
comportamiento, y \emph{métodos numéricos}, para aproximar sus
valores.

En general, las soluciones de una EDO de primer orden no se pueden hallar de forma explícita, ni siquiera en el caso lineal (pues las integrales involucradas pueden tener primitivas no elementales). Por ello, se suelen utilizar esquemas gráficos, para visualizar su comportamiento, y métodos numéricos, para aproximar sus valores.

Interpretación geométrica de la solución de un (PVI)

Supongamos dado un 

  (PVI) \quad   \left\{ \begin{array}{l} y'=f(x,y)  \\ y(x_0)=y_0, \end{array} \right.  

con solución única \varphi(x) en un intervalo real I que contine a x_0 en su interior. En particular,  y= \varphi(x) verifica

\varphi(x_0)=y_0 \quad \mbox{y} \quad \varphi'(x_0)= f(x_0,\varphi(x_0)) = f(x_0,y_0), 

es decir, la curva y= \varphi(x) pasa por el punto (x_0,y_0) y la pendiente de la recta tangente a y= \varphi(x) que pasa por dicho punto (x_0,y_0) tiene pendiente  f(x_0,y_0). De este modo, aunque no conozcamos la expresión explícita de la solución \varphi(x) podemos hacer un esbozo de ella "cerca del punto (x_0,y_0)",  dibujando su aproximación lineal mediante un segmento que pase por (x_0,y_0) con pendiente \varphi'(x_0)=f(x_0,y_0).

Si esto lo hacemos con cada punto (x_0,y_0) de un recinto dado del plano, obtenemos el campo direccional o campo de direcciones.

Representación gráfica del campo de direcciones

Los programas usuales de cálculo numérico o simbólico suelen implementar el dibujo de campos direccionales. Sage dibuja el campo de direcciones con la orden plot_vector_field. Veamos su sintaxis con la EDO del ejemplo anterior:

xy' =2y + x^3.

Nota importante: Si la pendiente de la recta tangente a la curva y= \varphi(x) que pasa por el punto (x,y) es f(x, y), un vector director de dicha recta es (1, f(x,y))también  (\lambda, \lambda f(x,y)) para cualquier \lambda real no nulo. Como en el ejemplo que vamos a tratar es f(x,y) = 2y/x + x^2, se toma en el punto (x,y) el vector director (x, xf(x,y)).

y = var('y') g = plot_vector_field((x,2*y+x^3), (x, -.5, .5), (y, -.5, .5)) g.show(ymin=-.5, ymax=.5) 
       

Podemos también representar gráficamente las curvas integrales junto con el campo de direcciones. Lo hacemos para el mismo ejemplo:

x = var('x'); y = function('y',x) DE = x*diff(y, x) == 2*y + x^3 desolve(DE, [y,x]) # answer : (c + x)*x^2 sol=[] for i in srange(-2, 2, 0.2): sol.append(desolve(DE, [y, x], ics=[1, i])) sol.append(desolve(DE, [y, x], ics=[-1, i])) g=plot(sol, x, -2, 2) y = var('y') g += plot_vector_field((x,2*y+x^3), (x, -2, 2), (y, -1, 1)) g.show(ymin=-1, ymax=1) 
       

Representemos ahora en el rectángulo [0,1]\times [0,1] curvas integrales y el campo de direcciones de la EDO

2y' + y -3 =0.
Podemos tomar en el punto (x,y) el vector director (1,f(x,y)) = (1,(3-y)/2) o cualquier vector proporcional a él, como (2,2f(x,y)) = (2,3-y). En Sage cogemos este último.

x = var('x'); y = function('y',x) DE = 2*diff(y, x) + y == 3 desolve(DE, [y,x]) sol=[] for i in srange(0, 3, 0.1): sol.append(desolve(DE, [y, x], ics=[1, i])) sol.append(desolve(DE, [y, x], ics=[-1, i])) g=plot(sol, x, 0, 1) y = var('y') g += plot_vector_field((2,3-y), (x, 0, 1), (y, 0, 1)) g.show(ymin=0, ymax=1) 
       

Finalmente, para la misma EDO, 2y' + y -3 = 0, vamos a representar en el rectángulo [0,8] \times [-2,6] el campo direccional y las curvas integrales (o soluciones particulares) que pasan por los puntos (0,-2), (0,0), (0,2), (0,4) y (0,6).

x = var('x'); y = function('y',x) DE = 2*diff(y, x) + y == 3 desolve(DE, [y,x]) sol=[] for i in srange(-2, 8, 2): sol.append(desolve(DE, [y, x], ics=[0, i])) g=plot(sol, x, 0, 8) y = var('y') g += plot_vector_field((2,3-y), (x, 0, 8), (y, -2, 6)) g.show(ymin=-2, ymax=6) 
       

4.6. Métodos numéricos de resolución de EDOs de primer orden: Métodos de Euler y de Heun

Nuevamente, supongamos dado un 

  (PVI) \quad   \left\{ \begin{array}{l} y'=f(x,y)  \\ y(x_0)=y_0, \end{array} \right.  

con solución única \varphi(x) en un intervalo real I que contine a x_0 en su interior. Resolver numéricamente el (PVI) dado consiste en considerar un conjunto finito 

x_0 \quad < \quad x_1  \quad < \quad x_2   \quad < \ldots < \quad x_N  

de puntos del intervalo I y obtener una aproximación, y_i, del valor exacto \varphi(x_i), para cada i=0,1, \ldots, N. Supondremos que los puntos son equidistantes, es decir, 

x_0 \quad < \quad x_1 = x_0 + h \quad < \quad x_2 = x_1 + h \quad < \ldots < \quad x_N = x_{N-1} + h,
 donde h>0 es el llamado "paso". Estudiaremos dos métodos de resolución numérica de EDOs de primer orden: el Método de Euler y el Método de Heun. Ambos son métodos iterados o iterativos, es decir,  conocido y_0, obtendremos y_i a partir de y_{i-1}, para cada i=1,\ldots,N.

4.6.1. Método de Euler (o de la tangente):

Conocido y_0, el Método de Euler aproxima \varphi(x_1) mediante y_1 \equiv el valor en x_1 de la recta tangente a la curva y=\varphi(x) en el punto (x_0, y_0), cuya pendiente es \varphi'(x_0) = f(x_0,y_0). Esta recta tangente tiene por ecuación

y = y_0 + f(x_0,y_0) (x - x_0),

de donde

\varphi(x_1) \simeq y_1 = y_0 + f(x_0,y_0) (x_1 - x_0) = y_0 + h \cdot f(x_0,y_0) .

El proceso se repite, obteniendo:

\varphi(x_2) \simeq y_2 = y_1+ h \cdot f(x_1,y_1) ,

\varphi(x_3) \simeq y_3 = y_2+ h \cdot f(x_2,y_2) 

...

\varphi(x_n) \simeq y_n= y_{n-1}+ h \cdot f(x_{n-1},y_{n-1}) .

Así, el esquema iterativo (o algoritmo) del Método de Euler es:

  (Euler) \quad   \left\{ \begin{array}{l} \mbox{Conocido } y_0,  \\ y_i = y_{i-1}+ h \cdot f(x_{i-1},y_{i-1}), \mbox{ para } i=1, \ldots, N. \end{array} \right.  

Para resolver con Sage el (PVI) mediante el Método de Euler, se utiliza la orden eulers_method, cuya sintaxis es:

eulers_method(f,x0,y0,h,b) (aquí, h es el paso y b es x_N).

Previamente, hemos de declarar x e y mediante la orden  x,y=PolynomialRing(QQ,2,"xy").gens().
Si no lo hacemos, Sage nos da un error, avisándonos de que no hemos definido y.

Al utilizar la orden eulers_method, Sage da como salida tres columnas, en las que aparecen, respectivamente, los valores  x_i, \;y_i \; y \;h \cdot f(x_i,y_i) (para i=0,1,\ldots,N).


Ejemplo 10. Mediante dos pasos del Método de Euler, obtener una aproximación de \varphi(1), siendo \varphi la única solución del

  (PVI) \quad   \left\{ \begin{array}{l} y'= 5x + y -5  \\ y(0)=1. \end{array} \right.

Es claro que f(x,y) = 5x + y -5, x_0=0, y_0=1, h = \frac{1}{2}b= 1 .

x,y=PolynomialRing(QQ,2,"xy").gens(); eulers_method(5*x+y-5,0,1,1/2,1) 
       
         x                    y                  h*f(x,y)
         0                    1                   -2
       1/2                   -1                 -7/4
         1                -11/4                -11/8
         x                    y                  h*f(x,y)
         0                    1                   -2
       1/2                   -1                 -7/4
         1                -11/4                -11/8

O bien, con decimales:

eulers_method(5*x+y-5,0,1,0.5,1) 
       
         x                    y                  h*f(x,y)
         0                    1    -2.00000000000000
0.500000000000000    -1.00000000000000    -1.75000000000000
1.00000000000000    -2.75000000000000    -1.37500000000000
         x                    y                  h*f(x,y)
         0                    1    -2.00000000000000
0.500000000000000    -1.00000000000000    -1.75000000000000
1.00000000000000    -2.75000000000000    -1.37500000000000

Observamos que Sage devuelve tres columnas, con los valores respectivos de x_i, y_i y h \cdot f(x_i,y_i), para i=0,1,...,N (siendo N=2 en este caso).

Ejemplo 11. Para el 

  (PVI) \quad   \left\{ \begin{array}{l} y'= 4y +1 - x  \\ y(0)=1, \end{array} \right.

obtener una aproximación de \varphi(1) utilizando el Método de Euler con paso h=0.2, siendo \varphi la única solución del (PVI).

Es claro que ahora f(x,y) = 4y + 1 - x, x_0=0, y_0=1, h = 0.2 (por tanto, N =  \displaystyle \frac{b-x_0}{h} = \frac{1 - 0}{0.2}= 5 ) y b= 1. Con Sage obtenemos la aproximación:

eulers_method(4*y+1-x,0,1,0.2,1) 
       
         x                    y                  h*f(x,y)
         0                    1     1.00000000000000
0.200000000000000     2.00000000000000     1.76000000000000
0.400000000000000     3.76000000000000     3.12800000000000
0.600000000000000     6.88800000000000     5.59040000000000
0.800000000000000     12.4784000000000     10.0227200000000
1.00000000000000     22.5011200000000     18.0008960000000
         x                    y                  h*f(x,y)
         0                    1     1.00000000000000
0.200000000000000     2.00000000000000     1.76000000000000
0.400000000000000     3.76000000000000     3.12800000000000
0.600000000000000     6.88800000000000     5.59040000000000
0.800000000000000     12.4784000000000     10.0227200000000
1.00000000000000     22.5011200000000     18.0008960000000

o bien con números racionales

eulers_method(4*y+1-x,0,1,1/5,1) 
       
         x                    y                  h*f(x,y)
         0                    1                    1
       1/5                    2                44/25
       2/5                94/25              391/125
       3/5              861/125             3494/625
       4/5             7799/625           31321/3125
         1           70316/3125         281264/15625
         x                    y                  h*f(x,y)
         0                    1                    1
       1/5                    2                44/25
       2/5                94/25              391/125
       3/5              861/125             3494/625
       4/5             7799/625           31321/3125
         1           70316/3125         281264/15625

Aunque Sage tiene implementado el Método de Euler, también puede programarse. Presentamos a continuación una propuesta de programa y lo aplicamos al ejemplo anterior.

# Método de Euler def metodo_euler(x0,y0,b,N): # b es el punto final y N el número de pasos h = (b-x0)/N # Paso f = lambda x,y: 4*y+1-x # Aquí introducimos la función f(x,y) (segundo miembro de la EDO) nx = x0 ny = y0 # Creamos una lista para almacenar los valores w = [] w.append((0,nx,ny)) for i in range(1,N+1): ny = ny + h * f(nx,ny) nx = x0 + i * h w.append((i,nx,ny)) return w 
       
tabla_euler = metodo_euler(0,1,1,5); # Metemos en la variable "tabla_euler" la salida de valores (i,xi,yi) matriz_tabla_euler = matrix(tabla_euler); # Creamos una matriz con los valores de "tabla_euler" matriz_tabla_euler # Mostramos los valores 
       
[         0          0          1]
[         1        1/5          2]
[         2        2/5      94/25]
[         3        3/5    861/125]
[         4        4/5   7799/625]
[         5          1 70316/3125]
[         0          0          1]
[         1        1/5          2]
[         2        2/5      94/25]
[         3        3/5    861/125]
[         4        4/5   7799/625]
[         5          1 70316/3125]

En la primera columna aparecen los valores i=0,1,\ldots,N (que marcan el número de la iteración en la que estamos); en la segunda, los valores x_i (para i=0,1,\ldots,N); y, en la tercera, las aproximaciones y_i (para i=0,1,\ldots,N) de los valores \varphi(x_i) obtenidos por el Método de Euler que acabamos de programar.

También podemos mostrar las salidas con decimales:

matriz_tabla_euler.n(digits=10) # Mostramos los valores con decimales 
       
[0.0000000000 0.0000000000  1.000000000]
[ 1.000000000 0.2000000000  2.000000000]
[ 2.000000000 0.4000000000  3.760000000]
[ 3.000000000 0.6000000000  6.888000000]
[ 4.000000000 0.8000000000  12.47840000]
[ 5.000000000  1.000000000  22.50112000]
[0.0000000000 0.0000000000  1.000000000]
[ 1.000000000 0.2000000000  2.000000000]
[ 2.000000000 0.4000000000  3.760000000]
[ 3.000000000 0.6000000000  6.888000000]
[ 4.000000000 0.8000000000  12.47840000]
[ 5.000000000  1.000000000  22.50112000]

4.6.2. Método de Heun (o Método de Euler modificado) 

Conocido y_0, el Método de Heun propone aproximar \varphi(x_1) utilizando, en lugar de la recta tangente a la curva y = \varphi (x) en el punto (x_0,y_0), la recta que pasa por el punto (x_0,y_0)  que tiene por pendiente la media aritmética de las pendientes de las rectas tangentes a y = \varphi (x) en los puntos (x_0, y_0) y (x_1, \widehat{y}_1) , donde  \widehat{y}_1 = y_0 + h \cdot f(x_0, y_0) (el que se obtiene a partir de y_0 mediante el Método de Euler). Es decir, mediante el Método de Heun, se aproxima \varphi(x_1) por y_1 \equiv el valor en x_1 de la recta que pasa por el punto (x_0,y_0) y tiene pendiente 

\displaystyle \frac{f(x_0, y_0)+f(x_1, \widehat{y}_1)}{2} .

El proceso se repite para i=1, \ldots, N, obteniendo el siguiente esquema iterativo (o algoritmo) del Método de Heun:

  (Heun) \quad   \left\{ \begin{array}{l} \mbox{Conocido } y_0,  \\  \displaystyle y_i = y_{i-1}+ h \cdot \frac{ f(x_{i-1},y_{i-1}) + f(x_i,  \widehat{y}_i) }{2}, \quad \mbox{para } i=1, \ldots, N, \quad  \mbox{donde} \quad  \widehat{y}_i = y_{i-1}+ h \cdot f(x_{i-1},y_{i-1}). \end{array} \right.  

Una propuesta de programación con Sage del Método de Heun es la siguiente:

# Método de Heun def metodo_heun(x0,y0,b,N): h = (b-x0)/N f = lambda x,y: 4*y +1 - x # Aquí introducimos la función f(x,y) nx = x0 ny = y0 # Creamos una lista para almacenar los valores w = [] w.append((0,nx,ny)) for i in range(1,N+1): ny = ny + (h/2)*( f(nx,ny) + f(nx+h, ny+h*f(nx,ny)) ) nx = x0 + i * h w.append((i,nx,ny)) return w 
       

Lo aplicamos al método anterior, obteniendo:

tabla_heun = metodo_heun(0,1,1,5); # Metemos en la variable "tabla_heun" la salida de valores (i,xi,yi) matriz_tabla_heun = matrix(tabla_heun); # Creamos una matriz con los valores de "tabla_heun" matriz_tabla_heun # Mostramos los valores 
       
[                 0                  0                  1]
[                 1                1/5             119/50]
[                 2                2/5           3281/625]
[                 3                3/5       352411/31250]
[                 4                4/5     9374829/390625]
[                 5                  1 994434999/19531250]
[                 0                  0                  1]
[                 1                1/5             119/50]
[                 2                2/5           3281/625]
[                 3                3/5       352411/31250]
[                 4                4/5     9374829/390625]
[                 5                  1 994434999/19531250]

O bien con cifras decimales:

n(matriz_tabla_heun) 
       
[0.000000000000000 0.000000000000000  1.00000000000000]
[ 1.00000000000000 0.200000000000000  2.38000000000000]
[ 2.00000000000000 0.400000000000000  5.24960000000000]
[ 3.00000000000000 0.600000000000000  11.2771520000000]
[ 4.00000000000000 0.800000000000000  23.9995622400000]
[ 5.00000000000000  1.00000000000000  50.9150719488000]
[0.000000000000000 0.000000000000000  1.00000000000000]
[ 1.00000000000000 0.200000000000000  2.38000000000000]
[ 2.00000000000000 0.400000000000000  5.24960000000000]
[ 3.00000000000000 0.600000000000000  11.2771520000000]
[ 4.00000000000000 0.800000000000000  23.9995622400000]
[ 5.00000000000000  1.00000000000000  50.9150719488000]

4.6.3. Errores de aproximación mediante los Métodos de Euler y de Heun

Puede demostrarse:

  • Bajo ciertas condiciones (que f(x,y) posea derivadas parciales continuas), el error local cometido por el Método de Euler en la n-ésima iteración es de orden O(n h^2) (para cada n=1,\ldots,N). Más precisamente,

\varepsilon_n = | \varphi(x_n) - y_n) | \le \displaystyle  \frac{M_n}{2} n h^2 \sim O(n h^2), \quad n=1,\ldots,N,

  donde

\quad M_n = \max \{ \; |\varphi''(x)|\, : \; x \in [x_0, x_n] \; \}.

  • Bajo ciertas condiciones (que f(x,y) posea derivadas parciales segundas continuas), el error local cometido por el Método de Heun en la n-ésima iteración es de orden O(n h^3)   (para cada n=1,\ldots,N). Más precisamente,

\varepsilon_n = | \varphi(x_n) - y_n) | \le \displaystyle  \frac{\widetilde{M}_n}{3!} n h^3 \sim O(n h^3), \quad n=1,\ldots,N,
 donde
\widetilde{M}_n = \max \{ \; |\varphi'''(x)|  :  x \in [x_0, x_n] \; \}.

Puesto que el paso h>0 está destinado a ser pequeño, el Método de Heun supone una mejora con respecto al Método de Euler.

Por otro lado, si se conoce la solución exacta \varphi(x) del (PVI), se pueden calcular los errores locales exactos

\varepsilon_n = | \varphi(x_n) - y_n) |  \quad (n=1,\ldots,N)
 de las aproximaciones obtenidas mediante ambos métodos.

Podemos modificar ligeramente los anteriores programas realizados con Sage para el cálculo de las aproximaciones mediante los Métodos de Euler y de Heun e incluir en la salida una cuarta columna que contenga los errores locales cometidos en cada iteración.

A continuación damos una propuesta de programación con Sage del Método de Euler mostrando las aproximaciones y_i (i=0,1,\ldots,N) y los errores locales correspondientes, y lo aplicamos al Ejemplo 11.

def metodo_euler_con_error(x0,y0,b,N): h = (b-x0)/N f = lambda x,y: 4*y + 1 -x # Aquí introducimos la función f(x,y) (segundo miembro de la EDO) g = lambda x: -3/16 + x/4 + 19/16 * exp(4*x) # Aquí introducimos la solución exacta del (PVI) nx = x0 ny = y0 # Creamos una lista para almacenar los valores w = [] w.append(( 0 , nx , ny , n(abs(g(nx)-ny)) ) ) # Esto guarda [i=0,x0,y0,e(0)] (e(0)=0: error inicial) for i in range(1,N+1): ny = ny + h * f(nx,ny) nx = x0 + i * h w.append(( i , nx , ny , n(abs(g(nx)- ny)) ) ) # Esto guarda [i,xi,yi,e(i)] (e(i): error en la etapa i) return w 
       
tabla_euler_con_error = metodo_euler_con_error(0,1,1,5); matriz_tabla_euler = matrix(tabla_euler_con_error); matriz_tabla_euler # Mostramos los valores 
       
[0.000000000000000 0.000000000000000  1.00000000000000
0.000000000000000]
[ 1.00000000000000 0.200000000000000  2.00000000000000
0.505329852584806]
[ 2.00000000000000 0.400000000000000  3.76000000000000 
2.03422600396920]
[ 3.00000000000000 0.600000000000000  6.88800000000000 
6.16452195201190]
[ 4.00000000000000 0.800000000000000  12.4784000000000 
16.6664796090674]
[ 5.00000000000000  1.00000000000000  22.5011200000000 
42.3966831643588]
[0.000000000000000 0.000000000000000  1.00000000000000 0.000000000000000]
[ 1.00000000000000 0.200000000000000  2.00000000000000 0.505329852584806]
[ 2.00000000000000 0.400000000000000  3.76000000000000  2.03422600396920]
[ 3.00000000000000 0.600000000000000  6.88800000000000  6.16452195201190]
[ 4.00000000000000 0.800000000000000  12.4784000000000  16.6664796090674]
[ 5.00000000000000  1.00000000000000  22.5011200000000  42.3966831643588]

Análogamente, presentamos una propuesta de programación con Sage del Método de Heun mostrando las aproximaciones y_i (i=0,1,\ldots,N) y los errores locales correspondientes, y lo aplicamos al Ejemplo 11.

def metodo_heun_con_error(x0,y0,b,N): h = (b-x0)/N f = lambda x,y: 4*y + 1 -x # Aquí introducimos la función f(x,y) (segundo miembro de la EDO) g = lambda x: -3/16 + x/4 + 19/16 * exp(4*x) # Aquí introducimos la solución exacta del (PVI) nx = x0 ny = y0 # Creamos una lista para almacenar los valores w = [] w.append(( 0 , nx , ny , n(abs(g(nx)-ny)) ) ) # Esto guarda i=0, x0, y0 y el error inicial (=0) for i in range(1,N+1): ny = ny + (h/2)*( f(nx,ny) + f(nx + h, ny + h* f(nx,ny)) ) nx = x0 + i * h w.append(( i , nx , ny , n(abs(g(nx)- ny)) ) ) # Esto guarda [i,xi,yi,e(i)] (e(i): error en la etapa i) return w 
       
tabla_heun_con_error = metodo_heun_con_error(0,1,1,5); matriz_tabla_heun_con_error = matrix(tabla_heun_con_error); matriz_tabla_heun_con_error.n(digits=10) # Mostramos los valores 
       
[0.0000000000 0.0000000000  1.000000000 0.0000000000]
[ 1.000000000 0.2000000000  2.380000000 0.1253298526]
[ 2.000000000 0.4000000000  5.249600000 0.5446260040]
[ 3.000000000 0.6000000000  11.27715200  1.775369952]
[ 4.000000000 0.8000000000  23.99956224  5.145317369]
[ 5.000000000  1.000000000  50.91507195  13.98273122]
[0.0000000000 0.0000000000  1.000000000 0.0000000000]
[ 1.000000000 0.2000000000  2.380000000 0.1253298526]
[ 2.000000000 0.4000000000  5.249600000 0.5446260040]
[ 3.000000000 0.6000000000  11.27715200  1.775369952]
[ 4.000000000 0.8000000000  23.99956224  5.145317369]
[ 5.000000000  1.000000000  50.91507195  13.98273122]

Finalmente, presentamos dos animaciones. La primera muestra gráficamente la solución exacta, \varphi(x) y la poligonal que une los puntos (x_i,y_i) (para i=0,1,\ldots,N), donde cada y_i es la aproximación de \varphi(x_i) que proporciona el Método de Euler. Nótese que en la ventana interactiva hay que introducir el segundo miembro de la EDO, f(x,y), y la solución exacta del (PVI)\varphi(x).

 

Estudiaremos dos m\'etodos: el de Euler y el de Heun, para resolver  num\'ericamente:
\mbox{P.V.I.} : \left\{ \begin{array}{l} y' = f(x,y) \\
y(x_0)=y_0 \end{array} \right.
Ambos m\'etodos tratan de buscar una aproximaci\'on a la soluci\'on exacta
y=\varphi(x) para una sucesi\'on discreta de puntos.  \
2ex]
 Esto es, se pretende dar una aproximaci\'on del valor y_i = \varphi(x_i) para los
 valores:
x_0, \; x_1 = x_0+h, \; x_2 = x_1 + h, \ldots, x_n = x_{n-1}+h, \ldots
donde el paso h > 0. \
2ex]
As\'i, obtendremos el valor aproximado de y_i = \varphi(x_i) a partir de
y_{i-1}.

 

 

 

Estudiaremos dos m\'etodos: el de Euler y el de Heun, para resolver  num\'ericamente:
\mbox{P.V.I.} : \left\{ \begin{array}{l} y' = f(x,y) \\
y(x_0)=y_0 \end{array} \right.
Ambos m\'etodos tratan de buscar una aproximaci\'on a la soluci\'on exacta
y=\varphi(x) para una sucesi\'on discreta de puntos.  \
2ex]
 Esto es, se pretende dar una aproximaci\'on del valor y_i = \varphi(x_i) para los
 valores:
x_0, \; x_1 = x_0+h, \; x_2 = x_1 + h, \ldots, x_n = x_{n-1}+h, \ldots
donde el paso h > 0. \
2ex]
As\'i, obtendremos el valor aproximado de y_i = \varphi(x_i) a partir de
y_{i-1}.

 

Estudiaremos dos m\'etodos: el de Euler y el de Heun, para resolver  num\'ericamente:

\mbox{P.V.I.} : \left\{ \begin{array}{l} y' = f(x,y) \\

y(x_0)=y_0 \end{array} \right.

Ambos m\'etodos tratan de buscar una aproximaci\'on a la soluci\'on exacta

y=\varphi(x) para una sucesi\'on discreta de puntos.  \

2ex]

 

 Esto es, se pretende dar una aproximaci\'on del valor y_i = \varphi(x_i) para los

 valores:

x_0, \; x_1 = x_0+h, \; x_2 = x_1 + h, \ldots, x_n = x_{n-1}+h, \ldots

donde el paso h > 0. \

2ex]

 

As\'i, obtendremos el valor aproximado de y_i = \varphi(x_i) a partir de

y_{i-1}.

 

 

 

Estudiaremos dos m\'etodos: el de Euler y el de Heun, para resolver  num\'ericamente:
\mbox{P.V.I.} : \left\{ \begin{array}{l} y' = f(x,y) \\
y(x_0)=y_0 \end{array} \right.
Ambos m\'etodos tratan de buscar una aproximaci\'on a la soluci\'on exacta
y=\varphi(x) para una sucesi\'on discreta de puntos.  \
2ex]
 Esto es, se pretende dar una aproximaci\'on del valor y_i = \varphi(x_i) para los
 valores:
x_0, \; x_1 = x_0+h, \; x_2 = x_1 + h, \ldots, x_n = x_{n-1}+h, \ldots
donde el paso h > 0. \
2ex]
As\'i, obtendremos el valor aproximado de y_i = \varphi(x_i) a partir de
y_{i-1}.

 

Estudiaremos dos m\'etodos: el de Euler y el de Heun, para resolver  num\'ericamente:

\mbox{P.V.I.} : \left\{ \begin{array}{l} y' = f(x,y) \\

y(x_0)=y_0 \end{array} \right.

Ambos m\'etodos tratan de buscar una aproximaci\'on a la soluci\'on exacta

y=\varphi(x) para una sucesi\'on discreta de puntos.  \

2ex]

 

 Esto es, se pretende dar una aproximaci\'on del valor y_i = \varphi(x_i) para los

 valores:

x_0, \; x_1 = x_0+h, \; x_2 = x_1 + h, \ldots, x_n = x_{n-1}+h, \ldots

donde el paso h > 0. \

2ex]

 

As\'i, obtendremos el valor aproximado de y_i = \varphi(x_i) a partir de

y_{i-1}.

 

 

He encontrado también algunos interact@, pero son un "tochaco"...

 

Partimos de (x_0, y_0). Heun propone utilizar, en vez de la tangente, el promedio en los puntos:   \D \frac{f(x_0, y_0)+f(x_1, \widehat{y}_1)}{2} ,  donde  \widehat{y}_1 = y_0 + h(f(x_0, y_0) se obtiene por Euler.
Procediendo as\'{\i} sucesivamente, obtenemos el siguiente esquema iterativo:
\left\{ \begin{array}{l}
y_0 = y_0 \\
y_{n} = y_{n-1} + h \, \D  \frac{f(x_{n-1}, y_{n-1})+f(x_n, \widehat{y}_n)}{2} ,
\; n=1, 2, \ldots
\end{array} \right.
donde \widehat{y}_n = y_{n-1} + h \, f(x_{n-1}, y_{n-1})  es el obtenido al aplicar Euler.

 

Partimos de (x_0, y_0). Heun propone utilizar, en vez de la tangente, el promedio en los puntos:   \D \frac{f(x_0, y_0)+f(x_1, \widehat{y}_1)}{2} ,  donde  \widehat{y}_1 = y_0 + h(f(x_0, y_0) se obtiene por Euler.

 

 

Procediendo as\'{\i} sucesivamente, obtenemos el siguiente esquema iterativo:

\left\{ \begin{array}{l}

y_0 = y_0 \\

y_{n} = y_{n-1} + h \, \D  \frac{f(x_{n-1}, y_{n-1})+f(x_n, \widehat{y}_n)}{2} ,

\; n=1, 2, \ldots

\end{array} \right.

donde \widehat{y}_n = y_{n-1} + h \, f(x_{n-1}, y_{n-1})  es el obtenido al aplicar Euler.

 

 

También he encontrado algunos interact@, pero son un "tochazo".

Mostramos finalmente dos animaciones. La primera animación muestra gráficamente la solución exacta y las aproximaciones que proporciona el Método de Euler (nótese que hay que introducir la función f(x,y) y la solución exacta \varphi(x)).

Finalmente, mostramos dos animaciones. La primera muestra gráficamente la solución exacta y la poligonal que se obtiene uniendo los puntos (x_i,y_i) (para i=0,1,\ldots,N), donde cada y_i es la aproximación del valor exacto \varphi(x_i) que proporciona el Método de Euler. Lo aplicamos al Ejemplo 11 (nótese que hay que introducir la función f(x,y) y la solución exacta \varphi(x))..

def tab_list(y, headers = None): ''' Converts a list into an html table with borders. ''' s = '<table border = 1>' if headers: for q in headers: s = s + '<th>' + str(q) + '</th>' for x in y: s = s + '<tr>' for q in x: s = s + '<td>' + str(q) + '</td>' s = s + '</tr>' s = s + '</table>' return s var('x y') @interact def euler_method(y_exact_in = input_box('-cos(x)+1.0', type = str, label = 'Exact solution = '), y_prime_in = input_box('sin(x)', type = str, label = "y' = "), start = input_box(0.0, label = 'x starting value: '), stop = input_box(6.0, label = 'x stopping value: '), startval = input_box(0.0, label = 'y starting value: '), nsteps = slider([2^m for m in range(0,10)], default = 10, label = 'Number of steps: '), show_steps = slider([2^m for m in range(0,10)], default = 8, label = 'Number of steps shown in table: ')): y_exact = lambda x: eval(y_exact_in) y_prime = lambda x,y: eval(y_prime_in) stepsize = float((stop-start)/nsteps) steps_shown = min(nsteps,show_steps) sol = [startval] xvals = [start] for step in range(nsteps): sol.append(sol[-1] + stepsize*y_prime(xvals[-1],sol[-1])) xvals.append(xvals[-1] + stepsize) sol_max = max(sol + [find_maximum_on_interval(y_exact,start,stop)[0]]) sol_min = min(sol + [find_minimum_on_interval(y_exact,start,stop)[0]]) show(plot(y_exact(x),start,stop,rgbcolor=(1,0,0))+line([[xvals[index],sol[index]] for index in range(len(sol))]),xmin=start,xmax = stop, ymax = sol_max, ymin = sol_min) if nsteps < steps_shown: table_range = range(len(sol)) else: table_range = range(0,floor(steps_shown/2)) + range(len(sol)-floor(steps_shown/2),len(sol)) html(tab_list([[i,xvals[i],sol[i]] for i in table_range], headers = ['step','x','y'])) 
       

Click to the left again to hide and once more to show the dynamic interactive window

Obsérvese cómo al aumentar el número de pasos (desplazando la barra a la derecha), es decir, al disminuir el paso h, la aproximación mejora.

La segunda animación muestra gráficamente la solución exacta, \varphi(x), y las aproximaciones de los valores \varphi(x_i)  proporcionados por el Método de Euler, el Método de Heun y el Método de Runge-Kutta de 4º orden (que no estudiamos aquí). Nótese que en la ventana interactiva hay que introducir nuevamente la función f(x,y) y la solución exacta \varphi(x)

def ImpEulerMethod(xstart, ystart, xfinish, nsteps, f): sol = [ystart] xvals = [xstart] h = N((xfinish-xstart)/nsteps) for step in range(nsteps): k1 = f(xvals[-1],sol[-1]) k2 = f(xvals[-1] + h,sol[-1] + k1*h) sol.append(sol[-1] + h*(k1+k2)/2) xvals.append(xvals[-1] + h) return zip(xvals,sol) def RK4Method(xstart, ystart, xfinish, nsteps, f): sol = [ystart] xvals = [xstart] h = N((xfinish-xstart)/nsteps) for step in range(nsteps): k1 = f(xvals[-1],sol[-1]) k2 = f(xvals[-1] + h/2,sol[-1] + k1*h/2) k3 = f(xvals[-1] + h/2,sol[-1] + k2*h/2) k4 = f(xvals[-1] + h,sol[-1] + k3*h) sol.append(sol[-1] + h*(k1+2*k2+2*k3+k4)/6) xvals.append(xvals[-1] + h) return zip(xvals,sol) def tab_list(y, headers = None): ''' Converts a list into an html table with borders. ''' s = '<table border = 1>' if headers: for q in headers: s = s + '<th>' + str(q) + '</th>' for x in y: s = s + '<tr>' for q in x: s = s + '<td>' + str(q) + '</td>' s = s + '</tr>' s = s + '</table>' return s var('x, y') @interact def euler_method(q = range_slider(0,10,.1,(0,6),'x range'), y_exact_in = input_box('-cos(x)+2.0', type = str, label = 'Exact solution = '), y_prime_in = input_box('sin(x)', type = str, label = "y' = "), startval = input_box(1.0, label = 'Starting value for y: '), nsteps = slider([2^m for m in range(0,10)], default = 10, label = 'Number of steps: '), show_steps = slider([2^m for m in range(0,10)], default = 8, label = 'Number of steps shown in table: ')): start = q[0] stop = q[1] y_exact = lambda x: eval(y_exact_in) y_prime = lambda x,y: eval(y_prime_in) stepsize = float((stop-start)/nsteps) steps_shown = min(nsteps,show_steps) sol2 = ImpEulerMethod(start, startval, stop, nsteps, y_prime) sol3 = RK4Method(start, startval, stop, nsteps, y_prime) sol = [startval] xvals = [start] for step in range(nsteps): sol.append(sol[-1] + stepsize*y_prime(xvals[-1],sol[-1])) xvals.append(xvals[-1] + stepsize) sol_max = max(sol + [find_maximum_on_interval(y_exact,start,stop)[0]]) sol_min = min(sol + [find_minimum_on_interval(y_exact,start,stop)[0]]) slopes = plot_slope_field(y_prime(x=x,y=y), (start,stop), (sol_min, sol_max)) exact_plot = plot(y_exact(x),start,stop,rgbcolor=(1,0,0)) euler_plot = line([[xvals[index],sol[index]] for index in range(len(sol))]) rk4_plot = line(sol3, rgbcolor = (0,0,.125)) imp_plot = line(sol2, rgbcolor = (1,0,1)) show(slopes +exact_plot + euler_plot + imp_plot+ rk4_plot,xmin=start,xmax = stop, ymax = sol_max, ymin = sol_min) if nsteps < steps_shown: table_range = range(len(sol)) else: table_range = range(0,floor(steps_shown/2)) + range(len(sol)-floor(steps_shown/2),len(sol)) html(tab_list([[i,xvals[i],sol[i],sol2[i][1],sol3[i][1],y_exact(xvals[i])] for i in table_range], headers = ['step','x','<font color="#0000FF">Euler</font>','<font color="#FF00FF">Imp. Euler</font>', '<font color="#0000bb">RK4</font>','<font color="#FF0000">Exact</font>'])) 
       

Click to the left again to hide and once more to show the dynamic interactive window