function MultiClassifyByDiffusion( cPoints, cTrainLabels, cDiffuser, cDiffuserExtraParam, cClassifier, cClassifierExtraParam )

%
% function ClassifyByDiffusion( cPoints, cTrainLabels, cDiffuser, cDiffuserExtraParam, cClassifier, cClassifierExtraParam )
%
% IN:
%   cPoints                 : M by N matrix of M points in R^N
%   cTrainLabels            : training label function on cPoints, as a M row vector
%   cDiffuser               : pointer to a diffuser function complying to Diffuse_Template.m
%   cDiffuserExtraParam     : extra parameters for the diffuser function
%   cClassifier             : pointer to a classifier function complying to Classifier_Template.m
%   cClassifierExtraParam   : extra parameters for the classifier function
%
% OUT:
%
% USES:
%   cDiffuser, cClassifier
%
% SOURCE CONTROL
%   MM, 3/1/04 ("ClassifyByDiffusion" code)
%   Modified:   AL, 3/12/04 [changes in the way the data is displayed and how routines are called]
%               AL, 3/26/04 [added stopping criteria]

global gDiffuseObj
global gClassifierObj

%plot(cPoints(:,1),cPoints(:,2),'b.');drawnow;pause(0.1);hold on;

% Let cDiffuser create the diffusion object
feval(cDiffuser,'create',cPoints,cDiffuserExtraParam); gDiffuseObj,
% Let cClassifier create the classifier object
feval(cClassifier,'create',cPoints,cTrainLabels,cClassifierExtraParam); gClassifierObj,
lOldLabels=gClassifierObj.L;
cClassifierExtraParam.Diffuser = cDiffuser;

%lClassScore=zeros(gDiffuseObj.NumClasses,floor(cDiffuserExtraParam.maxtime/cDiffuserExtraParam.tstep)); lScoreTime=zeros(size(lClassScore,2),1);
%lAvScore=zeros(size(lClassScore,2),1);
%count=0;
disp_opt=1; %1;
for lTime=1:cDiffuserExtraParam.tstep:cDiffuserExtraParam.maxtime   
    % Diffuse one step
    %lTime, gDiffuseObj.AFlags', bidx=gDiffuseObj.BoundaryIdxs, pause,
    cDiffuserExtraParam.t=lTime; 
    feval(cDiffuser,'diffuse',cPoints,cDiffuserExtraParam); %gDiffuseObj,
    
    if mod(lTime-1,10)==0   % Call classifier %50
        %count=count+1;
        feval(cClassifier,'classify',cPoints,cTrainLabels,cClassifierExtraParam);  % CALL CLASSIFIER
        lTime, change_in_labels=sum(abs(lOldLabels-gClassifierObj.L)), lOldLabels=gClassifierObj.L;  % calculate change in class labels
        if (change_in_labels<1 & lTime>1); gClassifierObj.Stop=1; end;  % STOPPING CRITERIA
        %lScoreTime(count)=lTime; lClassScore(:,count)=gClassifierObj.class_score; lAvScore(count)=gClassifierObj.avscore;
        if (disp_opt==1) % plot labels and scores
            idx=find(gDiffuseObj.AFlags>0); 
            figure(1); scatter(cPoints(idx,1),cPoints(idx,2),15,gClassifierObj.L(idx)); axis image, colorbar
            title(sprintf('LABELS at time %d',lTime-1)),
            %fname=sprintf('corona_labels_%d',lTime-1); print(gcf,'-dpng',fname); 
            %%idx=find(gClassifierObj.score_per_pt>eps); 
           
            %figure(2); scatter(cPoints(idx,1),cPoints(idx,2),15,gClassifierObj.score_per_pt(idx)); 
            %colorbar, title(sprintf('SCORE at time %d',lTime));
            %%fname=sprintf('corona_%d',lTime);print(gcf,'-dpng',fname); 
            
            lTime, pause,
            
            %figure(3), plot(lScoreTime(1:count),lClassScore(:,1:count),'o-'); 
            %hold on; plot(lScoreTime(1:count),lClassScore(1:count),'ko-'); 
            %axis([0 cDiffuserExtraParam.maxtime 0 1]); title(sprintf('CLASS SCORE at time %d',lTime)); drawnow,
            
            %legend('class 1', 'class 2', 'class 3', 'class 4', 'class 5');  % only applies to 5-class problem
            %figure(1); map=[[0 0 1]; [0 1 0]; [1 0 0];  [0 1 1]; [1 0 1]]; colormap(map), colorbar, % bgrcm  % only applies to 5-class problem
            %pause    
        end
        %if 0 % Plot heat distribution
        %    ltemp=full(gDiffuseObj.Heat);
        %    %figure(11), plot(1:gDiffuseObj.M, ltemp,'-o'); axis([1 10 0 1]); % 10 pts
        %    figure(11), plot(1:gDiffuseObj.M, sort(ltemp,2)); axis([0 gDiffuseObj.M 0 1]); 
        %    title(sprintf('Time %d',lTime));drawnow;
        %end
    end
    
    % If the diffuser or the classifier says we should stop, we stop
    if ((gClassifierObj.Stop) | (gDiffuseObj.Stop)),
        figure(1); scatter(cPoints(:,1),cPoints(:,2),15,gClassifierObj.L); colorbar
        title(sprintf('LABELS at time %d',lTime)); pause(0.01),
        %%fname=sprintf('cross_labels_%d',lTime); print(gcf,'-dpng',fname); 
        figure(2); scatter(cPoints(:,1),cPoints(:,2),15,gClassifierObj.score_per_pt); 
        colorbar, title(sprintf('SCORE at time %d',lTime)); pause(0.01),
        %%fname=sprintf('cross_score_%d',lTime);print(gcf,'-dpng',fname); 
        break;
    end;
    %lTime = lTime + 1;
    
end;
return;