(* ----------------------------------------------------------------------------
 * $Id: DIPRF.mi,v 1.4 1994/11/28 21:19:07 dolzmann Exp $
 * ----------------------------------------------------------------------------
 * This file is part of MAS.
 * ----------------------------------------------------------------------------
 * Copyright (c) 1989 - 1992 Universitaet Passau
 * ----------------------------------------------------------------------------
 * $Log: DIPRF.mi,v $
 * Revision 1.4  1994/11/28  21:19:07  dolzmann
 * Bug fix in RFSUM.
 *
 * Revision 1.3  1992/10/15  16:29:38  kredel
 * Changed rcsid variable
 *
 * Revision 1.2  1992/02/12  17:34:22  pesch
 * Moved CONST definition to the right place
 *
 * Revision 1.1  1992/01/22  15:14:58  kredel
 * Initial revision
 *
 * ----------------------------------------------------------------------------
 *)

IMPLEMENTATION MODULE DIPRF;

(* DIP Rational Function Implementation Module. *)



(* Import lists and declarations. *)

FROM MASSTOR IMPORT LIST, SIL, BETA, FIRST, ADV, RED, COMP,
                    LENGTH, LIST1, SRED, SFIRST, INV;

FROM MASERR IMPORT severe, ERROR;

FROM MASBIOS IMPORT BLINES, SWRITE, CWRITE, CREAD, CREADB,
                    BKSP, MASORD, LETTER, DIGIT;

FROM SACLIST IMPORT EQUAL, SECOND, FIRST2, CINV, 
                    COMP2, FIRST3, LIST3, LIST2, ADV2, AWRITE;

FROM SACI IMPORT IREAD, IWRITE;

FROM SACPOL IMPORT PINV, VREAD, VLSRCH, VLWRIT;

FROM SACIPOL IMPORT IPSUM, IPQ, IPPROD, IPONE, IPSIGN, IPNEG;

FROM DIPC IMPORT PMPV, DIPFP, PFDIP, EPREAD;

FROM DIPI IMPORT DIIPSG, DIIPNG, DIIPWR, DIIPRD; 

FROM SACPGCD IMPORT IPGCDC;

CONST rcsidi = "$Id: DIPRF.mi,v 1.4 1994/11/28 21:19:07 dolzmann Exp $";
CONST copyrighti = "Copyright (c) 1989 - 1992 Universitaet Passau";



PROCEDURE IFWRIT(R,V: LIST); 
(*Integral function write. R is an integral function.  
R is the variable list. R is written in the output stream. *)
VAR  AL, RL, RP: LIST; 
BEGIN
(*1*) (*advance. *) FIRST2(R, RL,AL); 
      IF AL = 0 THEN AWRITE(AL); RETURN; END; 
(*2*) (*r non zero. *) AL:=DIPFP(RL,AL); 
      IF DIIPSG(AL) < 0 THEN SWRITE("-"); AL:=DIIPNG(AL); END; 
      DIIPWR(AL,V); 
(*5*) RETURN; END IFWRIT; 


PROCEDURE RFDEN(R: LIST): LIST; 
(*Rational function denominator.  R is a rational function.
BL is the denominator of R, a positive integral polynomial
in RL variables. *)
VAR  AL, BL, I, RL, RP: LIST; 
BEGIN
(*1*) (*advance. *) ADV2(R, RL,AL,RP); 
      IF AL <> 0 THEN BL:=FIRST(RP); RETURN(BL); END; 
      BL:=1; 
      FOR I:=1 TO RL DO BL:=LIST2(0,BL); END; 
(*4*) RETURN(BL); END RFDEN; 


PROCEDURE RFDIF(R,S: LIST): LIST; 
(*Rational function difference.  R and S are rational functions.
T=R-S. *)
VAR  SP, T: LIST; 
BEGIN
(*1*) (*negate and sum. *) SP:=RFNEG(S); T:=RFSUM(R,SP); 
(*4*) RETURN(T); END RFDIF; 


