# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# + [markdown] id="view-in-github" colab_type="text"
# <a href="https://colab.research.google.com/github/maxigaarp/teaching/blob/master/optimization/Cap11-Metodo%20del%20gradiente.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>

# + id="tdFBxxfkAyqn" colab_type="code" colab={"base_uri": "https://localhost:8080/", "height": 170} outputId="963d53a3-3419-41c2-cf2d-16e2e2516405"
############### Gradient Descent ##########################

"""
This cell is for the function f(x,y)=x^2+2y^2 only

The next cell is for the method in general with symbolic math
"""


import numpy as np

x=[]

## funcion x^2+2y^2

x.append([2,1]) # punto inicial

grad = [2*x[0][0],4*x[0][1]] #gradiente [2x,4y]
k=0
print("Punto inicial:"+str(x[0]))

while np.linalg.norm(grad)>0.00001: 

    a=grad[0]**2+2*grad[1]**2 # valor del coeficiente cuadratico en obtencion de t
    b=-(2*x[k][0]*grad[0]+4*x[k][1]*grad[1]) # valor coeficiente lineal en obtencion de t
    grad=[2*x[k][0],4*x[k][1]] #gradiente [2x,4y]

    t=-1*b/2/a #valor de t
    x.append([np.round(x[k][0]-t*grad[0],3), np.round(x[k][1]-t*grad[1],3)]) # calculo del proximo x
    print("Iteration "+str(k)+", Gradient: "+str(grad)+ ", step: "+str(t)+", point: "+str(x[k]))

    k+=1
    grad=[2*x[k][0],4*x[k][1]] #gradiente [2x,4y]



# + id="tinTIdlzAyq1" colab_type="code" colab={"base_uri": "https://localhost:8080/", "height": 238} outputId="c26255cd-48a6-4784-ba28-e0002e77ac96"
##upgrade##
 



############### Symbolic Gradient Descent ###################

from sympy import symbols,diff, Symbol, Function
import numpy as np
from sympy.solvers import solve

def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0: 
       return v
    return v / norm

np.set_printoptions(formatter={'float': lambda x: "{0:0.3f}".format(x)})

n = 2 # numero de variables
z = [Symbol('z'+str(i+1)) for i in range(n)] # definicion de variables z1,z2,...,zn

#f = z[0]**4+4*z[1]**4+10*z[0]**3- 2*z[1]**2 #definicion de funcion f(z)

f = z[0]**2 + 2*z[1]**2 #funcion simple

#f = (z[0]-2)**2 + (z[1]-1)**2 -z[2]*(z[0]+z[1]-1) con esta funcion no converge 

gradient=[f.diff(zi) for zi in z] # calculo del gradiente f'(z)



x=[np.array([5,5])] #iteraciones del metodo del gradiente, valor inicial x[0]=(2,1)

t=0.3 #valor del paso fijo
maxiter=1000 #numero maximo de iteraciones
print("Punto inicial: "+str(x[0]))

#t=Symbol("t")

for k in range(maxiter):
    nablaf_xk=np.array([nf.subs([(z[i],x[k][i]) for i in range(n)]) for nf in gradient],dtype="float32") #evaluar x[k] en gradiente

    #t=solve(diff(f.subs([(z[i],x[k][i]-t*nablaf_xk[i]) for i in range(n)]), t)) por aoora solo calcula puntos criticos, por lo que se puede ir al maximo

    x.append(x[k]-t*nablaf_xk)
    
    if np.linalg.norm(nablaf_xk)<0.001: # termino del algoritmo
        print("Optimo: "+str(x[k+1]))
        break
    else:
        print("Iteration "+str(k+1)+", gradient: "+str(nablaf_xk)+", x: "+str(x[k+1]))

    
    



# + id="eL5G5r5oAyq8" colab_type="code" colab={"base_uri": "https://localhost:8080/", "height": 1000} outputId="7da8ed3f-b54e-45af-c2a7-4fadfda48b68"
import plotly.graph_objects as go

xd=np.linspace(-5,5,101)
yd=np.linspace(-5,5,101)
X,Y=np.meshgrid(xd,yd)
Z=np.array([[f.evalf(subs = dict(zip(z,[x,y]))) for x in xd] for y in yd]).astype(float)
fig = go.Figure()
fig.add_trace(go.Surface(z=Z, x=X, y=Y, opacity=0.3))

xp=np.round([p[0] for p in x])
yp=np.round([p[1] for p in x])
zp=np.array([f.evalf(subs = dict(zip(z,[p[0],p[1]]))) for p in x]).astype(float)

fig.add_trace(go.Scatter3d(x=xp, y=yp, z=zp,marker=dict(size=4,color="red"),
                                line=dict(color='darkblue',width=2)))

fig.update_layout(title='Gradient Descent', autosize=True,
                  width=1000, height=1000,
                  margin=dict(l=65, r=50, b=65, t=90))

fig.show()


# + id="qfu92Fy3AyrC" colab_type="code" colab={}




StarcoderdataJupyterScriptsDedupFiltered