%
% This code is part of the supplementary material to the CVPR 2013 submission
% "From N to N+1: Multiclass Transfer Incremental Learning", ID: 727
%
% CONFIDENTIAL REVIEW COPY. DO NOT DISTRIBUTE.
%
%

function [alpha, best_classifiers] = train_MultiSourceTrAdaBoost(cue, idx, n, p, t, hyperparameters, f)
% cue{.}.p_train
% cue{.}.t_train
% cue{.}.p_test
% cue{.}.t_test
%
% t{pk,f} / pk-? (1:n), f - feature | sources
% p{pk,f} / pk-? (1:n), f - feature |
%
% n - num. sources?
%
% f - cue index
M=10; % iterations


p_train_small{f}=cue{f}.p_train;
t_train_small{f}=cue{f}.t_train;

% initialization %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear w
nS=0;
for pk=1:n
        if pk==idx, continue, end
        nS=nS+numel(t{pk,f}); %nS at the end indicates the total number of samples from all the sources
end
alphaS=0.5*log(1+sqrt(2*log(nS/M)));
for pk=1:n
        if pk~=idx
            w{pk}=ones(size(p{pk,f},1),1)/(nS+numel(t_train_small{f}));
        else
            w{idx}=ones(numel(t_train_small{f}),1)/(nS+numel(t_train_small{f}));
        end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

w_now=[];
for tt=1:M

    ss=0;
    for k=1:n
        ss=ss+sum(w{k});
    end
    for k=1:n
            w{k}=w{k}(:)/ss;
    end

    best_weak=[];
    lowest_err=Inf;

    err=[];
    for pk=1:n
        if pk==idx, continue, end

        % D_{s^k} U D_t
        samples_p= [p{pk,f}; p_train_small{f}];
        samples_t= [t{pk,f}; t_train_small{f}];

        w_now=[w{pk}; w{idx}];
        [a,index{pk}]=histc(rand(1,numel(w_now)), [0;cumsum(w_now(:))/sum(w_now)]);

        train_p=samples_p(index{pk},:);
        train_t=samples_t(index{pk});

        weak = MulticlassRLS(struct('with_bias', false));
        weak.train(hyperparameters, {train_p}, train_t);
        label = weak.predict({samples_p});

        label_s{pk}=label(1:numel(w{pk}));
        label_t{pk}=label(numel(w{pk})+1:end);
        clear label

        epsilon=0;
        for j=1:numel(w{idx})
            epsilon=epsilon+w{idx}(j)*(label_t{pk}(j)~=t_train_small{f}(j))/sum(w{idx});
        end

        err(pk)=epsilon;

        if err(pk) < lowest_err
            lowest_err = err(pk);
            best_weak = weak;
            best = pk;
        end
    end

    vec=1:n;
    vec(idx)=[];

    alpha(tt)=0.5*log((1-err(best))/(max(err(best),eps)));

    segno=1;
    if err(best)>=0.5
        segno=-1;

        epsilon=0;
        for j=1:numel(w{idx})
            epsilon=epsilon+w{idx}(j)*(segno*label_t{best}(j)~=t_train_small{f}(j))/sum(w{idx});
        end

        err(best)=epsilon;
        alpha(tt)=0.5*log((1-err(best))/(max(err(best),eps)));

    end

    clear w_now
    samples_y= [t{best,f}; t_train_small{f}];
    w_now=[w{best}; w{idx}];
    for j=1:numel(w{best})
        w{best}(j)=w{best}(j)*exp(-alphaS*abs(segno*label_s{best}(j)-t{best,f}(j)));
    end
    for j=1:numel(w{idx})
        w{idx}(j)=w{idx}(j)*exp(alpha(tt)*abs(segno*label_t{best}(j)-t_train_small{f}(j)));
    end

    best_classifiers{tt} = best_weak;
    alpha(tt) = alpha(tt) * segno;
end
