% FUNCTION [ LOCAL_MAX_LIST, LOCAL_MAX_VALUE_LIST ] = LOCAL_MAX_STRICT_FAST( DATA, NBEST )
%
% For each row of DATA, return the list of local maxima ( "greater and
% not equal" meaning ). This is the same code as "LOCAL_MAX_STRICT", but most
% safety tests have been removed. Use it only when you are sure of
% your own code.
%
% DATA: a matrix of real values of any dimensionality D [ N1 N2 N3 ... ND ].
%
% LOCAL_MAX_LIST: a cell array of dimension [ N2 N3 ... ND ]. 
%   LOCAL_MAX_LIST{ I2, I3, ... , ID } is a vector.
%   This vector is the list of row indices of local maxima of DATA( :, I2, I3, ..., ID ). 
%
% LOCAL_MAX_VALUE_LIST: a cell array of dimension [ N2 N3 ... ND ]. 
%   LOCAL_MAX_VALUE_LIST{ I2, I3, ... , ID } is a vector.
%   This vector is the list of values of local maxima of DATA( :, I2, I3, ..., ID ). 
%   ( same order as in LOCAL_MAX_LIST )
%
% (optionally) NBEST: integer, a maximum bound on the number of local maxima 
%   returned in each vector.
%
% Note: if NBEST is not used, then the results are ordered by
% increasing row index. If NBEST is used, then the results are ordered
% by decreasing value (global maximum comes first, second best comes
% second, etc.).
%
% Therefore, if you want all local maxima, ordered by decreasing
% value, use NBEST = +Inf.
%
%
%
% See also: LOCAL_MAX, LOCAL_MAX_FAST, LOCAL_MAX_STRICT, LOCAL_MAX_STRICT_FAST
%
% By Guillaume Lathoud 2004 - lathoud@idiap.ch

function [ local_max_list, local_max_value_list ] = local_max_strict_fast( data, nbest )

  siz = size( data );
  
  if nargout < 2
    
    % We work in flat 2-dimensional space,
    % and at the end we reshape "local_max_list".
    %
    % This way any dimensionality of "data" can be processed.
    
    local_max_list       = cell( prod( siz( 2:end ) ), 1 );
    
    % Two ways, depending on "nbest" parameter
    
    if nargin > 1

      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      % Limit the number of local maxima

      if nbest == 0
	if ~strcmp( warning, 'off' )
	  disp( 'local_max: WARNING! nbest = 0' );
	end
	
	local_max_list = cell( siz( 2:end ) );
	
	if nargout > 1
	  local_max_value_list = cell( siz( 2:end ) );
	end
	
	return;
	
      end

      
      for a = 1:length( local_max_list )
	
	d = diff( [ -Inf; data( :, a ); -Inf ] );
	
	ind = find( ( d( 1:end-1 ) > 0 ) & ( d(2:end) < 0 ) );
	
	v = data( ind, a );
	[ v, ind2 ] = sort( -v );
	
	if length( ind ) > nbest
	  ind2 = ind2( 1:nbest );
	end
	
	ind = ind( ind2 );
	
	local_max_list{ a }       = ind;
	
      end
      
      % Reshape the result to match with "data" size
      
      local_max_list       = reshape( local_max_list, [ siz( 2:end ) 1 ] );
      
    else
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   
      % Return all local maxima
      
      for a = 1:length( local_max_list )
	
	d = diff( [ -Inf; data( :, a ); -Inf ] );
	
	local_max_list{ a }       = find( ( d( 1:end-1 ) > 0 ) & ( d(2:end) < 0 ) );
	
      end      

      % Reshape the result to match with "data" size
      
      local_max_list        = reshape( local_max_list, [ siz( 2:end ) 1 ] );
      
    end

  else   % if nargout > 1
    
    % ----------------------------------------------------------------------
    % Also return values at the local maxima
    
    % We work in flat 2-dimensional space,
    % and at the end we reshape "local_max_list".
    %
    % This way any dimensionality of "data" can be processed.
    
    local_max_list       = cell( prod( siz( 2:end ) ), 1 );
    local_max_value_list = cell( prod( siz( 2:end ) ), 1 );
    
    % Two ways, depending on "nbest" parameter
    
    if nargin > 1

      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      % Limit the number of local maxima

      if nbest == 0
	if ~strcmp( warning, 'off' )
	  disp( 'local_max: WARNING! nbest = 0' );
	end
	
	local_max_list = cell( siz( 2:end ) );
	
	if nargout > 1
	  local_max_value_list = cell( siz( 2:end ) );
	end
	
	return;
	
      end

      
      for a = 1:length( local_max_list )
	
	d = diff( [ -Inf; data( :, a ); -Inf ] );
	
	ind = find( ( d( 1:end-1 ) > 0 ) & ( d(2:end) < 0 ) );
	
	v = data( ind, a );
	[ v, ind2 ] = sort( -v );
	v = -v;
	
	if length( v ) > nbest
	  v   = v( 1:nbest );
	  ind2 = ind2( 1:nbest );
	end
	
	ind = ind( ind2 );
	
	local_max_list{ a }       = ind;
	local_max_value_list{ a } = v;
	
      end
      
      % Reshape the result to match with "data" size
      
      local_max_list       = reshape( local_max_list, [ siz( 2:end ) 1 ] );
      local_max_value_list = reshape( local_max_value_list, [ siz( 2:end ) 1 ] );
      
    else
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   
      % Return all local maxima
      
      for a = 1:length( local_max_list )
	
	d = diff( [ -Inf; data( :, a ); -Inf ] );
	
	local_max_list{ a }       = find( ( d( 1:end-1 ) > 0 ) & ( d(2:end) < 0 ) );
	local_max_value_list{ a } = data( local_max_list{ a }, a );
	
      end      

      % Reshape the result to match with "data" size
      
      local_max_list        = reshape( local_max_list, [ siz( 2:end ) 1 ] );
      local_max_valuse_list = reshape( local_max_value_list, [ siz( 2:end ) 1 ] );
      
    end
    
  end
  