import numpy as np
import matplotlib.pyplot as plt
Buscamos obtener una aproximación de $f'$ en un punto $x$ en función de valores de $f$ en un número finito de puntos cercanos a $x$.
¿Por qué?
A partir de la definición de derivada
$$ f'(x)=\lim_{h\to0}\frac{f(x+h)-f(x)}{h} $$podemos obtener tres aproximaciones: para $h>0$
Fórmula progresiva
$$ f'(x)\approx \frac{f(x+h)-f(x)}{h}$$Fórmula regresiva
$$ f'(x)\approx \frac{f(x)-f( x -h)}{h}$$Fórmula centrada
$$ f'(x)\approx \frac{f(x+h)-f(x-h)}{2h}$$Tener en cuenta que si solo usamos una de estas fórmulas no podemos calcular la derivada al menos en un extremo del intervalo. Por ejemplo, si usamos la fórmula progresiva no podemos calcular la derivada aproximada en $b$ porque necesitamos $f(b+h)$ que, en general, es desconocido.
Dada la función $f(x)=\ln(x)$ en $[1,2]$ y para h = 0.1
y h = 0.01
.
df_p
, regresivas, df_r
, y centradas, df_c
en puntos equiespaciados, con espacio entre ellos h
, del intervalo $[1,2]$. En los cálculos no se pueden usar puntos que estén fuera de este intervalo.Notas
np.arange
.np.linspace
.np.diff(v)
que calcula $(v_2-v_1,v_3-v_2,\ldots,v_n-v_{n-1})$v
se puede usar el comando norm
. Por ejemplofrom numpy.linalg import norm
vn = norm(v)
%run Ejercicio1.py
Vemos que la fórmula centrada da lugar a un error menor. Esto se debe a que las fórmulas progresiva y regresiva son de orden 1 y la fórmula centrada es de orden 2.
¿Es posible conseguir aproximaciones de orden 2 para $f'(a)$ y $f'(b)$? Sí, si usamos un polinomio de interpolación de $f$ de $2^{o}$ grado en $x_{0}$, $x_{1}$, $x_{2}$ y $h \gt0 $ con $x_1= x_0+h$ y $x_2 = x_1+h$, siendo $y_{j}=f(x_{j})$. Una vez obtenido el polinomio de derivación, lo derivamos y sustituyendo los valores $x_{0}$ obtenemos la fórmula progresiva, sustituyendo $x_{1}$, la fórmula centrada y sustituyendo $x_{2}$ obtendremos la fórmula regresiva. Todas ellas de orden dos.
$$ \begin{array}{l} \mathbf{Progresiva}\\ f'(x_{0})\approx\dfrac{-3y_{0}+4y_{1}-y_{2}}{2h}\\ \mathbf{Centrada}\\ f'(x_{01})\approx\dfrac{-y_{0}+y_{2}}{2h}\\ \mathbf{Regresiva}\\ f'(x_{2})\approx\dfrac{y_{0}-4y_{1}+3y_{2}}{2h} \end{array} $$Que también podemos escribir de la forma:
$$ \begin{array}{l} \mathbf{Progresiva}\\ f'(x)\approx \dfrac{1}{2h}\left(-3f(x)+4f(x+h)-f(x+2h)\right)\\ \mathbf{Centrada}\\ f'(x)\approx \dfrac{1}{2h}\left(f(x+h)-f(x-h)\right)\\ \mathbf{Regresiva}\\ f'(x)\approx \dfrac{1}{2h}\left(f(x-2h)-4f(x-h)+3f(x)\right) \end{array} $$Dada la función $f(x)= x^3 + x ^2 + x$ en $[0,1]$, y h = 0.02
Nota
Para unir vectores se puede, por ejemplo
v = np.zeros(5)
v[0] = 3.
v[1:4] = np.array([5.,4,3])
v[-1] = 2.
np.concatenate
%run Ejercicio2.py
Dados $x_{0}$, $x_{1}$, $x_{2}$ con $x_1= x_0+h$ y $x_2 = x_1+h$ ($h \gt0 $), siendo $y_{j}=f(x_{j})$, una fórmula de aproximación de la derivada segunda es
$$f''(x_1)\approx \frac{1}{h^2}(y_0-2y_1+y_2)$$o también
$$f''(x)\approx \frac{f(x-h)-2f(x)+f(x+h)}{h^2}$$Dada la función $f(x)=\cos(2\pi x)$ en $[-1,0]$ y h = 0.001
Calcular y dibujar su derivada segunda exacta en $[-1,0]$ y su derivada segunda aproximada utilizando la fórmula anterior. Calcular el error relativo de la aproximación en el intervalo $[-1+h,-h]$.
%run Ejercicio3.py
Sea $\Omega =[a,b]\times[c,d]\subset \mathbb{R}^2$. Introducimos particiones uniformes
\begin{eqnarray*} a=x_1<x_2<\ldots<x_{M-1}<x_M=b \\ c=y_1<y_2<\ldots<y_{N-1}<y_N=d \end{eqnarray*}Si llamamos a un punto $(x_m,y_n)$ sus vecinos son
Podemos construir las fórmulas de forma análoga a como hicimos con las fórmulas para una variable. Por ejemplo
$\partial_x f(x_m,y_n)$
$\nabla f(x_m,y_n)=(\partial_x f(x_m,y_n),\partial_y f(x_m,y_n))$
$\mathrm{div} (\mathbb{f}(x_m,y_n))=\partial_x f_1(x_m,y_n)+\partial_y f_2(x_m,y_n)$
$\Delta f(x_m,y_n)=\partial_{xx} f(x_m,y_n)+ \partial_{yy} f(x_m,y_n)$
Pero antes de usar estas fórmulas, recordemos como se representan las funciones de dos variables, tanto escalares como vectoriales, en python.
Se representan las funciones de dos variables en coordenadas cartesianas en dominios rectangulares. Como en el caso de las funciones de una variable nosotros decidimos el número de puntos que utilizaremos en la representación.
Si queremos representar la función escalar $f(x,y)=x^2+y^2$ en $x \in [0,5]$ con paso $h_x=1$ e $y \in [-2,2]$ con paso $h_y=1$, primero creamos la malla
h = 1.
x = np.arange(0., 5. + h, h)
y = np.arange(-2., 2. + h, h)
x, y = np.meshgrid(x, y)
y hemos creado dos matrices
print(x)
print(y)
Calculamos ahora los valores de $z=f(x,y)=x^2+y^2$ para cada par de $(x_{ij},y_{ij}) \quad i=1,\ldots,m,\,j=1,\ldots,n$ siendo $m$ y $n$ el número de filas y columnas tanto de x
como de y
. Operando elemento a elemento obtenemos una matriz z
de dimensiones $m\times n$
z = -(x**2 + y**2)
print(z)
Con estas tres matrices x
, y
, z
ya podemos representar la función
$f$. Por ejemplo, si representamos la función usando las curvas de nivel
import matplotlib.cm as cm # colormap
plt.figure()
plt.contour(x, y, z, 20, cmap=cm.bwr)
plt.title(r'$f(x,y)=-x^2-y^2$', fontsize=16)
plt.show()
plt.figure()
plt.contourf(x, y, z, 20, cmap=cm.bwr)
plt.colorbar()
plt.title(r'$f(x,y)=-x^2-y^2$', fontsize=16)
plt.show()
También podemos representar la función como una superficie
from mpl_toolkits import mplot3d
fig = plt.figure(figsize=(10,5))
ax = plt.axes(projection ='3d')
ax.plot_surface(x, y, z, cmap=cm.bwr)
plt.title(r'$f(x,y)=-x^2-y^2$', fontsize=16)
plt.show()
fig = plt.figure(figsize=(10,5))
ax = plt.axes(projection ='3d')
ax.contour3D(x, y, z, 50, cmap=cm.bwr)
plt.title(r'$f(x,y)=-x^2-y^2$', fontsize=16)
plt.show()
Si queremos representar una función vectorial $\mathbb{f}=(f_1(x,y),f_2(x,y))$ podemos usar el comando quiver
f1 = lambda x, y: (x**2 + y**2)/3
f2 = lambda x, y: (x**2 - y**2)/2
plt.figure()
ax = plt.gca()
ax.quiver(x,y,f1(x,y),f2(x,y))
ax.set_xlim([-1,6])
ax.set_ylim([-3,3])
plt.show()
La orden numpy
fy, fx = np.gradient(f,hx,hy)
devuelve el gradiente (calculado numéricamente) de la función escalar f
, usando los pasos hx
y hy
. Lo calcula usando una fórmula centrada de orden dos para los puntos interiores y diferencias de orden uno o dos, progresivas o regresivas en los bordes.
Por lo tanto, la matriz que devuelve tiene las mismas dimensiones que las matrices de los argumentos de entrada.
Calcular el gradiente de una función usando la orden numpy gradient
:
hx = 0.1
y hy = 0.1
.np.linalg.norm
.%run Ejercicio4
gradient
para las funciones $f_1$ y $f_2$, con hx = 0.1
y hy = 0.1
. Dibujar en la misma figura $\mathbb{f}$ y $\text{div} (\mathbb{f})$ np.linalg.norm
.%run Ejercicio5
%run Ejercicio6