function result = demo_linclass(action,hfigure,varargin)
% DEMO_LINCLASS Demo on the algorithms learning linear classifiers.
%
% Synopsis:
% demo_linclass
%
% Description:
% DEMO_LINCLASS demonstrates use of the algorithms which find
% linear decision hyperplane between two (dichotomy)
% vector sets. The demo requires 2D input training data.
%
% The program vizualizes found hyperplane in the current
% algorithm step. The missclassified vector used by the
% demonstrated iterative algorithms for update is vizualized
% as well. Text description of the found solution is
% printed at the bottom part of window.
%
% Following algorithms can be tested:
%
% Perceptron - Perceptron learning rule (see 'help perceptron').
% Kozinec - Kozinec's algorithm (see 'help ekozinec', eps=-1).
% e-Kozinec - Kozinec's algorithm finding eps-optimal hyperplane
% (see 'help ekozinec', eps > 0).
% Linear SVM - Linear Supprot Vector Machines for separable data
% (see 'help smo', C=inf, ker='linear').
%
% Control:
% Algorithm - Dselects algorithm for testing.
% Epsilon - Input parameter of 'ekozinec' algorithm
% (see 'help ekozinec').
% Iterations - Number of iterations in one step.
% Animation - Enables/dissables animation - smooth changeover
% between two algorithm states.
%
% FIG2EPS - Exports screen to the PostScript file.
% Load data - Loads input training data from file.
% Create data - Invokes program for creating training data.
% Reset - Sets the algorithm to the initial state.
% Play - Runs the algorithm.
% Stop - Stops the running algorithm.
% Step - Perform one step of the algorithm.
% Info - Invoke the info box.
% Close - Close the program.
%
% See also
% PERCEPTRON, EKOZINEC, SVM.
%
% 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:
% 19-sep-2003, VF
% 17-Feb-2003, VF
% 24. 6.00 V. Hlavac, comments polished.
% 11-dec-2000 V. Franc, a little increasing of code readibility
% 15-dec-2000
LINE_WIDTH=1; % width of separation line
ANIM_STEPS=10; % number of steps during the line animation
BORDER=0.2; % minimal space between axis and points
%DATA_IDENT='Finite sets, Enumeration'; % file identifier
ALGOS=['Perceptron';'Kozinec ';'e-Kozinec '; 'LinearSVM '];
WRONGPOINT_SIZE = 13;
% if number of arguments is less then 1, that means first call of this
% function. Every other calls set up at least argument action
if nargin < 1,
action = 'initialize';
end
% what action is required ?
switch lower(action)
case 'initialize'
% == Initialize user interface control and figure =======
% == Figure =============================================
left=0.1;
width=0.8;
bottom=0.1;
height=0.8;
hfigure=figure('Name','Linear discriminant function', ...
'Visible','off',...
'NumberTitle','off', ...
'Units','normalized', ...
'Position',[left bottom width height],...
'Units','normalized', ...
'tag','Demo_Linclass',...
'RendererMode','manual');
% == Axes =========================================
left=0.1;
width=0.65;
bottom=0.35;
height=0.60;
haxes1=axes(...
'Units','normalized', ...
'Box','on', ...
'DrawMode','fast',...
'UserData',[],...
'Position',[left bottom width height]);
xlabel('feature x_1');
ylabel('feature x_2');
% == Comment window =================================
% Comment Window frame
bottom=0.05;
height=0.2;
uicontrol( ...
'Style','frame', ...
'Units','normalized', ...
'Position',[left bottom width height], ...
'BackgroundColor',[0.5 0.5 0.5]);
% Text label
uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left height-0.01 width 0.05], ...
'BackgroundColor',[0.5 0.5 0.5], ...
'ForegroundColor',[1 1 1], ...
'String','Comment Window');
% Edit window
border=0.01;
hconsole=uicontrol( ...
'Style','edit', ...
'HorizontalAlignment','left', ...
'Units','normalized', ...
'Max',10, ...
'BackgroundColor',[1 1 1], ...
'Position',[left+border bottom width-2*border height-0.05], ...
'Enable','inactive',...
'String','');
% == Buttons ===========================================
% -- Export to EPS ---------
width=0.1;
left=0.75-width;
bottom=0.95;
height=0.04;
hbtclose = uicontrol(...
'Units','Normalized', ...
'Callback','fig2eps(gcf)',...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','FIG2EPS');
%----------------------------------
% Close button
left=0.8;
bottom=0.05;
height=0.05;
width=0.15;
hbtclose = uicontrol(...
'Units','Normalized', ...
'Callback','close(gcf)',...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Close');
% Info button: call stanard info box
bottom=bottom+1.5*height;
hbtinfo = uicontrol(...
'Units','Normalized', ...
'Callback','demo_linclass(''info'',gcf)',...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Info');
% Step button: perform one adaptation step
bottom=bottom+1.5*height;
hbtstep = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Step', ...
'Callback','demo_linclass(''step'',gcf)');
% Stop button: stop process of adaptation
bottom=bottom+height;
hbtstop = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Stop', ...
'Callback','set(gcbo,''UserData'',1)',...
'Enable','off');
% Play button: start up adaptation
bottom=bottom+height;
hbtplay = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Play', ...
'Callback','demo_linclass(''play'',gcf)');
% Reset button: set up t = 0
bottom=bottom+height;
hbtreset = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Reset', ...
'Callback','demo_linclass(''reset'',gcf)');
% Creat data
bottom=bottom+1.5*height;
hbtcreat = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Create data', ...
'Callback','demo_linclass(''creatdata'',gcf)');
% Load data
bottom=bottom+1*height;
hbtload = uicontrol(...
'Units','Normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Load data', ...
'Callback','demo_linclass(''getfile'',gcf)');
% == Popup menus ======================================
% Pop up menu for the selection between algorithms
% title
bottom=0.95-height;
htxalgo=uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left bottom width height], ...
'String','Algorithm');
% popup menu
bottom=bottom-height;
hpualgo=uicontrol( ...
'Style','popup', ...
'Units','normalized', ...
'CallBack','demo_linclass(''epshandler'',gcf)',...
'Position',[left bottom width height], ...
'String',ALGOS);
% == Edit line ========================================
% epsilon
bottom=bottom-1.2*height;
htxeps=uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left bottom width 0.9*height], ...
'Enable','off',...
'String','epsilon');
bottom=bottom-height;
hedeps = uicontrol(...
'Units','normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'Style','edit',...
'Enable','off',...
'CallBack','demo_linclass(''epshandler'',gcf)',...
'String','1e-2');
% # of iterations
bottom=bottom-1.1*height;
htxiter=uicontrol( ...
'Style','text', ...
'Units','normalized', ...
'Position',[left bottom width 0.9*height], ...
'String','Iterations');
bottom=bottom-0.9*height;
hediter = uicontrol(...
'Units','normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'Style','edit',...
'CallBack','demo_linclass(''iterhandler'',gcf)',...
'String','1');
% == Check boxes ==============================================
% Make check box to determine if a line will be drawn in one
% step or smooth plot.
bottom=bottom-height*1.2;
hxbanim = uicontrol(...
'Style','checkbox', ...
'Units','normalized', ...
'ListboxTop',0, ...
'Position',[left bottom width height], ...
'String','Animation');
% ============================================================
% Store handlers
handlers=struct(...
'line',struct('handler',-1,'alpha',0,'theta',0,'t',0),...
'btstep',hbtstep,...
'btstop',hbtstop,...
'btclose',hbtclose,...
'btplay',hbtplay,...
'btreset',hbtreset,...
'btinfo',hbtinfo,...
'btload',hbtload,...
'btcreat',hbtcreat,...
'pualgo',hpualgo,...
'console',hconsole,...
'editer',hediter,...
'edeps',hedeps,...
'txeps',htxeps,...
'axes1',haxes1,...
'xbanim',hxbanim);
set(hfigure,'UserData',handlers)
% Reset
demo_linclass('reset',hfigure);
% Put figure on desktop
set(hfigure,'Visible','on');
drawnow;
case 'iterhandler'
% == Handler for edit line Iterations ===============
h=get(hfigure,'UserData');
iter=round(str2num(get(h.editer,'String')));
if isempty(iter) | iter < 1, iter=1; end
set(h.editer,'String',num2str(iter));
case 'epshandler'
% == Handler for edit line Epsilon =======================
h=get(hfigure,'UserData');
% if algorithm e-Kozinec is selected then ...
if get(h.pualgo,'Value')==3,
set(h.edeps,'Enable','on');
set(h.txeps,'Enable','on');
epsil=str2num(get(h.edeps,'String'));
if epsil < 0,
epsil=1;
set(h.edeps,'String',num2str(epsil));
end
else
set(h.edeps,'Enable','off');
set(h.txeps,'Enable','off');
end
case 'creatdata'
% == Invoke data set creator ================================
createdata('finite',2,'demo_linclass','created',hfigure);
case 'created'
% == Load new created data set =============================
% get handler and make this figure active
figure(hfigure);
h=get(hfigure,'UserData');
% get file name
path=varargin{1};
name=varargin{2};
pathname=strcat(path,name);
% if checkdat(pathname,DATA_IDENT,2,[0 0])==1,
if check2ddata(pathname),
file.pathname=pathname;
file.path=path;
file.name=name;
set(h.btload,'UserData',file);
demo_linclass('loadsets',hfigure);
demo_linclass('reset',hfigure);
else
errordlg('This file does not contain required data.','Bad file','modal');
end
case 'getfile'
% == Invoke standard open file dialog ===================
% Opens file and checks if contains appropriate data,
% if yes loads data.
h=get(hfigure,'UserData');
[name,path]=uigetfile('*.mat','Open file');
if name~=0,
file.pathname=strcat(path,name);
file.path=path;
file.name=name;
if check2ddata(file.pathname),
% if checkdat(file.pathname,DATA_IDENT,2,[0 0])==1,
set(h.btload,'UserData',file);
demo_linclass('loadsets',hfigure);
demo_linclass('reset',hfigure);
else
errordlg('This file does not contain required data.','Bad file','modal');
end
end
case 'redraw'
% == Redraw points in axes ==================================
h=get(hfigure,'UserData'); % uicontrol handlers
% get point sets
sets=get(h.axes1,'UserData');
if isempty(sets)==1,
return;
end
% clears axes
set(get(h.axes1,'Children'),'EraseMode','normal');
clrchild(h.axes1);
h.line.handler=line('EraseMode','xor','Color','k','Visible','off','Parent',h.axes1);
set(hfigure,'UserData',h); % uicontrol handlers
%%% pplot(sets.X,sets.I);
%% ppoints(sets.X,sets.I);
ppatterns(sets);
demo_linclass('drawline',hfigure,h.line.theta,h.line.alpha);
drawnow;
case 'loadsets'
% == Load data sets ========================================
% Get file name from the pop up menu according to menu pointer.
% Than clear axes,load new file and appear the points from the file.
h=get(hfigure,'UserData');
% Clear axes
clrchild(h.axes1);
set(h.axes1, ...
'Box','on', ...
'DrawMode','fast' );
xlabel('feature x_1');
ylabel('feature x_2');
% No line
h.line.handler=-1;
set(hfigure,'UserData',h);
% Get file name with sets
file=get(h.btload,'UserData');
% Load sets
sets=load(file.pathname);
%%%
sets.I=sets.y;
sets.N=2;
for ii=1:max(sets.y),
sets.K(ii)=length(find(sets.y==ii));
end
% store loaded sets
set(h.axes1,'UserData',sets);
% set axes according to current point set
win=cmpwin(min(sets.X'),max(sets.X'),BORDER,BORDER);
setaxis(h.axes1,win);
axes(h.axes1);
% plots points
%% ppoints(sets.X,sets.I);
ppatterns(sets);
drawnow;
case 'play'
% == Start up the adaptation process ============================
% Get handle to data.
h=get(hfigure,'UserData');
if h.line.handler==-1,
return;
end
% Check if data are loaded.
sets=get(h.axes1,'UserData');
if isempty(sets)==1,
return;
end
% Disable and enable buttons.
set([h.btinfo h.btstep h.btclose h.btplay h.btreset h.btload h.btcreat ...
h.pualgo h.editer],'Enable','off');
set(h.btstop,'Enable','on');
set(h.btstop,'UserData',0);
h.stop = 0;
set(hfigure,'UserData',h);
% Play - adaptation process
while h.stop==0 & get(h.btstop,'UserData')==0,
demo_linclass('step',hfigure);
h=get(hfigure,'UserData');
end
% Enable and dissable buttons.
set([h.btinfo h.btstep h.btclose h.btplay h.btreset h.pualgo ...
h.editer h.btload h.btcreat],'Enable','on');
set(h.btstop,'Enable','off');
case 'step'
% == Perform one adaptation step ======================================
h=get(hfigure,'UserData'); % get handlers we will need...
if h.line.handler==-1,
return;
end
% get sets
sets=get(h.axes1,'UserData');
% no data set loaded
if isempty(sets)==1,
return;
end
[alpha,theta,solution,t]=exec(hfigure);
if mod(h.stepcnt,2)==1 & h.line.t >0,
if solution ~= 1,
demo_linclass('drawline',hfigure,theta,alpha);
else
text=makeinfo(t,alpha,theta,solution);
set(h.console,'String',text );
end
else
if get(h.xbanim,'Value')==0,
demo_linclass('drawline',hfigure,theta,alpha);
else
demo_linclass('animline',hfigure,theta,alpha);
end
if solution==1 | solution==-1,
h.stop=1;
end
h.line.alpha = alpha;
h.line.theta = theta;
h.line.t = t;
if solution==0 | solution ==1,
% appear time and line parameters
text=makeinfo(t,alpha,theta,solution);
elseif solution==-1,
text=sprintf('Solution does not exist.\n');
end
set(h.console,'String',text );
end
% store new solution
h.stepcnt=h.stepcnt+1;
set(hfigure,'UserData',h);
case 'animline'
% == Smooth transition of line from old to new position ===============
h=get(hfigure,'UserData'); % get handlers
% old position of line is...
alpha2=h.line.alpha;
theta2=h.line.theta;
t2=h.line.t;
% New position get from input arguments
theta1=varargin{1};
alpha1=varargin{2};
if t2~=0,
% move line
step=1/ANIM_STEPS;
for k=0:step:1,
alpha=(1-k)*alpha2+k*alpha1; % smooth transition of alpha
theta=(1-k)*theta2+k*theta1; % --//-- theta
demo_linclass('drawline',hfigure,theta,alpha);
end
else
% it is first step
demo_linclass('drawline',hfigure,theta1,alpha1); % first step
end % if t2~=0
case 'reset'
% == Reset adaptation process, set up zero step ================
h=get(hfigure,'UserData'); % get handlers
% get data set
sets=get(h.axes1,'UserData');
% get file
file=get(h.btload,'UserData');
% zeroize parameters of the separation line
h.line.t=0;
h.line.theta=0;
h.line.alpha=[0;0];
h.stepcnt=0;
if h.line.handler==-1,
% create line
axes(h.axes1);
h.line.handler=...
line('EraseMode','xor','Color','k','Visible','off','Parent',h.axes1);
h.badpoint.handler=line('EraseMode','xor','Color','k','Visible','off',...
'Parent',h.axes1,...
'Marker','o',...
'MarkerSize',WRONGPOINT_SIZE);
drawnow;
else
% change parameters of line
set(h.line.handler,'Visible','off');
set(h.badpoint.handler,'Visible','off');
end % if hline==-1
% set up handlers and flush queue with graph. objects
set(hfigure,'UserData',h);
% create comment
if isempty(sets)==0,
consoletext=sprintf('Step t=0\nNo separation line');
titletext=sprintf('Data file: %s, %d vectors',file.name,sum(sets.K));
else
consoletext=sprintf(['No data loaded.\nPress Load data button.\n',...
'Load sample data from ../toolboxroot/data/binary_separable']);
titletext='';
pos=get(h.axes1,'Position');
fsize=min(pos(3),pos(4))/10;
setaxis(h.axes1,[-1 1 -1 1]);
axis([-1 1 -1 1]);
builtin('text',0,0,'Press ''Load data'' button.',...
'HorizontalAlignment','center',...
'FontUnits','normalized',...
'Clipping','on',...
'FontSize',fsize);
end
% show comment
set(h.console,'String',consoletext );
% print title
pos=get(h.axes1,'Position');
fsize=(1-pos(2)-pos(4))*1;
title(titletext,...
'Parent',h.axes1,...
'VerticalAlignment','bottom',...
'HorizontalAlignment','left',...
'FontUnits','normalized',...
'Units','normalized',...
'Position',[0 1 0],...
'FontSize',fsize);
case 'drawline'
% == Draw separation line ============================
h=get(hfigure,'UserData'); % get handlers
% get new line position from input arguments
theta=varargin{1};
alpha=varargin{2};
if mod(h.stepcnt,2)==1 & h.line.t >0,
set(h.badpoint.handler,'Visible','on',...
'XData',alpha(1),'YData',alpha(2));
else
set(h.badpoint.handler,'Visible','off');
% Cut off line along axes
[x1,y1,x2,y2,in]=cliplin1(alpha,theta,getaxis(h.axes1));
% erase old line
set(h.line.handler,'Visible','off');
% draw new line if is in the axes
if in==1,
set(h.line.handler,...
'XData',[x1 x2],...
'YData',[y1 y2],...
'LineWidth',LINE_WIDTH,...
'Visible','on');
end
end
% flush draw queue
drawnow;
case 'info'
% == Invokes standard Matlab`s info box ==========================
helpwin(mfilename);
end
%========================================
function [text]=makeinfo(t,alpha,theta,solution)
% assembles text description about current solution state
if solution==1,
txline{1}=sprintf('Solution was found after t=%d step(s).',t);
else
txline{1}=sprintf('Step t=%d',t);
end
txline{2}=sprintf('Linear decision function:');
txline{3}=sprintf('%f x_1 + %f x_2 + %f = 0',alpha(1),alpha(2),-theta);
text='';
for i=1:3,
text=strvcat(text,txline{i});
end
return;
%===========================================
function [alpha,theta,solution,tplus1]=exec(hfigure);
h=get(hfigure,'UserData');
if h.line.handler==-1,
return;
end
% get sets
sets=get(h.axes1,'UserData');
% no data set loaded
if isempty(sets)==1,
return;
end
% get parameters
t=h.line.t;
alpha=h.line.alpha;
theta=h.line.theta;
iter=max(1,round(str2num(get(h.editer,'String'))));
epsil=str2num(get(h.edeps,'String'));
if mod(h.stepcnt,2) ~= 0 & t > 0,
iter = -1;
end
% perform one adaptation step
switch get(h.pualgo,'Value')
case 1
%
%[alpha,theta,solution,tplus1]=perceptr(sets.X,sets.I,iter,t,alpha,theta);
if iter==-1, tmp_options.tmax = -1; else tmp_options.tmax=t+iter; end
init_model.t=t;
init_model.W=alpha;
init_model.b=-theta;
tmp_model = perceptron(sets,tmp_options,init_model);
if iter==-1,
if tmp_model.last_update, alpha=sets.X(:,tmp_model.last_update);
else alpha=tmp_model.W; end
else
alpha = tmp_model.W;
end
solution=tmp_model.exitflag;
tplus1 = tmp_model.t;
theta = -tmp_model.b;
case 2
%%
%% [alpha,theta,solution,tplus1]=kozinec(sets.X,sets.I,iter,t,alpha,theta);
if iter==-1, tmp_options.tmax = -1; else tmp_options.tmax=t+iter; end
tmp_options.eps=-1;
if t~=0,
init_model.t=t;
init_model.W=alpha;
init_model.b=-theta;
tmp_model = ekozinec(sets,tmp_options, init_model);
else
tmp_model = ekozinec(sets,tmp_options);
end
if iter==-1,
if tmp_model.last_update, alpha=sets.X(:,tmp_model.last_update);
else alpha=tmp_model.W; end
else
alpha = tmp_model.W;
end
solution=tmp_model.exitflag;
tplus1 = tmp_model.t;
theta = -tmp_model.b;
case 3
% [alpha,theta,solution,tplus1]=ekozinec(sets.X,sets.I,epsil,iter,t,...
% alpha,theta);
if iter==-1, tmp_options.tmax = -1; else tmp_options.tmax=t+iter; end
if t~=0,
init_model.t=t;
init_model.W=alpha;
init_model.b=-theta;
tmp_options.eps=epsil;
tmp_model = ekozinec(sets,tmp_options,init_model);
else
tmp_options.eps=epsil;
tmp_model = ekozinec(sets,tmp_options);
end
if iter==-1,
if tmp_model.last_update, alpha=sets.X(:,tmp_model.last_update);
else alpha=tmp_model.W; end
else
alpha = tmp_model.W;
end
solution=tmp_model.exitflag;
tplus1 = tmp_model.t;
theta = -tmp_model.b;
case 4
tmp_options.ker='linear';
tmp_options.C = 1e12;
% [alpha,theta,solution]=svmmot(sets.X,sets.I);
tmp_model=smo(sets,tmp_options);
% if tmp_model.exitflag <=0, solution=-1; else solution=1; end
if tmp_model.trnerr > 0, solution = -1; else solution=1; end
theta=-tmp_model.b;
alpha=tmp_model.sv.X*tmp_model.Alpha(:);
tplus1=1;
case 5
% [alpha,theta,solution,tplus1]=psum(sets.X,sets.I,10,iter,t,alpha,theta);
% case 6
% [alpha,theta,solution,tplus1]=psumv(sets.X,sets.I,iter,t,alpha,theta);
% case 7
% [alpha,theta,solution,tplus1]=navara1(sets.X,sets.I,iter,t,alpha,theta);
% case 8
% [alpha,theta,solution,tplus1]=navarah1(sets.X,sets.I,iter,t,alpha,theta);
% case 9
% [alpha,theta,solution]=simplex(sets.X,sets.I);
% if solution==0, solution=-1; end
% tplus1=1;
end
return
function []=setaxis(handle,rect)
% function []=setaxis(handle,rect)
%
% SETAXIS sets scaling for the x- and y-axes
% on the plot with a given handle.
%
% See also AXIS.
%
% Statistical Pattern Recognition Toolbox, Vojtech Franc, Vaclav Hlavac
% (c) Czech Technical University Prague, http://cmp.felk.cvut.cz
% Written Vojtech Franc (diploma thesis) 02.01.2000
% Modifications
set(handle,'XLim',rect(1:2));
set(handle,'YLim',rect(3:4));
if size(rect,2)>=6,
set(handle,'ZLim',rect(5:6));
end
return;
%========================================
function [rect]=getaxis(handle)
% function [rect]=getaxis(handle)
%
% GETAXIS returns a row vector containing the scaling for
% the plot with a given handle.
%
% See also AXIS.
%
% Statistical Pattern Recognition Toolbox, Vojtech Franc, Vaclav Hlavac
% (c) Czech Technical University Prague, http://cmp.felk.cvut.cz
% Written Vojtech Franc (diploma thesis) 02.01.2000
% Modifications
% 24. 6.00 V. Hlavac, comments polished.
rect=[get(handle,'XLim'),get(handle,'YLim'),get(handle,'ZLim')];
return;
function [win]=cmpwin(mins,maxs,xborder,yborder)
%
% [win]=cmpwin(mins,maxs,xborder,yborder)
%
% CMPWIN computes appropriate size of the axes.
%
% Statistical Pattern Recognition Toolbox, Vojtech Franc, Vaclav Hlavac
% (c) Czech Technical University Prague, http://cmp.felk.cvut.cz
% Written Vojtech Franc (diploma thesis) 02.01.2000
% Modifications
% 24. 6.00 V. Hlavac, comments polished.
dx=max( (maxs(1)-mins(1)), 1 )*xborder;
dy=max( (maxs(2)-mins(2)), 1 )*yborder;
%x1=floor(mins(1)-dx);
%x2=ceil(maxs(1)+dx);
%y1=floor(mins(2)-dy);
%y2=ceil(maxs(2)+dx);
x1=(mins(1)-dx);
x2=(maxs(1)+dx);
y1=(mins(2)-dy);
y2=(maxs(2)+dx);
win=[x1 x2 y1 y2];
return;
function [x1,y1,x2,y2,in]=cliplin1(alpha,theta,window)
% [x1,y1,x2,y2,in]=cliplin1(alpha,theta,window)
%
% CLIPLIN1 clips the line given by the equation alpha*x=theta along
% the window. It returns two points on the border of the window.
% If the line is in the window then the argument is equal to 1
% else it returns 0.
%
% See also CLIPLIN2.
%
% Statistical Pattern Recognition Toolbox, Vojtech Franc, Vaclav Hlavac
% (c) Czech Technical University Prague, http://cmp.felk.cvut.cz
% Written Vojtech Franc (diploma thesis) 20.10.1999, 23.12.1999
% Modifications
% 24. 6.00 V. Hlavac, comments polished.
minx=window(1);
maxx=window(2);
miny=window(3);
maxy=window(4);
x=zeros(4,1);
y=zeros(4,1);
if alpha(1)==0,
if alpha(2)~=0,
x1=minx;
y1=theta/alpha(2);
x2=maxx;
y2=y1;
in=1;
else
% if alpha == 0 then it means the bad input.
x1=0;
y1=0;
x2=0;
y2=0;
in=0;
end
elseif alpha(2)==0,
x1=theta/alpha(1);
y1=miny;
x2=x1;
y2=maxy;
in=1;
else
y(1)=maxy;
x(1)=(theta-alpha(2)*y(1))/alpha(1);
y(2)=miny;
x(2)=(theta-alpha(2)*y(2))/alpha(1);
x(3)=maxx;
y(3)=(theta-alpha(1)*x(3))/alpha(2);
x(4)=minx;
y(4)=(theta-alpha(1)*x(4))/alpha(2);
j=0;
for i=1:4,
if x(i) <= maxx & x(i) >= minx & y(i) <= maxy & y(i) >= miny,
if j==0,
j=j+1;
x1=x(i);
y1=y(i);
elseif j==1,
j=j+1;
x2=x(i);
y2=y(i);
end
end
end
if j<2,
x1=0;
y1=0;
x2=0;
y2=0;
in=0;
else
in=1;
end
end % elseif alpha(2)==0
function []=clrchild(handle)
% function []=clraxis(handle)
%
% CLRCHILD clears children of an object with the given handle.
%
% See also DELETE.
%
% Statistical Pattern Recognition Toolbox, Vojtech Franc, Vaclav Hlavac
% (c) Czech Technical University Prague, http://cmp.felk.cvut.cz
% Written Vojtech Franc (diploma thesis) 02.01.2000
% Modifications
% 24. 6.00 V. Hlavac, comments polished.
delete(get(handle,'Children'));
return;
function model=ekozinec(data,options,init_model)
% EKOZINEC Kozinec's algorithm for eps-optimal separating hyperplane.
%
% Synopsis:
% model = ekozinec(data)
% model = ekozinec(data,options)
% model = ekozinec(data,options,init_model)
%
% Description:
% This function is implementation of the Kozinec's algorithm
% [Koz73] with eps-optimality stopping condition ([SH10], Chapter 5).
% It transforms the binary-class problem to the single-class problem.
% The nearest point from convex hull of transformed data which
% determines the optimal separating hyperplane is found by the
% Kozinec's algorithm.
%
% model = ekozinec(data) finds eps-optimal separating hyperplane for
% linearly separable data.
%
% model = ekozinec(data,options) specifies stopping conditions of
% the algorithm in structure options:
% .eps [1x1] ... controls how close is the found solution to
% the optimal hyperplane in terms of Euclidien norm of the
% normal vector (default 0.01).
% .tmax [1x1]... maximal number of iterations.
%
% If tmax==-1 then it only returns index (model.last_update)
% of data vector which should be used by the algorithm for updating
% the linear rule in the next iteration.
%
% model = ekozinec(data,options,init_model) specifies initial model
% which must contain:
% .W [dim x 1] ... normal vector.
% .b [1x1] ... bias of hyperplane.
% .t [1x1] (optional) ... iteration number.
%
% Input:
% data [struct] Labeled (binary) training data.
% .X [dim x num_data] Input vectors.
% .y [1 x num_data] Labels (1 or 2).
%
% options [struct]
% .eps [1x1] Precision of found hyperplane (see above).
% .tmax [1x1] Maximal number of iterations (default tmax=inf).
% If tmax==-1 then it does not perform any iteration but returns only
% index of the point which should be used to update linear rule.
%
% init_model [struct] Initial model; must contain items
% .W, .b and .t (see below).
%
% Output:
% model [struct] Found linear classifier:
% .W [dim x 1] Normal vector of hyperplane.
% .b [1x1] Bias of hyperplane.
%
% .exitflag [1x1] 1 ... eps-optimality condition satisfied
% 0 ... number of iterations exceeded tmax.
% .t [int] Number of iterations.
% .last_update [d x 1] Index of the last point used for update.
%
% Example:
% data = genlsdata( 2, 50, 1);
% model = ekozinec(data)
% figure; ppatterns(data); pline(model);
%
% See also
%
% 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:
% 3-may-2004, VF
% 17-sep-2003, VF
% 16-Feb-2003, VF
% 21-apr-2001, V.Franc, created
% get data dimensions
[dim,num_data] = size(data.X);
% Process input arguments
% ------------------------------------
if nargin < 2, options = []; else options = c2s( options ); end
if ~isfield(options,'tmax'), options.tmax = inf; end
if ~isfield(options,'eps'), options.eps = 0.01; end
if nargin < 3,
% make inital model
model.b = 0;
if data.y(1)==1, W = [data.X(:,1);1]; else W = -[data.X(:,1);1]; end
else
% get inital model from input
model = init_model;
W = [model.W; model.b];
end
if ~isfield( model,'t'), model.t = 0; end
model.exitflag = 0;
model.last_update = 0;
% Add one constant coordinates to the data and swap
% points from the second class along the origin.
% ----------------------------------------------------
data.X = [data.X; ones(1,num_data)];
dim=dim+1;
inx = find(data.y==2);
data.X(:,inx) = -data.X(:,inx);
if options.tmax == -1,
% return index of point which should be used to update linear rule
%----------------------------------------------------------------------
norm_W = norm(W);
[min_proj,min_inx]=min( data.X'*W/norm_W );
% bound for separating or eps-optimal separating hyperplane
if options.eps < 0, bound = norm_W/2; else bound = norm_W - options.eps; end
model.last_update = min_inx;
if min_proj <= bound, model.exitflag = 0; else model.exitflag = 1; end
else
% main loop
%----------------
while model.exitflag == 0 & options.tmax > model.t,
model.t = model.t + 1;
norm_W = norm(W);
[min_proj,min_inx]=min( data.X'*W/norm_W );
% bound for separating or eps-optimal separating hyperplane
if options.eps < 0, bound = 0; else bound=norm_W - options.eps; end
if min_proj <= bound,
model.last_update = min_inx;
xt=data.X(:,min_inx);
k=min(1,(W-xt)'*W/((W-xt)'*(W-xt)) );
W = W*(1-k) + xt*k;
model.exitflag = 0;
else
model.exitflag = 1;
end
end
end
model.W = W(1:dim-1);
model.b = W(dim);
model.fun = 'linclass';
return;