PROCEDURE RFEXP(A,NL: LIST): LIST; 
(*Rational function exponentiation.  A is a rational function,
n is a non-negative beta-integer.  B=A**n. *)
VAR  B, I, KL, RL: LIST; 
BEGIN
(*1*) (*nl less than or equal to 1. *) 
      IF NL = 0 THEN RL:=RFNOV(A); B:=1; 
         FOR I:=1 TO RL DO B:=LIST2(0,B); END; 
         B:=RFFIP(RL,B); RETURN(B); END; 
      IF NL = 1 THEN B:=A; RETURN(B); END; 
(*2*) (*recursion. *) KL:=NL DIV 2; B:=RFEXP(A,KL); B:=RFPROD(B,B); 
      IF NL > 2*KL THEN B:=RFPROD(B,A); END; 
(*5*) RETURN(B); END RFEXP; 


PROCEDURE RFFIP(RL,A: LIST): LIST; 
(*Rational function from integral polynomial. A is an integral
polynomial in RL variables. R is the rational function A/1. *)
VAR  B, R: LIST; 
BEGIN
(*1*) (*a zero. *) 
      IF A = 0 THEN R:=LIST2(RL,A); RETURN(R); END; 
      B:=PINV(0,1,RL); R:=LIST3(RL,A,B); 
(*4*) RETURN(R); END RFFIP; 


PROCEDURE RFINV(R: LIST): LIST; 
(*Rational function inverse. R is a non-zero rational
function. S=1/R. *)
VAR  R1, R2, RL, RP, S, S1, S2: LIST; 
BEGIN
(*1*) (*advance. *) FIRST3(R, RL,R1,R2); 
      IF IPSIGN(RL,R1) > 0 THEN S1:=R2; S2:=R1; ELSE
         S1:=IPNEG(RL,R2); S2:=IPNEG(RL,R1); END; 
      S:=LIST3(RL,S1,S2); 
(*4*) RETURN(S); END RFINV; 


PROCEDURE RFNEG(R: LIST): LIST; 
(*Rational function negative. R is a rational function. S=-R. *)
VAR  R1, RL, RP, RP1, S: LIST; 
BEGIN
(*1*) (*advance. *) ADV2(R, RL,R1,RP); 
      IF R1 = 0 THEN S:=R; ELSE RP1:=IPNEG(RL,R1); 
         S:=COMP2(RL,RP1,RP); END; 
(*4*) RETURN(S); END RFNEG; 


PROCEDURE RFNOV(R: LIST): LIST; 
(*Rational function number of variables. R is a rational
function. RL is the number of variables of the numerator
and denumerator of R. *)
VAR  RL: LIST; 
BEGIN
(*1*) (*advance. *) RL:=FIRST(R); 
(*4*) RETURN(RL); END RFNOV; 


PROCEDURE RFNUM(R: LIST): LIST; 
(*Rational function numerator.  R is a rational function.
AL is the numerator of R, an integral polynomial. *)
VAR  AL: LIST; 
BEGIN
(*1*) (*advance. *) AL:=SECOND(R); 
(*4*) RETURN(AL); END RFNUM; 


PROCEDURE RFONE(R: LIST): LIST; 
(*Rational function one.  R is a rational function.  s=1 if R=1,
s=0 else. *)
VAR  A, B, RL, RP, SL: LIST; 
BEGIN
(*1*) (*denominator=numerator. *) ADV2(R, RL,A,RP); SL:=0; 
      IF A = 0 THEN RETURN(SL); END; 
      B:=FIRST(RP); SL:=EQUAL(A,B); 
(*4*) RETURN(SL); END RFONE; 


PROCEDURE RFPROD(R,S: LIST): LIST; 
(*Rational function product.  R and S are rational functions.
T=R*S. *)
VAR  AL, BL, D1, D2, R1, R2, RB1, RB2, RL, RP, S1, S2, SB1, SB2, SP, T,
     T1, T2: LIST; 
BEGIN
(*1*) (*r=0 or s=0. *) ADV2(R, RL,R1,RP); ADV2(S, RL,S1,SP); 
      IF (R1 = 0) OR (S1 = 0) THEN T:=LIST2(RL,0); RETURN(T); 
         END; 
(*2*) (*obtain numerators and denominators. *) R2:=FIRST(RP); 
      S2:=FIRST(SP); AL:=IPONE(RL,R2); BL:=IPONE(RL,S2); 
(*3*) (*r and s integers. *) 
      IF (AL = 1) AND (BL = 1) THEN T1:=IPPROD(RL,R1,S1); 
         T:=LIST3(RL,T1,R2); RETURN(T); END; 
