<jupyter_start><jupyter_text>Gradiente<jupyter_code>from sympy import symbols, diff, Plane, Point3D, cos, sin, Eq, Line, Point, exp, sqrt
from sympy.utilities.lambdify import lambdify
from sympy.plotting import plot3d, plot3d_parametric_line
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits import mplot3d
import numpy as np
plt.rcParams['figure.figsize'] = 12, 6
def plot_surface(f, n=300, lims=5):
    f_ = lambdify((x, y), f)
    X = np.linspace(-lims, lims, n)
    Y = np.linspace(-lims, lims, n)
    X, Y = np.meshgrid(X, Y)
    Z = f_(X, Y)
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
                       linewidth=0, antialiased=False)
    return fig, ax, surf
def gradient_descent(f, p, step=0.1 , tol=0.0001, n=200):
    x_0, y_0 = p
    pdiv1 = diff(f, x)
    pdiv2 = diff(f, y)
    dif = 20
    ns = 0
    steps = [(float(x_0), float(y_0))]
    z_0 = float(f.subs(([x, x_0], [y, y_0])))
    vals = [z_0]
    
    while dif > tol and ns < n:    
        
        grad1 = float(pdiv1.subs(([x, x_0], [y, y_0])))
        grad2 = float(pdiv2.subs(([x, x_0], [y, y_0])))
        dir1 = x_0 + step*grad1
        dir2 = y_0 + step*grad2
        z = float(f.subs(([x, dir1], [y, dir2])))
        dif = np.abs(z_0 - z)
        steps.append((float(dir1), float(dir2)))
        vals.append(z)
        x_0 = dir1
        y_0 = dir2
        z_0 = z
        ns  += 1
    return steps, vals
def plot_contour(f, p, n=1000, r=5):
    x0, y0 = p
    f_ = lambdify((x, y), f)
    X = np.linspace(x0-r, x0+r, n)
    Y = np.linspace(y0-r, y0+r, n)
    X, Y = np.meshgrid(X, Y)
    Z = f_(X, Y)
    fig,ax=plt.subplots(1,1)
    cp = ax.contourf(X, Y, Z)
    fig.colorbar(cp) # Add a colorbar to a plot
    plt.show()
def plot_path(f, steps, n=100):
    x0, y0 = steps[-1]
    x1, y1 = steps[0]
    r = np.round(np.sqrt((x0 - x1)**2 + (y0 - y1)**2 )) + 1

    f_ = lambdify((x, y), f)
    X = np.linspace(x0-r, x0+r, n)
    Y = np.linspace(y0-r, y0+r, n)
    X, Y = np.meshgrid(X, Y)
    Z = f_(X, Y)
    fig,ax=plt.subplots(1,1)
    cp = ax.contourf(X, Y, Z)
    fig.colorbar(cp) # Add a colorbar to a plot
    
    
    X = [t[0] for t in steps]
    Y = [t[1] for t in steps]
    ax.plot(X, Y, c='#EE774E')
    ax.scatter(X, Y, c='#EE774E')
    plt.show()
def random_path(f, p, step=0.1, cooling=1, tol=0.001, n=100):
    x_0, y_0 = p
    dif = 20
    ns = 0
    steps = [(float(x_0), float(y_0))]
    z_0 = float(f.subs(([x, x_0], [y, y_0])))
    vals = [z_0]
    
    while dif > tol and ns < n:
        vdir = np.random.uniform(-1,1,2)
        vdir /= np.sqrt(np.dot(vdir,vdir))
        dir1 = x_0 + step*vdir[0]
        dir2 = y_0 + step*vdir[1]
        z = float(f.subs(([x, dir1], [y, dir2])))
        if z > z_0:
            dif = np.abs(z_0 - z)
            steps.append((float(dir1), float(dir2)))
            x_0 = dir1
            y_0 = dir2
            z_0 = z
            step *= cooling
            vals.append(z)
        ns+=1
        
    return steps, vals<jupyter_output><empty_output><jupyter_text>Comentarios Sea función $f: \mathbb{R}^n \rightarrow \mathbb{R}$ una función diferenciable en un punto $a\in \mathbb{R}^n$, al vector $$\nabla f = \left(\frac{\partial f}{\partial x_1}, \ldots, \frac{\partial f}{\partial x_n} \right)$$se le conoce como vector **gradiente** (cada $\frac{\partial f}{\partial x_i}$, están evaluadas en $a$).En clase aprendimos que si $v$ es un vector unitario en $\mathbb{R}^n$, entonces, la derivada direcciónal en $a$ satisface$$ f'(a; v) = \nabla f(a) \cdot v$$A su vez, el ángulo $\theta$ entre los vectores $\nabla f(a) $ y $v$ satisface$$\cos(\theta) = \frac{\nabla f(a) \cdot v}{\lVert  \nabla f(a) \lVert \lVert v \lVert}. $$Entonces, $ \nabla f(a) \cdot v = \lVert  \nabla f(a) \lVert \cos(\theta).$ Esto implica que, $ \nabla f(a) \cdot v$ es máximo, cuando el $\theta = 0$. Es decir, la dirección de máximo crecimiento de $f$ se da en la dirección del gradiente. Comprobemos esto con los siguientes ejemplos.  Descenso por gradiente  Ejemplo 1 $f(x, y) = -x^2 - y^2$<jupyter_code>x, y, t = symbols('x y t')
f = -x*x - y*y
plot_surface(f)
print("Grafica de contorno")
plot_contour(f, (0,0))
p1, v1 = gradient_descent(f, (2,-3))
p2, v2 = random_path(f, (2, -3), step=1)
print("Ascenso por gradiente")
plot_path(f, p1)
print("Ascenso aleatorio")
plot_path(f, p2)<jupyter_output>Ascenso aleatorio<jupyter_text>Ejemplo 2: $g(x, y) = \sin(x)\cos(y)$<jupyter_code>g = sin(x) * cos(y)
plot_surface(g)
print("Grafica de contorno")
plot_contour(g, (0,0))
p1, v1 = gradient_descent(g, (2,-3))

p2, v2 = random_path(g, (2, -3))
print("Ascenso por gradiente")
plot_path(g, p1)
print("Ascenso aleatorio")
plot_path(g, p2)<jupyter_output>Ascenso aleatorio<jupyter_text>Ejemplo 3: $f(x, y) = \frac{1}{1+ x^2 + y^2}$<jupyter_code>f = 1 / (x*x + y*y + 1)
f
plot_surface(f)
print("Grafica de contorno")
plot_contour(f, (0,0))
p1, v1 = gradient_descent(f, (-3, 0), step=0.9)
p2, v2 = random_path(f, (-3, 0), step=0.9)
print("Ascenso por gradiente")
plot_path(f, p1)
print("Ascenso aleatorio")
plot_path(f, p2)<jupyter_output>Ascenso aleatorio
{'fraction_non_alphanumeric': 0.17566260398529696, 'fraction_numerical': 0.03869220352099052, 'mean_word_length': 2.89894419306184, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '545569', 'license': 'MIT', 'n_tokens_mistral': 2339, 'n_tokens_neox': 2270, 'n_words': 569, 'path': 'notebooks/Gradiente.ipynb', 'repo_name': 'luisgrivas/pynotes', 'size': '5169'}