clear; clc;
%% Rosenbrock
a = 1;
b = 100;
f = @(x) (a-x(1)).^2 + b*(x(2)-x(1).^2).^2;

contour_plot(f);

%% Pick a common initial guess
x0 = [1.2; 1.2];

%% Method 1: call Matlab's minimizer
%  with just the cost function
options = optimoptions('fminunc', ...
                       'Display', 'iter');
x1 = fminunc(f, x0, options);

%% Method 1 bis: call that minimizer but
%                also specify the gradient
g = @(x) [ -2*(a-x(1)) - 4*b*(x(2)-x(1).^2).*x(1) ;
           2*b*(x(2)-x(1).^2)];
options = optimoptions( ...
            'fminunc', 'Display', 'iter', ...
            'SpecifyObjectiveGradient', true);
x2 = fminunc(@(x) cost_and_grad(x, f, g), ...
             x0, options);

%% Method 2: use the Manopt toolbox
problem.M = euclideanfactory(2, 1);
problem.cost = f;
problem.grad = g;

figure(2); clf;

checkgradient(problem);

%%
x3 = steepestdescent(problem, x0);

%%
x4 = trustregions(problem, x0);


%% Function definitions must come at the very end (Matlab's rule)
function [cost, grad] = cost_and_grad(x, f, g)
    cost = f(x);
    grad = g(x);
end

%% Make a plot of f
function contour_plot(f)
    % Grid
    x1 = linspace(0, 2, 200);
    x2 = linspace(0, 2, 200);
    [X1, X2] = meshgrid(x1, x2);
    
    % Evaluate f on grid
    F = arrayfun(@(a, b) f([a; b]), X1, X2);
    
    % Plot contours
    figure(1); clf;
    contourf(X1, X2, F, 50);
    colorbar;
    xlabel('x_1'); ylabel('x_2');
    title('Contour of f');
    axis equal;
    hold; plot(1, 1, 'r.', 'MarkerSize', 20);
end
