#
#--> ratinterp(x,y,v): Rational Function interpolation
#
# Computers f(v) a rational function such that f(x[i])=y[i].
# 
# Author: Carlos von Achenbach, October 93
#
ratinterp:= proc(x,f,v)

local r,den,S,Sstr,i,ind,j,jbest,stepa,stepb,stepc,n,t,a,g;

# Test input

if type(x,vector) and type(f,vector) then
        RETURN(ratinterp(convert(x,list),convert(f,list),v))
fi:
if not type(x,list) or not type(f,list) then 
        ERROR(`argument must be a list or vector`)
fi:
if nops(x)<>nops({op(x)}) then ERROR(`x values must be distinct`) fi;
if f[1]=infinity then ERROR(`Wrong input`) fi:
if nops(x)<>nops(f) then 
	ERROR(`second arg. must be of the same length as the first arg.`)
fi:
n:= nops(x)-1;
g:= table();
a:= array(1..n);

# Initialisation

S:= x[1];
for j to n do S:= S,x[j+1] od:
S:= [S];
for j to n do 
	if f[j+1]=infinity then 
		g[0,S[j+1]]:= infinity
	else
		g[0,S[j+1]]:= f[j+1]-f[1] 
	fi:
od:

# Iteration

for j to n do
	stepa:= false;
        for ind from j+1 to n+1 do
                if g[j-1,S[ind]] <> 0 and g[j-1,S[ind]] <> infinity then
                        jbest:= ind;
                        stepa:= true;
                        break;
                fi:
        od:
        if stepa then 
                Sstr:= S[1];
                for i from 2 to j do Sstr:= Sstr,S[i] od:
                Sstr:= Sstr,S[jbest];
                for i from j+1 to jbest-1 do Sstr:= Sstr,S[i] od:
                for i from jbest+1 to n+1 do Sstr:= Sstr,S[i] od:
                S:= [Sstr];
                a[j]:= g[j-1,S[j+1]]/(S[j+1]-S[j]);
                for ind from j+2 to n+1 do
			if g[j-1,S[ind]]=0 then
				g[j,S[ind]]:= infinity
			elif g[j-1,S[ind]]=infinity then
				g[j,S[ind]]:= -1
			else
                        	g[j,S[ind]]:= (a[j]*(S[ind]-S[j])/
                                       	       g[j-1,S[ind]])-1
			fi:
                od:
                if j=n then t:= n; break; fi:
        else
                stepb:= true; stepc:= false;
                for ind from j+1 to n+1 do
                        if g[j-1,S[ind]] <> 0 then
                                stepb:= false;
                                stepc:= true;
                        fi:
                od:
                if stepb then
                        t:= j-1;
                        break;
                fi:
                if stepc then
                        ERROR(`Interpolation does not exist`)
                fi:
        fi:
od:

# Termination

den:= 1;
for i from t by -1 to 2 do
	den:= normal( 1 + (v-S[i])*a[i]/den )
od:
if t=0 then
	r:= f[1]
else
	r:= f[1] + (v-S[1])*a[1]/den
fi:
RETURN(normal(r));

end:

`help/text/ratinterp` := TEXT(`      `,
`FUNCTION: ratinterp - rational function interpolation`,`      `,
`CALLING SEQUENCE:`,`   ratinterp( x, y, v )`,`      `,`PARAMETERS:`,
`   x - list or vector of independent values, [x[1],..x[n]]`,
`   y - list or vector of dependent values, [y[1],..y[n]]`,
`   v - variable to be used in a rational function`,`      `,`SYNOPSIS:   `,
`- The function ratinterp computes the rational function of variable v which `,
`  interpolates the points (x[1],y[1]), (x[2],y[2]), ..., (x[n],y[n]).`,
`  If n is odd then the numerator and denominator polynomials will have degree`
,`  (n-1)/2.  Otherwise, n is even and the degree of the numerator is n/2 and \
the `,`  degree of the denominator is n/2-1.`,`      `,`- If the same x-value \
is entered twice, it is an error, whether or not the same`,
`  y-value is entered; all independent values must be distinct.`,`   `,
`REFERENCE: "Reliable Rational Interpolation", Numerische Mathematik 36,`,
`  111-128 (1981).`,`   `,`EXAMPLES:   `,`> ratinterp([1,2,3],[1,2,3],z);`,
`   `,`                                       z`,`   `,
`> ratinterp([0,1,2,3,4],[1,1/2,1/3,1/4,1/5],z);`,`   `,
`                                       1`,
`                                     -----`,
`                                     1 + z`,`   `,
`> ratinterp([1,2,6],[3,4,5],a);`,`   `,
`                                   - 2 + 17 a `,
`                                   ----------`,
`                                     2 + 3 a`,`   `,`      `,
`SEE ALSO:  interp`,`   `):

#save `rfinterp.m`;
#quit
