%
% SimpleNplusOne (extends MulticlassRLS)
%
% Given some priors (multiclass classifier), trains
% binary model for a new class and makes predictions
% from priors and new trained model.
%
% This code is part of the supplementary material to the CVPR 2013 paper
% "From N to N+1: Multiclass Transfer Incremental Learning",
% Ilja Kuzborskij, Francesco Orabona and Barbara Caputo
%
% Copyright (C) 2012-2013, Ilja Kuzborskij
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.
%
% Contact the author: ilja.kuzborskij [at] gmail.com
%
classdef SimpleNplusOne < MulticlassRLS
    properties
    end

    methods
        function obj = SimpleNplusOne(parameters)
        % Constructs SimpleNplusOne
        %
        % parameters.priors             -- prior (N) models; should implement predict method
        % parameters.new_class_label    -- label of a new class (numeric)
        %
            obj@MulticlassRLS(parameters);
            obj.model = struct;
        end

        function train_model(obj, hyperparameters, data_obj)
            t_data_obj.train_y = data_obj.train_y;
            t_data_obj.train_y(data_obj.train_y~=obj.parameters.new_class_label) = 0;
            t_data_obj.train_x = data_obj.train_x;

            train_model@MulticlassRLS(obj, hyperparameters, t_data_obj);
        end

        function [pred, margins] = predict(obj, test_x)
            [junk, margins1] = obj.parameters.priors.predict(test_x);
            [junk, margins2] = predict@MulticlassRLS(obj, test_x);
            margins = [margins1 margins2(:, obj.model.class_map~=0)];

            [junk, class_idx] = max(margins, [], 2);
            obj.model.class_map = [obj.parameters.priors.model.class_map; ...
                obj.model.class_map(obj.model.class_map~=0)];
            pred = obj.model.class_map(class_idx);
        end
    end
end
