function model = ganders( distrib, options, init_model )
% GANDERS Solves the Generalized Anderson's task.
%
% Synopsis:
% model = ganders( distrib)
% model = ganders( distrib, options)
% model = ganders( distrib, options, init_model )
%
% Description:
% This function is an implementation of the general framework
% to find the optimal solution of the Generalized Anderson's
% task [SH10].
%
% The goal of the GAT is find the binary linear classification
% rule (g(x)=sgn(W'*x+b) with minimal probability of
% misclassification. The conditional probabilities are known to
% be Gaussians their paramaters belong to a given set of parameters.
% The true parameters are not known. The linear rule which
% guarantes the minimimal classification error for the worst
% possible case (the worst configuration of Gaussains) is
% sought for.
%
% Input:
% distrib [struct] Set of binary labeled Gaussians.
% .Mean [dim x ncomp] Mean vectors.
% .Cov [dim x dim x ncomp] Covariance matrices.
% .y [1 x ncomp] Labels of the Gaussians (1 or 2).
%
% options [struct] Determines stopping conditions:
% .tmax [1x1] Maximal number of iterations (default inf).
% .eps [1x1] Minimal improvement of the optimized
% criterion (default 1e-6).
% .mineps_tmax [1x1] Number of iterations of the one-dimensional
% numerical search (default 100).
%
% init_model [struct] Initial model:
% .W, .b, .t see below.
%
% Output:
% model [struct] Binary linear classifer:
% .W [dim x 1] Normal vector of the found hyperplane W'*x + b = 0.
% .b [1x1] Bias of the hyperplane.
%
% .r [1x1] Mahalanobis distance for the cloasest Gaussian.
% .err [1x1] Probability of misclassification.
% .t [1x1] Number of iterations.
% .exitflag [1x1] 0 ... maximal number of iterations was exceeded.
% 1 ... solution was found.
% -1 ... solution (with err < 0.5) does not exist.
%
% Example:
% distrib = load('mars');
% model = ganders( distrib );
% figure; pandr( model, distrib );
%
% See also
% ANDRORIG, EANDERS, GGRADANDR, ANDRERR, LINCLASS.
%
% About: Statistical Pattern Recognition Toolbox
% (C) 1999-2003, 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:
% 4-may-2004, VF
% 17-sep-2003, VF
if nargin < 2, options = []; else options=c2s(options); end
if ~isfield(options,'eps'), options.eps=1e-6; end
if ~isfield(options,'tmax'), options.tmax=inf; end
if ~isfield(options,'mineps_tmax'), options.mineps_tmax = 100; end
[dim,ncomp] = size(distrib.Mean);
exitflag = 0;
t = 0;
Mu = [distrib.Mean;ones(1,ncomp)];
Mu(:,find( distrib.y==2) ) = -Mu(:,find( distrib.y==2) );
C = zeros(dim+1,dim+1,ncomp);
C(1:dim,1:dim,:) = distrib.Cov;
if nargin == 3,
W = [init_model.W; init_model.b];
if isfield( init_model, 't' ), t = init_model.t; end
end
if t==0,
[W,eflag] = optimal_hyperplane(Mu);
if eflag <= 0, exitflag = -1; end
end
[minr,inx] = min_radius(W,Mu,C);
old_minr=minr;
while exitflag==0 & t < options.tmax,
t = t + 1;
X0=zeros(dim+1,ncomp);
for i=1:ncomp,
X0(:,i)=Mu(:,i)-(minr/sqrt(W'*C(:,:,i)*W))*C(:,:,i)*W;
end
[dW,eflag]=optimal_hyperplane( X0 );
if eflag > 0,
k = gat1dsearch(Mu,C,W,dW,options.mineps_tmax,0);
W=W*(1-k)+dW*k;
[minr,inx] = min_radius(W,Mu,C);
if minr-old_minr < options.eps,
exitflag = 1;
end
else
exitflag = 1;
end
old_minr = minr;
end
model.W = W(1:end-1);
model.b = W(end);
model.r = minr;
model.err = 1-cdf('norm',minr,0,1);
model.t = t;
model.exitflag = exitflag;
model.options = options;
model.fun = 'linclass';
return;
function [W,exitflag] = optimal_hyperplane(X)
[dim,num_data]=size(X);
H=eye(dim);
f=zeros(dim,1);
b=-ones(num_data,1);
A=-X';
options=optimset('Display','off','Diagnostics','off','LargeScale','off');
[W,fval,exitflag]=quadprog(H,f,A,b,[],[],[],[],[],options);
return;
function [minr,inx] = min_radius(W,Mu,C);
Radius = zeros(size(Mu,2),1);
for i = 1:size(Mu,2),
den = sqrt(W'*C(:,:,i)*W);
if den ~= 0,
Radius(i) = W'*Mu(:,i)/sqrt(W'*C(:,:,i)*W);
else
Radius(i) = 0;
end
end
[minr,inx]=min( Radius );
return;