(*4*) (*r or s an integer. *) 
      IF AL = 1 THEN IPGCDC(RL,R1,S2, D1,RB1,SB2); 
         T1:=IPPROD(RL,RB1,S1); T:=LIST3(RL,T1,SB2); RETURN(T); END; 
      IF BL = 1 THEN IPGCDC(RL,S1,R2, D2,SB1,RB2); 
         T1:=IPPROD(RL,SB1,R1); T:=LIST3(RL,T1,RB2); RETURN(T); END; 
(*5*) (*general case. *) IPGCDC(RL,R1,S2, D1,RB1,SB2); IPGCDC(RL,S1,R2,
      D2,SB1,RB2); T1:=IPPROD(RL,RB1,SB1); T2:=IPPROD(RL,RB2,SB2); 
      T:=LIST3(RL,T1,T2); 
(*8*) RETURN(T); END RFPROD; 


PROCEDURE RFQ(R,S: LIST): LIST; 
(*Rational function quotient. R and S are rational functions,
S non-zero. T=R/S. *)
VAR  AL, SP, T: LIST; 
BEGIN
(*1*) (*r zero. *) AL:=RFNUM(R); 
      IF AL = 0 THEN T:=R; ELSE SP:=RFINV(S); T:=RFPROD(R,SP); END; 
(*4*) RETURN(T); END RFQ; 


PROCEDURE RFREAD(V: LIST): LIST; 
(*Rational function read. The rational function R is read
from the input stream. V is the variable list. any preceding
blanks are skipped. *)
VAR  C, EL, JL, R, R1, R2, RL, RLS, VL: LIST; 
BEGIN
LOOP
(*1*) (*read nominator. *) R:=LIST2(0,0); RL:=LENGTH(V); C:=CREADB(); 
      IF C = MASORD("/") THEN R1:=PINV(0,1,RL); 
         EXIT (*GO TO 2;*) END; 
      BKSP; 
      IF C = MASORD("(") THEN R1:=DIIPRD(V); PFDIP(R1, RLS,R1); 
         EXIT (*GO TO 2;*) END; 
      IF DIGIT(C) THEN R1:=IREAD(); R1:=PINV(0,R1,RL); 
         EXIT (*GO TO 2;*) END; 
      IF LETTER(C) THEN VL:=VREAD(); JL:=VLSRCH(VL,V); R1:=PINV(0,1,RL); 
         IF JL = 0 THEN R:=RFFIP(RL,R1); RETURN(R); END; 
         EL:=EPREAD(); R1:=PMPV(RL,R1,JL,EL); 
         EXIT (*GO TO 2;*) END; 
      (*GO TO 4;*) 
      ERROR(severe,"error found in RFREAD. "); RETURN(R); 
      END;
LOOP
(*2*) (*read denominator. *) C:=CREADB(); 
      IF C <> MASORD("/") THEN BKSP; R2:=PINV(0,1,RL); 
         EXIT (*GO TO 3;*) END; 
      C:=CREADB(); BKSP; 
      IF C = MASORD("(") THEN R2:=DIIPRD(V); PFDIP(R2, RLS,R2); 
         EXIT (*GO TO 3;*) END; 
      IF DIGIT(C) THEN R2:=IREAD(); R2:=PINV(0,R2,RL); 
         EXIT (*GO TO 3;*) END; 
      IF LETTER(C) THEN VL:=VREAD(); JL:=VLSRCH(VL,V); 
         IF JL <> 0 THEN  
            R2:=PINV(0,1,RL); EL:=EPREAD(); R2:=PMPV(RL,R2,JL,EL); 
            EXIT (*GO TO 3;*) END;
         END; 
      (*GO TO 4;*) 
      ERROR(severe,"error found in RFREAD. "); RETURN(R); 
      END;

(*3*) (*reduction to lowest terms. *) R:=RFRED(RL,R1,R2); RETURN(R); 

(*4*) (*error. *) ERROR(severe,"error found in RFREAD. ");  
(*7*) END RFREAD; 


