function [model, coeff, LOSS] = kls_train_adapt_zita_Multi(model,prev_outs)

% Train an Adaptive Kernel Least Square, considering prior knowledge.
% The weight for each known model is chosen with a projected sub-gradient
% descent.

% This code is part of the supplementary material to the CVPR 2010 paper
% "Safety in Numbers: Learning Categories from Few Examples with Multi 
% Model Knowledge Trasfer", T. Tommasi, F. Orabona, B. Caputo.

% Copyright (C) 2009-2010, Tatiana Tommasi
%
% 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: ttommasi [at] idiap.ch


n = size(model.K,1);

model.K=[model.K ones(n,1); ones(1,n) 0];
	
index_p=find(model.Y==1);
l_p=numel(index_p);
index_m=find(model.Y==-1);
l_m=numel(index_m);
zita=zeros(1,numel(model.Y));
zita(index_p)=numel(model.Y)/(2*l_p);
zita(index_m)=numel(model.Y)/(2*l_m);

if numel(model.C)==1
    id=1/model.C*diag(1./zita); 
    id=[id zeros(n,1)];
    id=[id ; zeros(1,n+1)];
    id(end,end)=0;
else
    id=diag(1./model.C); id(end+1,end+1)=0;
end
G=pinv(model.K+id);
dd=diag(G);

x1=G*[model.Y';0];
model.beta = x1(1:end-1);
model.b = x1(end);

loo_pred=model.Y'-model.beta./dd(1:end-1);
   

for j=1:numel(prev_outs)
    if numel(prev_outs{j})==0, continue; end
    x2=G*[prev_outs{j};0];

    term_prev{j}=x2(1:end-1)./dd(1:end-1);
    beta_prev{j}=x2;
end


t=zeros(1,numel(prev_outs)); 

for idx_modello=1:numel(prev_outs)
    if numel(prev_outs{idx_modello})==0, break; end
end
useless=idx_modello;

term_prev_mat=zeros(numel(prev_outs),numel(model.Y));
for idx_modello=1:numel(prev_outs)
    if idx_modello==useless, continue;end
    term_prev_mat(idx_modello,:)=term_prev{idx_modello}';
end

for ITER=1:(10000)
    S=t*term_prev_mat;
        
    part=zita'.*(model.Y'.*(model.beta./dd(1:end-1)-S'));

    deriv= - ((part'>0).*zita.*model.Y)*term_prev_mat';
    t_one=t-deriv/(sqrt(ITER)*numel(model.Y));

    t_two=t_one;
    index_NEG=find(t_one<0);
    t_two(index_NEG)=0;
    t_two(useless)=0;
    
     if(norm(t_two))>1
         t_two=t_two/(norm(t_two));
     end
    t=t_two;

  
end

coeff=t;

Sloss=zeros(numel(model.Y),1);
Sf=zeros(numel(model.Y)+1,1);
for idx_modello=1:numel(prev_outs)
    if numel(prev_outs{idx_modello})==0, continue; end
    Sf=Sf+coeff(idx_modello)*beta_prev{idx_modello};
   Sloss=Sloss+coeff(idx_modello)*term_prev{idx_modello};
end

LOSS=zita'.*(model.Y'.*(model.beta./dd(1:end-1)-Sloss));

model.beta=model.beta-Sf(1:end-1);
model.b=model.b-Sf(end);



