## Copyright (c) 1998-2011 Andrew V. Knyazev <andrew.knyazev@ucdenver.edu>
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without",
## modification, are permitted provided that the following conditions are met:
##
##     1 Redistributions of source code must retain the above copyright notice,
##       this list of conditions and the following disclaimer.
##     2 Redistributions in binary form must reproduce the above copyright
##       notice, this list of conditions and the following disclaimer in the
##       documentation and/or other materials provided with the distribution.
##     3 Neither the name of the author nor the names of its contributors may be
##       used to endorse or promote products derived from this software without
##       specific prior written permission.
##
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
## ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
## SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
## CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

% function [A,REF,HMAX,H,R,EQUAL] = polyfitinf(M,N,K,X,Y,EPSH,MAXIT,REF0)
%
%   Best polynomial approximation in discrete uniform norm
%
%   INPUT VARIABLES:
%
%   M       : degree of the fitting polynomial
%   N       : number of data points
%   X(N)    : x-coordinates of data points
%   Y(N)    : y-coordinates of data points
%   K       : character of the polynomial:
%                   K = 0 : mixed parity polynomial
%                   K = 1 : odd polynomial  ( X(1) must be >  0 )
%                   K = 2 : even polynomial ( X(1) must be >= 0 )
%   EPSH    : tolerance for leveling. A useful value for 24-bit
%             mantissa is EPSH = 2.0E-7
%   MAXIT   : upper limit for number of exchange steps
%   REF0(M2): initial alternating set ( N-vector ). This is an
%             OPTIONAL argument. The length M2 is given by:
%                   M2 = M + 2                      , if K = 0
%                   M2 = integer part of (M+3)/2    , if K = 1
%                   M2 = 2 + M/2 (M must be even)   , if K = 2
%
%   OUTPUT VARIABLES:
%
%   A       : polynomial coefficients of the best approximation
%             in order of increasing powers:
%                   p*(x) = A(1) + A(2)*x + A(3)*x^2 + ...
%   REF     : selected alternating set of points
%   HMAX    : maximum deviation ( uniform norm of p* - f )
%   H       : pointwise approximation errors
%	R		: total number of iterations
%   EQUAL   : success of failure of algorithm
%                   EQUAL=1 :  succesful
%                   EQUAL=0 :  convergence not acheived
%                   EQUAL=-1:  input error
%                   EQUAL=-2:  algorithm failure
%
%   Relies on function EXCH, provided below.
%
%   Example: 
%   M = 5; N = 10000; K = 0; EPSH = 10^-12; MAXIT = 10;
%   X = linspace(-1,1,N);   % uniformly spaced nodes on [-1,1]
%   k=1; Y = abs(X).^k;     % the function Y to approximate
%   [A,REF,HMAX,H,R,EQUAL] = polyfitinf(M,N,K,X,Y,EPSH,MAXIT);
%   p = polyval(A,X); plot(X,Y,X,p) % p is the best approximation
%
%   Note: using an even value of M, e.g., M=2, in the example above, makes
%   the algorithm to fail with EQUAL=-2, because of collocation, which
%   appears because both the appriximating function and the polynomial are
%   even functions. The way aroung it is to approximate only the right half
%   of the function, setting K = 2 : even polynomial. For example: 
%
% N = 10000; K = 2; EPSH = 10^-12; MAXIT = 10;  X = linspace(0,1,N);
% for i = 1:2
%     k = 2*i-1; Y = abs(X).^k;
%     for j = 1:4
%         M = 2^j;
%         [~,~,HMAX] = polyfitinf(M,N,K,X,Y,EPSH,MAXIT);
%         approxerror(i,j) = HMAX;
%     end
% end
% disp('Table 3.1 from Approximation theory and methods, M.J.D.POWELL, p. 27');
% disp(' ');
% disp('            n          K=1          K=3'); 
% disp(' '); format short g;
% disp([(2.^(1:4))' approxerror']);
%
%   ALGORITHM:
%
%   Computation of the polynomial that best approximates the data (X,Y)
%   in the discrete uniform norm, i.e. the polynomial with the  minimum
%   value of max{ | p(x_i) - y_i | , x_i in X } . That polynomial, also
%   known as minimax polynomial, is obtained by the exchange algorithm,
%   a finite iterative process requiring, at most,
%      n
%    (   ) iterations ( usually p = M + 2. See also function EXCH ).
%      p
%   since this number can be very large , the routine  may not converge
%   within MAXIT iterations . The  other possibility of  failure occurs
%   when there is insufficient floating point precision  for  the input
%   data chosen.
%
%   CREDITS: This routine was developed and modified as 
%   computer assignments in Approximation Theory courses by 
%   Prof. Andrew Knyazev, University of Colorado Denver, USA.
%
%   Team Fall 98 (Revision 1.0):
%           Chanchai Aniwathananon
%           Crhistopher Mehl
%           David A. Duran
%           Saulo P. Oliveira
%
%   Team Spring 11 (Revision 1.1): Manuchehr Aminian
%
%   The algorithm and the comments are based on a FORTRAN code written
%   by Joseph C. Simpson. The code is available on Netlib repository:
%   http://www.netlib.org/toms/501
%   See also: Communications of the ACM, V14, pp.355-356(1971)
%
%   NOTES:
%
%   1) A may contain the collocation polynomial
%   2) If MAXIT is exceeded, REF contains a new reference set
%   3) M, EPSH and REF can be altered during the execution
%   4) To keep consistency to the original code , EPSH can be
%   negative. However, the use of REF0 is *NOT* determined by
%   EPSH< 0, but only by its inclusion as an input parameter.
%
%   Some parts of the code can still take advantage of vectorization.  
%
%   Revision 1.0 from 1998 is a direct human translation of 
%   the FORTRAN code http://www.netlib.org/toms/501
%   Revision 1.1 is a clean-up and technical update.  
%   Tested on MATLAB Version 7.11.0.584 (R2010b) and 
%   GNU Octave Version 3.2.4

%   $Revision: 1.1 $  $Date: 2011/08/3 $

%       ************************************ beginning of POLYFITINF
function [A,REF,HMAX,H,R,EQUAL] = polyfitinf(M,N,K,X,Y,EPSH,MAXIT,REF0)

    % Preassign output variables A,REF,HMAX,H,R,EQUAL in case of error return
    A = []; REF = []; HMAX = []; H = []; R = 0; EQUAL = -2;
    %%%% end preassignment

    %       Setting M with respect to K
    MOLD = M;

    switch K
        case 1
            K0 = 0;
            K1 = 1;
            Q1 = 1;
            Q2 = 2;
            M =  (M-Q1)/2;
        case 2
            K0 = 0;
            K1 = 0;
            Q1 = 0;
            Q2 = 2;
            
            % If the user has input odd M, but wants an even polynomial,
            % subtract 1 from M to prevent errors later. The outputs should be
            % mathematically equivalent.
            if mod(M,2) == 1
                M = M-1;
            end
            
            M =  (M-Q1)/2;
        otherwise
            if (K ~= 0)
                warning('polyfitinf:MixedParity','Using mixed parity polynomial...');
            end
            K0 = 1;
            K1 = 0;
            Q1 = 0;
            Q2 = 1;
    end

    P = M + 2;

    %       Check input data consistency

    if ( (length(X) ~= N) || (length(Y) ~= N) )
        error('Input Error: check data lengths');
    end

    if (P > N)
        error('Input Error: insufficient data points');
    end

    if (M < 0)
        error('Input Error: insufficient degree');
    end

    if ( (K == 2) && (X(1) < 0) ) || ( (K == 1) && (X(1) <= 0) )
        error('Input Error: X(1) inconsistent with parity');
    end

    if any(diff(X)<0)
        error('Input Error: Abscissae out of order');
    end

    ITEMP = MOLD + 1;

    A = zeros(1,ITEMP);


    ITEMP = P + 2;
    Z = zeros(1,ITEMP);
    Z(1) = 0;
    Z(ITEMP) = N + 1;

    EPSH = abs(EPSH);

    %       Read initial reference set into Z, if available.

    if (nargin == 8)
        J = 0;
        
        Z(2:(P+1))= REF0(1:P);
        
        %	Check if REF is monotonically increasing
        if ( any(diff(REF0) < 0) || any(REF0 > J) )
            error('Input Error : Bad initial reference set');
        end
        
    else
        
        %          Loads Z with the points closest to the Chebychev abscissas
        
        X1 = X(1);
        XE = X(N);
        
        %          Setting parity-dependent parameters
        
        if (K0 == 1)
            XA = XE + X1;
            XE = XE - X1;
            Q = pi/(M + 1.0);
        else
            XA = 0.;
            XE = XE + XE;
            ITEMP = 2*(M+1) + Q1;
            Q = pi/(ITEMP);
        end
        
        %          Calculate the J-th Chebyshev abcissa and load Z(J+1)
        %          with the appropriate index from the data abcissas
        
        for JJ = 1:P
            J = P + 1 - JJ;
            X1 = XA + XE*( cos(Q*(P-J)) );
            ITEMP = J + 2;
            R = Z(ITEMP);
            HIGH = R - 1;
            FLAG = 1;
            if (HIGH >= 2)
                II = 2;
                while ( (II <= HIGH) && (FLAG == 1) )
                    I = HIGH + 2 - II;
                    ITEMP = I - 1;
                    
                    %			If the Chebyschev abscissa is bracketed by
                    % 		     two input abcissas, get out of the while loop
                    
                    if (X(I)+X(ITEMP) <= X1)
                        FLAG = 0;
                    end
                    II = II + 1;
                end
            end
            
            if (FLAG == 1)
                I = 1;
            end
            ITEMP = J + 1;
            
            if (I < R)
                Z(ITEMP) = I;
            else
                Z(ITEMP) = R - 1;
            end
        end
        
        %          If the lower Chebyshev abcissas are less than X(1),
        %          load the lower elements of Z with the lowest points

        IND = find(Z(2:end) >= (1:(length(Z)-1)));
        
        try TEMP = IND(1);	% If IND is empty, do nothing.
        catch exception % The catch will be that IND is an empty array.
            
            if strcmpi(exception.identifier,'MATLAB:badsubscript')
                % This will be the exception. Do nothing.
            end
        end
        
        if TEMP~=1
            Z(2:TEMP) = (1:(TEMP-1))';
        end
        
        
    end

    %       M1 entry. Initialize variables to prepare for exchange iteration

    ITEMP = M + 1;


    %       Zero the AA array


    AA = zeros(1,ITEMP);


    %       Load H with the ordinates and XX(I) with the abscissas if the
    %       polynomial is mixed . If it is even or odd , load XX with the
    %       squares of the abscissas.

    H(1:N) = Y(1:N);
    if (K0 <=0)
        XX(1:N) = X(1:N).^2;
    else
        XX(1:N) = X(1:N);
    end

    B1 = 0;
    B2 = 0;
    B3 = 0;
    R = -1;
    T = 0.;

    %       Iteration entry. R is the iteration index

    C = zeros(1,P);
    D = zeros(1,P);
    DAA = zeros(1,M+1);

    FLAG = 1;
    while ( (R < MAXIT) && (FLAG == 1) )
        
        R = R + 1;   % LABEL 350
        %S = 1.;
        
        %          Computation of div. differences schemes
        
        if (K1 > 0)
            
            %               If the polynomial is mixed or even:
            %for I = 1:P
            %    S = -S;
            %    ITEMP = I + 1;
            %    J = Z(ITEMP);
            %    Q = X(J);
            %    C(I) = (H(J) + S*T)/Q;
            %    D(I) = S/Q;
            %end

	    I = (1:P);
       	S = (-1).^I;
	    ITEMP = I+1;
	    J = Z(ITEMP);
	    C(I) = (H(J) + S*T)./X(J);
	    D(I) = S./Q;
	    clear I ITEMP S J
        
        else
            
            %               If the polynomial is odd:
            %for I = 1:P
            %    S = -S;
            %    ITEMP = I + 1;
            %    ITEMP = Z(ITEMP);
            %    C(I) = H(ITEMP) + S*T;
            %    D(I) = S;
            %end

	    I = (1:P);
       	S = (-1).^I;
	    ITEMP = I+1;
	    C(I) = H( Z(ITEMP) ) + S.*T;
	    D(I) = S;
        clear I ITEMP S
            
        end
        
        for I = 2:P
            for JJ = I:P
                J = P + I - JJ;
                ITEMP = J + 1;
                ITEMP = Z(ITEMP);
                QD = XX(ITEMP);
                ITEMP = 2 + J - I;
                ITEMP = Z(ITEMP);
                QD = QD - XX(ITEMP);
                ITEMP = J - 1;
                C(J) = (C(J)-C(ITEMP))/QD;
                D(J) = (D(J)-D(ITEMP))/QD;
            end
        end
        
        DT = -C(P)/D(P);
        T = T + DT;
        
        %           Computation of polynomial coefficients
        
        HIGH = M + 1;
        for II = 1:HIGH
            I = HIGH - II;
            ITEMP = I + 1;
            DAA(ITEMP) = C(ITEMP) + DT*D(ITEMP);
            ITEMP = I + 2;
            ITEMP = Z(ITEMP);
            QD = XX(ITEMP);
            LOW = I + 1;
            if (M >= LOW)
                DAA(LOW:M) = DAA(LOW:M) - QD*DAA(((LOW:M)+1));
            end
        end
        
        AA(1:HIGH) = AA(1:HIGH) + DAA(1:HIGH);
        
        %	   Evaluation of the polynomial to get the approximation errors
        
        MAXX = 0.;
        H = zeros(1,N);
        for I = 1:N
            SD = AA(HIGH);
            QD = XX(I);
            if (M > 0)
                for J = M:-1:1
                    SD = SD*QD + AA(J);
                end
            end
            if (K1 > 0)
                %		   If the polynomial is odd, multiply SD by X(I)
                SD = SD*X(I);
            end
            
            QD = Y(I) - SD;
            H(I) = Y(I) - SD;
            
            if  (abs(QD) > MAXX)
                %		   Load MAXX with the largest magnitude
                %		   of the approximation array
                MAXX = abs(QD);
            end
        end
        
        %	   Test for alternating signs
        
        ITEMP = Z(2);
        
        if (H(ITEMP) == 0.)
            
            %               This represents a case where the polynomial
            %               exactly predicts a data point
          
            warning('polyfitinf:Collocation','Collocation has occured.');
            if (B3 > 0)
                B3 = -1;
                FLAG = 0;
            else
                B3 = 1;
                if (EPSH < MAXX)
                    warning('polyfitinf:AnotherTry','1 more attempt with middle points');
                    LOW = (N+1)/2 - (P+1)/2 + 1;
                    HIGH = LOW + P;
                    Z(LOW:HIGH) = ( (LOW:HIGH) -1);
                    
                else
                    disp('Normal Exit.');
                    FLAG = 0;
                end
            end
        else
            
            if (H(ITEMP) > 0.)
                J = -1;
            else
                J =  1;
            end
            
            I = 2;
            FLAG2 = 1;
            while ( (I <= P) && (FLAG2 == 1) )
                ITEMP = I + 1;
                ITEMP = Z(ITEMP);
                if (H(ITEMP) == 0.)
                    J = 0;
                    warning('polyfitinf:Collocation','Collocation has occured.');
                    if (B3 > 0)
                        B3 = -1;
                        FLAG = 0;
                    else
                        B3 = 1;
                        if (EPSH < MAXX)
                            warning('polyfitinf:AnotherTry','1 more attempt with middle points');
                            LOW = (N+1)/2 - (P+1)/2 + 1;
                            HIGH = LOW + P;
                            Z(LOW:HIGH) = ( (LOW:HIGH) -1);
                        else
                            disp('Normal Exit.');
                            FLAG = 0;
                        end
                    end
                    FLAG2 = 0;
                else
                    if (H(ITEMP) < 0)
                        JJ = -1;
                    else
                        JJ = 1;
                    end
                    if (J~=JJ)
                        
                        %			   Error entry: bad accuracy for calculation
                        
                        B1 = 1;
                        FLAG2 = 0;
                        FLAG = 0;
                    else
                        J = -J;
                    end
                end
                
                I = I + 1;
                
            end	% end of while
            
            %                  Search for another reference
            
            if (FLAG2*FLAG == 1)
                
                [H,Z,EQUAL] = exch(N, P, EPSH, H, Z);
                if (EQUAL > 0)
                    FLAG = 0;
                else
                    if (R >= MAXIT)
                        B2 = 1;
                        FLAG = 0;
                    end
                end
                
            end
            
        end	  % end of if over H(ITEMP)
        
    end;      % end of iteration loop

    %       M2 entry; load output variables and return

    HIGH = M + 1;

    %       Load the coefficients into A array

    A(Q1 + Q2*(((1:HIGH)-1)) + 1) = AA(1:HIGH);

    %       Load REF with the final reference points

    REF(1:P) = Z((1:P) + 1);

    HMAX = MAXX;

    if (B3 < 0)
        EQUAL = -2;
        warning('polyfitinf:Collocation','polyfitinf terminates');
    end
    if (B1 > 0)
        EQUAL = -2;
        warning('polyfitinf:NoAlternatingSigns','Alternating signs not observed');
    end
    if (B2 > 0)
        EQUAL = 0;
        warning('polyfitinf:MaxIterationsReached','MAXIT was reached, current ref. set saved in REF.');
    end

    % Reverse the order of A to make it compatible with MATLAB'S polyval() function.
    A = A(end:-1:1);


endfunction
%	****************************************** end of POLYFITINF

function [H,Z,EQUAL] = exch(N, P, EPSH, H, Z)
% function [H,Z,EQUAL] = exch(N, P, EPSH, H, Z)
%
%   EXCH: exchange algorithm
%
%   INPUT VARIABLES:
%   N       : number of data points
%   P	: number of reference points
%   EPSH    : tolerance for leveling.
%   Z	: old reference indices
%
%   OUTPUT VARIABLES:
%   H       : pointwise approximation errors
%   Z	: new reference indices
%   EQUAL   :	EQUAL=1 :  normal exchange
%                   EQUAL=0 :  old and new references are equal
%
%   CREDITS: This routine was developed and modified as 
%   computer assignments in Approximation Theory courses by 
%   Prof. Andrew Knyazev, University of Colorado Denver, USA.
%
%   Team Fall 98 (Revision 1.0):
%           Chanchai Aniwathananon
%           Crhistopher Mehl
%           David A. Duran
%           Saulo P. Oliveira
%
%   Team Spring 11 (Revision 1.1): Manuchehr Aminian
%
%   The algorithm and the comments are based on a FORTRAN code written
%   by Joseph C. Simpson. The code is available on Netlib repository:
%   http://www.netlib.org/toms/501
%   See also: Communications of the ACM, V14, pp.355-356(1971)
%
%   Revision 1.0 from 1998 is a direct human translation of 
%   the FORTRAN code http://www.netlib.org/toms/501
%   Revision 1.1 is a clean-up and technical update.  
%   Tested on MATLAB Version 7.11.0.584 (R2010b) and 
%   GNU Octave Version 3.2.4

