- Mediante optimización se obtienen soluciones elegantes tanto en teoría como en ciertas aplicaciones.
- La teoría de optimización usa elementos comenzando con cálculo elemental y álgebra lineal básica, y luego se extiende con análisis funcional y convexo.
- Las aplicaciones en optimización involucran ciencia, ingeniería, economía, finanzas e industria.
- El amplio y creciente uso de la optimización lo hace escencial para estudiantes y profesionales de cualquier rama de la ciencia y la tecnología.
Referencia
Algunas aplicaciones son:
En esta clase veremos aspectos básicos de optimización. En específico, veremos cómo obtener máximos y mínimos de una función escalar de una variable (como en cálculo diferencial).
Basamos todos los resultados en los siguientes teoremas:
In [1]:
# Librería de cálculo simbólico
import sympy as sym
# Para imprimir en formato TeX
from sympy import init_printing; init_printing(use_latex='mathjax')
In [8]:
sym.var('x', real = True)
f = x**2
f
Out[8]:
In [12]:
df = sym.diff(f, x)
df
Out[12]:
In [14]:
x_c = sym.solve(df, x)
x_c[0]
Out[14]:
Veamos la gráfica...
In [16]:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
In [18]:
f_num = sym.lambdify([x], f, 'numpy')
x_vec = np.linspace(-5, 5, 100)
plt.plot(x_vec, f_num(x_vec))
plt.xlabel('$x$')
plt.ylabel('$x^2$')
plt.show()
Otra manera de hacer lo anterior
In [21]:
def f(x):
return x**2
In [47]:
df = sym.diff(f(x), x)
df
Out[47]:
In [48]:
x_c = sym.solve(df, x)
x_c[0]
Out[48]:
In [24]:
def g(x):
return x**3
In [26]:
dg = sym.diff(g(x), x)
x_c = sym.solve(dg, x)
x_c
Out[26]:
In [27]:
x_vec = np.linspace(-2,2,100)
plt.figure(figsize=(8,6))
plt.plot(x_vec, g(x_vec))
plt.xlabel('$x$')
plt.ylabel('$x^3$')
plt.show()
Sea $f(x)$ una función tal que $f’(c)=0$ y cuya segunda derivada existe en un intervalo abierto que contiene a $c$.
In [29]:
f = x**2
#d2f = sym.diff(f, x, x)
d2f = sym.diff(f, x, 2)
d2f
Out[29]:
In [30]:
d2f>0
Out[30]:
Por tanto, por el criterio de la segunda derivada, $f(0)=0$ es un mínimo relativo (en efecto, el mínimo global).
In [31]:
g(x)
Out[31]:
In [32]:
d2g = sym.diff(g(x), x, 2)
d2g
Out[32]:
In [33]:
d2g.subs(x, 0)
Out[33]:
In [34]:
f = x**2-6*x
f
Out[34]:
In [35]:
df = sym.diff(f, x)
df
Out[35]:
In [36]:
x_c = sym.solve(df, x)
x_c
Out[36]:
Evaluamos $f$ en los extremos y en los puntos críticos:
In [21]:
f.subs(x, 0), f.subs(x, 5), f.subs(x, x_c[0])
Out[21]:
Concluimos que el máximo absoluto de $f$ en $\left[0,5\right]$ es $0$ y se alcanza en $x=0$, y que el mínimo absoluto es $-9$ y se alcanza en $x=3$.
In [37]:
f_num = sym.lambdify([x], f, 'numpy')
x_vec = np.linspace(0, 5, 100)
plt.figure(figsize=(8,6))
plt.plot(x_vec, f_num(x_vec), 'k', label = '$y=f(x)$')
plt.plot([0], [0], '*r', label = '$(0,0=\max_{0\leq x\leq 5} f(x))$')
plt.plot([3], [-9], '*b', label = '$(3,-9=\min_{0\leq x\leq 5} f(x))$')
plt.legend(loc='best')
plt.xlabel('x')
plt.show()
In [38]:
def h(x):
return x**3-3*x
In [39]:
dh = sym.diff(h(x), x)
x_c = sym.solve(dh, x)
x_c
Out[39]:
In [40]:
h(-2.2), h(x_c[0]), h(x_c[1]), h(1.8)
Out[40]:
In [41]:
x_vec = np.linspace(-2.2, 1.8, 100)
plt.figure(figsize=(8,6))
plt.plot(x_vec, h(x_vec), 'k', label = '$y=f(x)$')
plt.plot([x_c[0]], [h(x_c[0])], '*r', label = '$\max_{-2.2\leq x\leq 1.8} h(x)$')
plt.plot([-2.2], [h(-2.2)], '*b', label = '$\min_{-2.2\leq x\leq 1.8} h(x)$')
plt.legend(loc='best')
plt.xlabel('x')
plt.show()
El procedimiento es análogo.
Si una función $f:\mathbb{R}^n\to\mathbb{R}$ alcanza un máximo o mínimo local en $\boldsymbol{x}=\boldsymbol{c}\in\mathbb{R}^n$, y $f$ es diferenciable en el punto $\boldsymbol{x}=\boldsymbol{c}$, entonces $\left.\frac{\partial f}{\partial \boldsymbol{x}}\right|_{\boldsymbol{x}=\boldsymbol{c}}=\boldsymbol{0}$ (todas las derivadas parciales en el punto $\boldsymbol{x}=\boldsymbol{c}$ son cero).
Criterio de la segunda derivada: para ver si es máximo o mínimo, se toma la segunda derivada (matriz jacobiana) y se verifica definición negativa o positiva, respectivamente.
Si se restringe a cierta región, hay ciertas técnicas. La más general, pero también la más compleja es la de multiplicadores de Lagrange.
In [42]:
sym.var('x y')
x, y
Out[42]:
In [43]:
def f(x, y):
return x**2 + y**2
In [44]:
dfx = sym.diff(f(x,y), x)
dfy = sym.diff(f(x,y), y)
dfx, dfy
Out[44]:
In [45]:
xy_c = sym.solve([dfx, dfy], [x, y])
xy_c
Out[45]:
In [46]:
x_c, y_c = xy_c[x], xy_c[y]
x_c
Out[46]:
In [49]:
d2fx = sym.diff(f(x,y), x, 2)
d2fy = sym.diff(f(x,y), y, 2)
dfxy = sym.diff(f(x,y), x, y)
Jf = sym.Matrix([[d2fx, dfxy], [dfxy, d2fy]])
Jf.eigenvals()
Out[49]:
In [50]:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
In [52]:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.linspace(-2, 2, 100)
y = x
X, Y = np.meshgrid(x, y)
ax.plot_surface(X, Y, f(X, Y))
ax.plot([x_c], [y_c], [f(x_c,y_c)], '*r')
Out[52]: