%
% Libsvm (extends GenericClassifier)
%
% Multiclass (bias-less) regularized least squares.
% Classes are coded using OVA coding.
%
% 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 Libsvm < GenericClassifier
    properties
    end

    methods
        function obj = Libsvm(parameters)
            if nargin < 1
                parameters = struct;
            end

            obj@GenericClassifier(parameters);
        end

        function flag = with_bias(obj)
            flag = isfield(obj.parameters, 'with_bias') && obj.parameters.with_bias;
        end

        function train_model(obj, hyperparameters, data_obj)
            %params = sprintf('-q -t 4 -c %f -w1 %f -w-1 %f', hyperparameters.c_val, ...
            %                 sum(data_obj.train_y==1)/numel(data_obj.train_y), ...
            %                 sum(data_obj.train_y==-1)/numel(data_obj.train_y));

            params = sprintf('-q -t 4 -c %f', hyperparameters.c_val);

            K = GenericClassifier.compute_mean_kernel_combinations_eff_(hyperparameters, data_obj.train_x, data_obj.train_x);
            K =  [ (1:numel(data_obj.train_y))' , K ];
            obj.model.train_x = data_obj.train_x;
            obj.model.hyperparameters = hyperparameters;
            obj.model.libsvm_model = svmtrain(data_obj.train_y, K, params);
        end

        function [pred, margins] = predict(obj, test_x)
            K = GenericClassifier.compute_mean_kernel_combinations_eff_(obj.model.hyperparameters, test_x, obj.model.train_x);
            K =  [ (1:size(K,1))' , K ];

            [pred, junk, margins] = svmpredict(zeros(size(K,1),1), K, obj.model.libsvm_model, '-q');
            margins = (pred.*sign(margins).*margins)';
        end
    end
end