%   License: BSD
%   Copyright 1998-2011 Andrew V. Knyazev
%   $Revision: 1.1 $  $Date: 2011/05/17 $

%       ************************************ beginning of exch

    EQUAL = 0;
    L = 0;
    ITEMP =  Z(2);

    %	SIG is arbitrarily chosen equal to the sign of the input
    %	point. This will be adjusted later if necessary.

    if (H(ITEMP) <= 0)
        SIG = 1.;
    else
        SIG = -1.;
    end

    %	The next loop prescans Z to insure it is a proper choice, i.e
    %	resets Z if necessary so that maximum error points are chosen,
    %	given the sign convention mentioned above. In order to work
    %	properly, this section requires Z(1) = 0 and Z(P+2) = N + 1 .

    for I = 1:P
        MAXX = 0.;
        SIG = -SIG;
        ITEMP = I + 2;
        ZE  =  Z(ITEMP) - 1;
        LOW =  Z(I) + 1;
        
        %	   Scan the open point interval containing only the 1th initial
        %	   reference point. In the interval pick the point with largest
        %	   magnitude and correct sign. Most of the sorting occurs in
        %	   this section. SIG contains the sign assumed for H(I).
        
        for J = LOW:ZE
            if (SIG*(H(J)-MAXX) > 0)
                MAXX = H(J);
                INDEX = J;
            end
        end
        ITEMP = I + 1;
        ITEMP =  Z(ITEMP);
        MAXL = abs(MAXX);
        
        %	   If the MAX error is significantly greater than the
        %	   input point, switch to this point.
        
        if (abs( MAXX - H(ITEMP) )/MAXL > EPSH)
            ITEMP = I + 1;
            Z(ITEMP) = INDEX;
            L = 1;
        end
    end
    %
    MAXL = 0.;
    MAXR = 0.;
    ITEMP = P + 1;
    LOW =  Z(ITEMP) + 1;
    %
    if (LOW <= N)
        
        %	   Find the error with largest abs value and proper sign
        %	   from among the points above the last reference point.
        %	   This section is necessary because the set of points
        %	   chosen may begin with the wrong sign alternation.
        
        for J = LOW:N
            if (SIG*(MAXR-H(J)) > 0)
                MAXR = H(J);
                INDR = J;
            end
        end
    end

    %	Find the error with largest abs value and proper sign
    %	from among the points below  the 1st reference  point.
    %	This section is necessary by the same reason as above.

    ITEMP =  Z(2);
    HZ1 = H(ITEMP);
    HIGH = ITEMP -1;
    if (HIGH > 0)
        if (HZ1 < 0)
            SIG = -1.;
        elseif (HZ1 == 0)
            SIG = 0.;
        else
            SIG = 1.;
        end
        
        for J = 1:HIGH
            if (SIG*(MAXL-H(J)) > 0)
                MAXL = H(J);
                INDL = J;
            end
        end
        
    end

    %	MAXL and MAXR contain the magnitude of the significant
    %	errors outside the reference point set. If either is
    %	zero, the reference point set extends to the end point
    %	on that side of the interval.

    MAXL = abs(MAXL);
    MAXR = abs(MAXR);
    HZ1 = abs(HZ1);
    ITEMP = P + 1;
    ITEMP =  Z(ITEMP);
    HZP = abs(H(ITEMP));

    %	L = 0 implies that the previous prescan did not change
    %	any points. If L = 0 and MAXL, MAXR are not significant
    %	if compared with upper and lower reference point errors,
    %	respectively, use the EQUAL exit.

    FLAG1 = 1;
    if (L == 0)
        if ( (MAXL == 0) || (EPSH >= (MAXL-HZP)/MAXL) )
            if ( (MAXR == 0) || (EPSH >= (MAXR-HZ1)/MAXR) )
                FLAG1 = 0;
                EQUAL = 1;
            end
        end
    end

    if ( (MAXL == 0) && (MAXR == 0) )
        FLAG1 = 0;
    end

    if ( (MAXL > MAXR) && (MAXL <= HZP) && (MAXR < HZ1) )
        FLAG1 = 0;
    end

    if ( (MAXL <= MAXR) && (MAXR <= HZ1) && (MAXL < HZP) )
        FLAG1 = 0;
    end

    %	If a point outside the present reference set must be
    %	included, (i.e. the sign of the 1st point previously
    %	assumed is wrong) shift to the side of largest
    %	relative error first.

    if (FLAG1 == 1)
        
        FLAG2 = 1;
        
        if ( (MAXL > MAXR) && (MAXL > HZP) )
            FLAG2 = 0;
        end
        
        if ( (MAXL <= MAXR) && (MAXR <= HZ1) )
            FLAG2 = 0;
        end
        
        if (FLAG2 == 1)
            
            %		SHR entry. This section inserts a point from
            %		above the prescan point set
            
            INDEX = Z(2);
            
            %		shift point set down, dropping the lowest point
            
            Z(2:P) = Z((2:P)+1);
            
            ITEMP = P + 1;
            
            %		add the next high point
            Z(ITEMP)=INDR;
            
            %		if MAXL > 0 replace reference points from the left,
            %		stopping the 1st time the candidate for replacement
            %		is greater than in magnitude than the prospective
            %		replacee. Alternation of signs is preserved because
            %		non-replacement immediately terminates the process.
            
            if (MAXL > 0)
                I = 2;
                FLAG3 = 1;
                while ( (I <= P) && (FLAG3 == 1) )
                    ITEMP = Z(I);
                    if ( abs(H(INDL)) >= abs(H(ITEMP)) )
                        J = Z(I);
                        Z(I) = INDL;
                        INDL = INDEX;
                        INDEX = J;
                    else
                        FLAG3 = 0;
                    end
                    I = I + 1;
                end
            end
            
        else
            
            %	   SHL entry. This section inserts a point from below the
            %	   prescan point set.
            
            ITEMP = P + 1 ;
            INDEX = Z(ITEMP);
            
            Z((2:P)+1) = Z(2:P);
            
            %		store lowest point in Z(2)
            Z(2) = INDL;
            
            %		if MAXR > 0 replace reference points from the right,
            %		stopping the 1st time the candidate for replacement
            %		is greater than in magnitude than the prospective
            %		replacee.
            
            if (MAXR > 0)
                II = 2;
                FLAG3 = 1;
                while ( (II <= P) && (FLAG3 == 1) )
                    I = P + 2 - II;
                    ITEMP = I + 1;
                    HIGH = Z(ITEMP);
                    if ( abs(H(INDR)) >= abs(H(HIGH)) )
                        J = Z(ITEMP);
                        Z(ITEMP) = INDR;
                        INDR = INDEX;
                        INDEX = J;
                    else
                        FLAG3 = 0;
                    end
                    II = II + 1;
                end
            end
            
        end
        
    end

endfunction
%	****************************************** end of exch