PROCEDURE RFRED(RL,A,B: LIST): LIST; 
(*Rational function reduction to lowest terms.  A and B are
integral polynomials in RL variables, B non-zero. R is the
rational function A/B in canonical form. *)
VAR  AP, BP, C, R, SL: LIST; 
BEGIN
(*1*) (*a zero. *) 
      IF A = 0 THEN R:=LIST2(RL,0); RETURN(R); END; 
(*2*) (*greatest common divisor. *) IPGCDC(RL,A,B, C,AP,BP); 
      SL:=IPSIGN(RL,BP); 
      IF SL < 0 THEN AP:=IPNEG(RL,AP); BP:=IPNEG(RL,BP); END; 
      R:=LIST3(RL,AP,BP); 
(*5*) RETURN(R); END RFRED; 


PROCEDURE RFSIGN(R: LIST): LIST; 
(*Rational function sign.  R is a rational function.  s=sign(R). *)
VAR  A, RL, SL: LIST; 
BEGIN
(*1*) (*sign of numerator. *) FIRST2(R, RL,A); SL:=IPSIGN(RL,A); 
(*4*) RETURN(SL); END RFSIGN; 


PROCEDURE RFSUM(R,S: LIST): LIST; 
(*Rational function sum.  R and S are rational functions.  T=R+S. *)
VAR  AL, BL, D, DP, E, R1, R2, RB2, RL, RP, S1, S2, SB2, SP, T, T1,
     T2: LIST; 
BEGIN
(*1*) (*r=0 or s=0. *) ADV2(R, RL,R1,RP); ADV2(S, RL,S1,SP); 
      IF R1 = 0 THEN T:=S; RETURN(T); END; 
      IF S1 = 0 THEN T:=R; RETURN(T); END; 
(*2*) (*obtain numerators and denominators. *) R2:=FIRST(RP); 
      S2:=FIRST(SP); AL:=IPONE(RL,R2); BL:=IPONE(RL,S2); 
(*3*) (*r and s integers. *) 
      IF (AL = 1) AND (BL = 1) THEN T1:=IPSUM(RL,R1,S1); 
(* ADo *) IF T1=0 THEN RETURN LIST2(RL,T1); END; (* oDA *)      
         T:=LIST3(RL,T1,R2); RETURN(T); END; 
(*4*) (*r or s an integer. *) 
      IF AL = 1 THEN T1:=IPPROD(RL,R1,S2); T1:=IPSUM(RL,T1,S1); 
         T:=LIST3(RL,T1,S2); RETURN(T); END; 
      IF BL = 1 THEN T1:=IPPROD(RL,R2,S1); T1:=IPSUM(RL,T1,R1); 
         T:=LIST3(RL,T1,R2); RETURN(T); END; 
(*5*) (*general case. *) IPGCDC(RL,R2,S2, D,RB2,SB2); 
      T1:=IPPROD(RL,R1,SB2); T2:=IPPROD(RL,RB2,S1); T1:=IPSUM(RL,T1,T2); 
      IF T1 = 0 THEN T:=LIST2(RL,0); RETURN(T); END; 
      IF IPONE(RL,D) <> 1 THEN IPGCDC(RL,T1,D, E,T1,DP); 
         IF IPONE(RL,E) <> 1 THEN R2:=IPQ(RL,R2,E); END; 
         END; 
      T2:=IPPROD(RL,R2,SB2); T:=LIST3(RL,T1,T2); 
(*8*) RETURN(T); END RFSUM; 


PROCEDURE RFWRIT(R,V: LIST); 
(*Rational function write. R is a rational function.  V is the 
variable list. R is written in the output stream. *)
VAR  AL, BL, RL, RP: LIST; 
BEGIN
(*1*) (*advance. *) ADV2(R, RL,AL,RP); 
      IF AL = 0 THEN AWRITE(AL); RETURN; END; 
(*2*) (*r non zero. *) AL:=DIPFP(RL,AL); 
      IF DIIPSG(AL) < 0 THEN SWRITE("-"); AL:=DIIPNG(AL); END; 
      DIIPWR(AL,V); BL:=FIRST(RP); 
      IF IPONE(RL,BL) <> 1 THEN SWRITE("/"); BL:=DIPFP(RL,BL); 
         DIIPWR(BL,V); END; 
(*5*) RETURN; END RFWRIT; 


END DIPRF.
(* -EOF- *)