function result = checkTerminationCriterions(obj)
% CHECKTERMINATIONCRITERION checks the history and the termination
% criterions if the training should be aborted.
%
% result is TRUE while training should proceed
% result is FALSE if training should be aborted

% LMNtool - Local Model Network Toolbox
% Tobias Ebert, 24-April-2012
% Institute of Mechanics & Automatic Control, University of Siegen, Germany
% Copyright (c) 2012 by Prof. Dr.-Ing. Oliver Nelles


if ~isempty(strfind(version,'R2010a'))
    % workaround for R2010a
    disp('uncomment the following line from the sourcetext')
    % isprop=@(obj,string) checkProp(obj,string);
end


if ~exist('obj','var')
    error('modelHistory:checkTerminationCriterions',...
        'This is a static function. You have to hand over the local model network object')
end

if isprop(obj.history,'displayMode')
    displayMode = obj.history.displayMode;
else
    displayMode = true;
end


% default: training should not be aborted
result = true;


% test termination criterions for break. A combinations of if-conditions
% are used for readability
if (sum(obj.leafModels) >= obj.maxNumberOfLM)
    
    % if there are enough local models
    result = false;
    
    if displayMode; fprintf('\n\nMaximum number of local models reached.\n'); end
    return
    
elseif obj.history.globalLossFunction(end) < obj.minError
    
    % if the minimal error falls below the specified error
    result = false;
    
    if displayMode; fprintf('\n\nError limit reached.\n'); end
    return
    
elseif obj.history.currentNumberOfParameters(end) > obj.maxNumberOfParameters
    
    % if the current number of parameters is greater than the maximal
    % number of parameters
    result = false;
    
    if displayMode; fprintf('\n\nMaximum number of parameters reached.\n'); end
    return
    
elseif obj.history.trainingTime(end) > obj.maxTrainTime*60
    
    % if a maximal training time is reached
    result = false;
    
    if displayMode; fprintf('\n\nMaximum Training time reached.\n'); end
    return
    
elseif obj.history.iteration > obj.maxIterations
    
    % if a maximal training time is reached
    result = false;
    
    if displayMode; fprintf('\n\nMaximum number of iterations reached.\n'); end
    return
    
elseif isprop(obj,'idxAllowedLM') && ~any(obj.idxAllowedLM & obj.leafModels)
    
    % if there is no leaf model left allowed to be split
    result = false;
    
    if displayMode; fprintf('\n\nAll leaf models are not allowed to split. End training algorithmn!\n'); end
    return
end

% test if training algorithm uses merging
if isa(obj,'lolimotMerge') || isa(obj,'lolimotPlusMerge')
    % do nothing, because it does not work
    
    % elseif (isprop(obj,'maxNumberOfLM') && ~isempty(obj.maxNumberOfLM) && ~isinf(obj.maxNumberOfLM)) || ...
    %         (isprop(obj,'maxNumberOfParameters') && ~isempty(obj.maxNumberOfParameters) && ~isinf(obj.maxNumberOfParameters)) || ...
    %         (~isempty(obj.maxIterations) && ~isinf(obj.maxIterations)) || ...
    %         (isprop(obj,'maxPenaltyDeterioration') && isinf(obj.maxPenaltyDeterioration))
    % do not stop traing according to penalty loss funciton if max LM or iter is set
    
elseif ~isempty(obj.history.validationDataLossFunction)
    % if validation data error rises, terminate training
    
    historyDepth = obj.maxValidationDeterioration;
    
    if length(obj.history.validationDataLossFunction)>historyDepth
        errorDiff = zeros(1,historyDepth);
        for idxPrevious = 1:historyDepth
            errorDiff(idxPrevious) = obj.history.validationDataLossFunction(end+1-idxPrevious) - obj.history.validationDataLossFunction(end-idxPrevious);
        end
        if all(errorDiff>-obj.minPerformanceImprovement) || any(abs(errorDiff)>abs(100*mean(obj.history.validationDataLossFunction)))
            result = false;
            if displayMode; fprintf('\n\nValidation data error rised %d times.\n',historyDepth); end
        end
    end
    
else
    % test model complexity
    historyDepth = obj.maxPenaltyDeterioration;
    
    if length(obj.history.penaltyLossFunction)>historyDepth
        errorDiff = zeros(1,historyDepth);
        for idxPrevious = 1:historyDepth
            errorDiff(idxPrevious) = obj.history.penaltyLossFunction(end+1-idxPrevious) - obj.history.penaltyLossFunction(end-idxPrevious);
        end
        if all(errorDiff>-obj.minPerformanceImprovement) || any(abs(errorDiff)>abs(100*mean(obj.history.penaltyLossFunction)))
            result = false;
            if displayMode; fprintf('\n\nEstimated model complexity limit reached. Penalty loss function (AIC) increased %d times.\n',historyDepth); end
        end
    end
    
end


end


function answer = checkProp(obj,string)
% new definition of isprop for R2010a for compatibility

myclass = class(obj);
mymeta = eval(['?' myclass]);
for k = 1:size(mymeta.Properties,1)
    if ~isempty(strfind(mymeta.Properties{k}.Name, string))
        answer = true;
        return
    end
end

end



