|
| 1 | +import matplotlib.pyplot as plt |
| 2 | +from functions_utils import * |
| 3 | +from armijo_utils import Armijo_method |
| 4 | +from newton_utils import NewtonMethod |
| 5 | +from penalty_method import AugmentedLagrangian |
| 6 | + |
| 7 | + |
| 8 | +class Gradient_descent(): |
| 9 | + def __init__(self, method_type='steepest_descent', threshold=0.00001, step_size_estimator=Armijo_method(), |
| 10 | + max_steps=100000, verbose=True): |
| 11 | + self.threshold = threshold |
| 12 | + self.max_steps = max_steps |
| 13 | + self.verbose = verbose |
| 14 | + self.f_val_list = [] |
| 15 | + self.step_sizes_list = [] |
| 16 | + self.step_size_estimator = step_size_estimator |
| 17 | + self.method_type = method_type |
| 18 | + |
| 19 | + def optimize(self, func, start_point): |
| 20 | + self.f_val_list.append(func.val(start_point)) |
| 21 | + |
| 22 | + x = start_point |
| 23 | + |
| 24 | + for step in range(self.max_steps): |
| 25 | + print("step:", step) |
| 26 | + prev_x = x |
| 27 | + if self.method_type == 'steepest_descent': |
| 28 | + x = self.optimizer_step(x, func) |
| 29 | + elif self.method_type == 'newton_method': |
| 30 | + x = self.optimizer_step_newton(x, func) |
| 31 | + else: |
| 32 | + print("Direction method not selected") |
| 33 | + break |
| 34 | + self.f_val_list.append(func.val(x)) |
| 35 | + |
| 36 | + # if self.verbose: |
| 37 | + # print("f(x)=", func.val(x), " current point= ~", np.round(x, 5)) |
| 38 | + |
| 39 | + # print("norm=",np.linalg.norm(func.grad(x))) |
| 40 | + if np.linalg.norm(func.grad(x)) < self.threshold: |
| 41 | + print("Optimizer reached accuracy threshold after", step, "iterations!") |
| 42 | + break |
| 43 | + return x |
| 44 | + |
| 45 | + def optimizer_step(self, x, func): |
| 46 | + step_size = self.step_size_estimator.calc_step_size(x, func, direction=func.grad(x)) |
| 47 | + x = x - step_size * func.grad(x) |
| 48 | + # self.step_size_estimator.armijo_plot() |
| 49 | + self.step_sizes_list.append(step_size) |
| 50 | + return x |
| 51 | + |
| 52 | + def optimizer_step_newton(self, x, func): |
| 53 | + newton = NewtonMethod() |
| 54 | + d = newton.direction(x, func) |
| 55 | + step_size = self.step_size_estimator.calc_step_size(x, func, direction=d) |
| 56 | + x = x - step_size * d |
| 57 | + self.step_sizes_list.append(step_size) |
| 58 | + return x |
| 59 | + |
| 60 | + def plot_step_sizes(self): |
| 61 | + iterations_list = range(len(self.step_sizes_list)) |
| 62 | + |
| 63 | + a, = plt.plot(iterations_list, self.step_sizes_list, label='step size') |
| 64 | + plt.legend(handles=[a]) |
| 65 | + plt.ylabel('step size') |
| 66 | + plt.xlabel('iterations') |
| 67 | + plt.show() |
| 68 | + |
| 69 | + def get_convergence(self, val_optimal): |
| 70 | + ''' |
| 71 | + gets converg rates list |
| 72 | + :param f_list: list of values of f during gradient descent algo |
| 73 | + :param val_optimal: the global minimum value of the function |
| 74 | + ''' |
| 75 | + converg_list = [] |
| 76 | + iterations_list = [] |
| 77 | + for idx, val in enumerate(self.f_val_list): |
| 78 | + converg_list.append(val - val_optimal) |
| 79 | + iterations_list.append(idx) |
| 80 | + |
| 81 | + return iterations_list, converg_list |
| 82 | + |
| 83 | + def plot_convergence(self, val_optimal, f_name='plot title', marker=None, save = True): |
| 84 | + ''' |
| 85 | + plots the convergence rate |
| 86 | + :param f_list: list of values of f during gradient descent algo |
| 87 | + :param val_optimal: the global minimum value of the function |
| 88 | + ''' |
| 89 | + converg_list = [] |
| 90 | + iterations_list = [] |
| 91 | + for idx, val in enumerate(self.f_val_list): |
| 92 | + #converg_list.append(abs(val - val_optimal)) |
| 93 | + converg_list.append(val) |
| 94 | + iterations_list.append(idx) |
| 95 | + |
| 96 | + plt.plot(iterations_list, converg_list) |
| 97 | + plt.ylabel('f(x)-f* / log') |
| 98 | + plt.xlabel('iterations') |
| 99 | + #plt.yscale('log') |
| 100 | + label = f_name + ' - ' + self.method_type + ' convergence rate' |
| 101 | + plt.title(label) |
| 102 | + if marker != None: |
| 103 | + x, y = marker |
| 104 | + plt.plot(x, y, 'ro') |
| 105 | + plt.gcf() |
| 106 | + name = label + '_fig.JPEG' |
| 107 | + plt.savefig(name, bbox_inches='tight') |
| 108 | + plt.show() |
| 109 | + |
0 commit comments