function model = adaboost(data,options)
% ADABOOST AdaBoost algorithm.
%
% Synopsis:
% model = adaboost(data,options)
%
% Description:
% This function implements the AdaBoost algorithm which
% produces a classifier composed from a set of weak rules.
% The weak rules are learned by a weak learner which is
% specified in options.learner. The task of the weak learner
% is to produce a rule with weighted error less then 0.5.
% The Adaboost algorithm calls in each stage the weak learner
%
% rule{t} = feval(options.learner,weight_data)
%
% where the structure weight_data contains
% .X [dim x num_data] Training vectors.
% .y [1 x num_data] Labels of training vectos (1 or 2).
% .D [1 x num_data] Distribution (weights) over training
% data which defines the weighted error.
%
% The item rule{t}.fun must contain name of function
% which classifies vector X by
% y = feval( rule{t}.fun, X, rule{t}).
%
% It is assumed that the weak rule responds with labels
% 1 or 2 (not 1,-1 as used in AdaBoost literature).
%
% Input:
% data [struct] Input training data:
% .X [dim x num_data] Training vectors.
% .y [1 x num_data] Labels of training vectos (1 or 2).
%
% options [struct] Parameters of the AdaBoost:
% .learner [string] Name of the weak learner.
% .max_rules [1x1] Maximal number of weak rules (defaul 100).
% This paramater defines a stopping condition.
% .err_bound [1x1] AdaBoost stops if the upper bound on the
% empirical error drops below the err_bound (default 0.001).
% .learner_options Additinal options used when the weak learner
% is called.
% .verb [1x1] If 1 then some info is displayed.
%
% Output:
% model [struct] AdaBoost classifier:
% .rule [cell 1 x T] Weak classification rules.
% .Alpha [1 x T] Weights of the rules.
% .WeightedErr [1 x T] Weighted errors of the weak rules.
% .Z [1 x T] Normalization constants of the distribution D.
% .ErrBound [1 x T] Upper bounds on the empirical error.
%
% Example:
% data = load('riply_trn');
% options.learner = 'weaklearner';
% options.max_rules = 100;
% options.verb = 1;
% model = adaboost(data,options);
% figure; ppatterns(data); pboundary(model);
% figure; hold on; plot(model.ErrBound,'r');
% plot(model.WeightedErr);
%
% See also:
% ADACLASS, WEAKLEARNER.
%
% About: Statistical Pattern Recognition Toolbox
% (C) 1999-2004, Written by Vojtech Franc and Vaclav Hlavac
% <a href="http://www.cvut.cz">Czech Technical University Prague</a>
% <a href="http://www.feld.cvut.cz">Faculty of Electrical Engineering</a>
% <a href="http://cmp.felk.cvut.cz">Center for Machine Perception</a>
% Modifications:
% 11-aug-2004, VF
if nargin < 2, options = []; else options = c2s(options); end
if ~isfield(options,'max_rules'), options.max_rules = 100; end
if ~isfield(options,'err_bound'), options.err_bound = 0.001; end
if ~isfield(options,'learner'), options.learner = 'weaklearner'; end
if ~isfield(options,'learner_options'), options.learner_options = []; end
if ~isfield(options,'verb'), options.verb = 0; end
[dim,num_data] = size(data.X);
data.D = ones(num_data,1)/num_data;
model.Alpha =[];
model.Z = [];
model.WeightedErr = [];
model.ErrBound = [];
t = 0;
go = 1;
while go,
t = t + 1;
if options.verb, fprintf('rule %d: ', t); end
if ~isempty(options.learner_options),
rule = feval(options.learner,data,options.learner_options);
else
rule = feval(options.learner,data);
end
y = feval(rule.fun,data.X,rule);
werr = (y(:)~=data.y(:))'*data.D(:);
if options.verb, fprintf('werr=%f', werr); end
if werr < 0.5,
alpha = 0.5*log((1-werr)/werr);
yh = 2*(y(:) == data.y(:))-1;
weights = data.D.*exp(-alpha*yh(:));
Z = sum(weights);
data.D = weights/Z;
err_bound = prod(model.Z);
model.Z = [model.Z; Z];
model.Alpha = [model.Alpha;alpha];
model.rule{t} = rule;
model.ErrBound = [model.ErrBound; err_bound];
if t >= options.max_rules,
go = 0;
model.exitflag = 1;
elseif err_bound <= options.err_bound,
go = 0;
model.exitflag = 2;
end
if options.verb,
fprintf(', alpha=%f, err_bound=%f\n',alpha,err_bound);
end
else
if options.verb, fprintf('>= 0.5 thus stop.\n'); end
go = 0;
model.exitflag = 0;
end
model.WeightedErr = [model.WeightedErr; werr];
end
model.fun = 'adaclass';
return;