Minha solucao para o exercicio 4

Sem o tensorflow

In [1]:
import numpy as np
from scipy.optimize import minimize,  line_search
In [2]:
contaf = 0
contagrad = 0
np.set_printoptions(precision=1)

A funcao f

In [3]:
def f(x):
    global contaf
    contaf += 1
    return x[0]**2 - 102*x[0] + 101*(x[1]**2)- 92*x[1] +  90*(x[2]**2) + 2

O gradiente

In [4]:
def grad(x):
   global contagrad
   contagrad  += 1
   g = np.zeros((3))
   g[0] = 2*x[0] - 102
   g[1] = 202*x[1] - 92
   g[2] = 180*x[2]
   return g

O erro relativo de 2 pontos

In [5]:
def err(x,xnew):
    return np.linalg.norm(xnew-x)/np.linalg.norm(x)

Decida do gradiente

In [6]:
contaf = 0
contagrad = 0
x = np.array([0.5, 0.5, 0.5])
zz = 99.0
while zz > 1.0e-5:
    xnew=x-1.0e-6*grad(x)
    zz = err(x,xnew)
    x = xnew
print("xmin=",x)
print("fmin=",round(f(x),2))
print("chamadas da funcao=",contaf-1)
print("chamadas do gradiente=",contagrad)
print("total de chamadas=", contaf+contagrad-1)
xmin= [8.5e+00 4.6e-01 9.3e-08]
fmin= -812.84
chamadas da funcao= 0
chamadas do gradiente= 86116
total de chamadas= 86116

Deu meio errado - o xmin e o fmin estao errados. O que parece que aconteceu é que o passo da decida do gradiente esta tao pequeno que para por causa do erro/diferença relativa. Uma solucao é talvez neste caso diminuir a tolerancia

In [7]:
contaf = 0
contagrad = 0
x = np.array([0.5, 0.5, 0.5])
zz = 99.0
while zz > 1.0e-5/10:
    xnew=x-1.0e-6*grad(x)
    zz = err(x,xnew)
    x = xnew
print("xmin=",x)
print("fmin=",round(f(x),2))
print("chamadas da funcao=",contaf-1)
print("chamadas do gradiente=",contagrad)
print("total de chamadas=", contaf+contagrad-1)
xmin= [3.4e+01 4.6e-01 1.4e-43]
fmin= -2330.92
chamadas da funcao= 0
chamadas do gradiente= 544351
total de chamadas= 544351

Melhorou mas ainda esta um pouco errado. Diminuindo mais a tolerancia...

In [8]:
contaf = 0
contagrad = 0
x = np.array([0.5, 0.5, 0.5])
zz = 99.0
while zz > 1.0e-5/30:
    xnew=x-1.0e-6*grad(x)
    zz = err(x,xnew)
    x = xnew
print("xmin=",x)
print("fmin=",round(f(x),2))
print("chamadas da funcao=",contaf-1)
print("chamadas do gradiente=",contagrad)
print("total de chamadas=", contaf+contagrad-1)
xmin= [4.4e+01 4.6e-01 1.0e-76]
fmin= -2566.86
chamadas da funcao= 0
chamadas do gradiente= 968006
total de chamadas= 968006

Melhorou mas o numero de chamadas para o gradiente é enorme!!!

Decida do grad com line search

In [9]:
contaf = 0
contagrad = 0
x = np.array([0.5, 0.5, 0.5])
zz = 99.0
while zz > 1.0e-5:
    alpha, _, _, _ ,_ ,_ = line_search(f, grad, x, -grad(x))
    xnew = x - alpha * grad(x)
    zz = err(x,xnew)
    x = xnew
print("xmin=",x)
print("fmin=",round(f(x),2))
print("chamadas da funcao=",contaf)
print("chamadas do gradiente=",contagrad)
print("total de chamadas=", contaf+contagrad)
xmin= [ 5.1e+01  4.6e-01 -1.5e-39]
fmin= -2619.95
chamadas da funcao= 2157
chamadas do gradiente= 1326
total de chamadas= 3483

L-BFGS

In [10]:
contaf = 0
contagrad = 0
x = np.array([0.5, 0.5, 0.5])
res = minimize(f, x, method="L-BFGS-B", tol=1.0e-5)
print("xmin=",res.x)
print("fmin=",round(f(res.x),2))
print("chamadas da funcao=",contaf)
print("chamadas do gradiente=",contagrad)
print("total de chamadas=", contaf+contagrad)
xmin= [ 5.1e+01  4.6e-01 -1.7e-04]
fmin= -2619.95
chamadas da funcao= 45
chamadas do gradiente= 0
total de chamadas= 45

Nelder Mead

In [11]:
contaf = 0
contagrad = 0
x = np.array([0.5, 0.5, 0.5])
res = minimize(f, x, method="Nelder-Mead", tol=1.0e-5)
print("xmin=",res.x)
print("fmin=",round(f(res.x),2))
print("chamadas da funcao=",contaf)
print("chamadas do gradiente=",contagrad)
print("total de chamadas=", contaf+contagrad)
xmin= [ 5.1e+01  4.6e-01 -5.0e-07]
fmin= -2619.95
chamadas da funcao= 223
chamadas do gradiente= 0
total de chamadas= 223

BOBYQA

In [12]:
import pybobyqa
In [13]:
contaf = 0
contagrad = 0
x = np.array([0.5, 0.5, 0.5])
res = pybobyqa.solve(f, x)
print("xmin=",res.x)
print("fmin=",round(f(res.x),2))
print("chamadas da funcao=",contaf)
print("chamadas do gradiente=",contagrad)
print("total de chamadas=", contaf+contagrad)
xmin= [5.1e+01 4.6e-01 1.5e-08]
fmin= -2619.95
chamadas da funcao= 103
chamadas do gradiente= 0
total de chamadas= 103
In [ ]: