function [loss, grad] = loss_function(X, y, w, reg_type, lambda)
% Funkcija izracunava funkciju gubitka i primenjuje regularizaciju 'l1' ili 'l2'
% u zavisnosti u parametra 'reg_type'.

N = length(y);
grad = zeros(size(w));
reg = 0;
pred = X * w;

if (reg_type == 'l1')
    % Za slucaj l1 regularizacije racunamo podgradijent (eng. subgradient).
    reg = sum(abs(w(2:end)));
    grad = (1/N) .* (X' * (pred - y));
    grad(2:end) = grad(2:end) + (lambda/N) .* w(2:end);
    for i = 2:length(w)
        if (abs(w(i)) > 0)
            grad(i) = grad(i) + lambda * sign(w(i));
        elseif (grad(i) < -lambda)
            grad(i) = grad(i) + lambda;
        elseif (grad(i) > lambda)
            grad(i) = grad(i) - lambda;
        elseif (-lambda <= grad(i) && grad(i) <= lambda)
            grad(i) = 0;
        end
    end
elseif (reg_type == 'l2')
    % Pri l2 regularizaciji funkcija gubitka je diferencijabilna te gradijent racunamo standardno.
    grad = (1/N) .* (X' * (pred - y));
    grad(2:end) = grad(2:end) + (lambda/N) .* w(2:end);
    reg = sum(w(2:end) .* w(2:end));
end

loss = (1/(2*N)) * sum((pred - y).^2) + lambda * reg;

end
