% This file contains the definition of an ancestor class for a
% composite problem. When designing a custom class for your application
% you need to inherit this base class to ensure that ACGM functions
% correctly. More information can be found in "README.txt".

%   Author: Mihai I. Florea, Aalto University
%   Version: 10 June 2021


classdef Problem < handle

    properties
        L;            % global Lipschitz constant
        % strong convexity parameters (s.c.p.)
        mu_f   = 0.0; % \mu_f, s.c.p. of the smooth part f
        mu_Psi = 0.0; % \mu_{\Psi}, s.c.p. of the regularizer \Psi
        mu     = 0.0; % \mu, strong s.c.p. of the composite objective F

    end

    % A class describing a composite problem MUST define the following
    % oracle functions. Uncomment to enforce this behavior in MATLAB
    % and to benefit from polymorphism.

    %methods(Abstract)
    %    f_val(obj, x);           % f(x), value of the smooth part
    %    f_grad(obj, x);          % \nabla f(x), smooth part gradient
    %    Psi_val(obj, x);         % \Psi(x), value of regularizer
    %    prox(obj, x, step_size); % prox function
    %end

    methods

        % Helper function for setting all the s.c.p. at once
        function set_mu(obj, mu_f, mu_Psi)
            obj.mu_f   = mu_f;
            obj.mu_Psi = mu_Psi;
            obj.mu     = mu_f + mu_Psi;
        end

        % Value of the composite objective F at point x
        % Input:
        %  x     : point x
        %  f_val : the value of f(x), if available beforehand,
        %          empty otherwise
        % Output;
        %  F     : the value of F(x)

        function F = F_val(obj, x, f_val)
            if isempty(f_val)
                F = obj.f_val(x) + obj.Psi_val(x);
            else
                F = f_val + obj.Psi_val(x);
            end
        end
    end

    methods(Static)
        % Line-search stopping criterion (LSSC) function
        % Input:
        %  x        : point x
        %  y        : point y
        %  f_val_x  : value of f(x)
        %  f_val_y  : value of f(y)
        %  f_grad_y : \nabla f(y), the gradient of f at y
        %  L        : the current Lipschitz constant estimate
        % Output;
        %  brk      : 1 if the LSSC passes, 0 if it fails

        function brk = LSSC(x, y, f_val_x, f_val_y, f_grad_y, L)
            x_minus_y = x(:) - y(:);
            brk = ( f_val_x <= f_val_y + sum(f_grad_y(:) .* x_minus_y) + ...
                               0.5 * L * sum(x_minus_y.^2 )                 );
        end
    end
end
