MODULE VECPOLY;

% Authors: A. C. Norman and P. M. A. Moore, 1979;

FLUID '(CURRENT!-MODULUS SAFE!-FLAG);


%**********************************************************************;
% Routines for working with modular univariate polynomials
% stored as vectors. Used to avoid unwarranted storage management
% in the mod-p factorization process;


SAFE!-FLAG:=CARCHECK 0;


SYMBOLIC PROCEDURE COPY!-VECTOR(A,DA,B);
% Copy A into B;
 << FOR I:=0:DA DO
      PUTV(B,I,GETV(A,I));
    DA >>;

SYMBOLIC PROCEDURE TIMES!-IN!-VECTOR(A,DA,B,DB,C);
% Put the product of A and B into C and return its degree.
% C must not overlap with either A or B;
  BEGIN
    SCALAR DC,IC,W;
    IF DA#<0 OR DB#<0 THEN RETURN MINUS!-ONE;
    DC:=DA#+DB;
    FOR I:=0:DC DO PUTV(C,I,0);
    FOR IA:=0:DA DO <<
      W:=GETV(A,IA);
      FOR IB:=0:DB DO <<
        IC:=IA#+IB;
        PUTV(C,IC,MODULAR!-PLUS(GETV(C,IC),
          MODULAR!-TIMES(W,GETV(B,IB)))) >> >>;
    RETURN DC
  END;


SYMBOLIC PROCEDURE QUOTFAIL!-IN!-VECTOR(A,DA,B,DB);
% Overwrite A with (A/B) and return degree of result.
% The quotient must be exact;
    IF DA#<0 THEN DA
    ELSE IF DB#<0 THEN ERRORF "Attempt to divide by zero"
    ELSE IF DA#<DB THEN ERRORF "Bad degrees in QUOTFAIL-IN-VECTOR"
    ELSE BEGIN
      SCALAR DC;
      DC:=DA#-DB; % Degree of result;
      FOR I:=DC STEP -1 UNTIL 0 DO BEGIN
        SCALAR Q;
        Q:=MODULAR!-QUOTIENT(GETV(A,DB#+I),GETV(B,DB));
        FOR J:=0:DB#-1 DO
          PUTV(A,I#+J,MODULAR!-DIFFERENCE(GETV(A,I#+J),
            MODULAR!-TIMES(Q,GETV(B,J))));
        PUTV(A,DB#+I,Q)
      END;
      FOR I:=0:DB#-1 DO IF GETV(A,I) NEQ 0 THEN
        ERRORF "Quotient not exact in QUOTFAIL!-IN!-VECTOR";
      FOR I:=0:DC DO
        PUTV(A,I,GETV(A,DB#+I));
      RETURN DC
    END;


SYMBOLIC PROCEDURE REMAINDER!-IN!-VECTOR(A,DA,B,DB);
% Overwrite the vector A with the remainder when A is
% divided by B, and return the degree of the result;
  BEGIN
    SCALAR DELTA,DB!-1,RECIP!-LC!-B,W;
    IF DB=0 THEN RETURN MINUS!-ONE
    ELSE IF DB=MINUS!-ONE THEN ERRORF "ATTEMPT TO DIVIDE BY ZERO";
    RECIP!-LC!-B:=MODULAR!-MINUS MODULAR!-RECIPROCAL GETV(B,DB);
    DB!-1:=DB#-1; % Leading coeff of B treated specially, hence this;
    WHILE NOT((DELTA:=DA#-DB) #< 0) DO <<
      W:=MODULAR!-TIMES(RECIP!-LC!-B,GETV(A,DA));
      FOR I:=0:DB!-1 DO
        PUTV(A,I#+DELTA,MODULAR!-PLUS(GETV(A,I#+DELTA),
          MODULAR!-TIMES(GETV(B,I),W)));
      DA:=DA#-1;
      WHILE NOT(DA#<0) AND GETV(A,DA)=0 DO DA:=DA#-1 >>;
    RETURN DA
  END;

SYMBOLIC PROCEDURE EVALUATE!-IN!-VECTOR(A,DA,N);
% Evaluate A at N;
  BEGIN
    SCALAR R;
    R:=GETV(A,DA);
    FOR I:=DA#-1 STEP -1 UNTIL 0 DO
      R:=MODULAR!-PLUS(GETV(A,I),
        MODULAR!-TIMES(R,N));
    RETURN R
  END;

SYMBOLIC PROCEDURE GCD!-IN!-VECTOR(A,DA,B,DB);
% Overwrite A with the gcd of A and B. On input A and B are
% vectors of coefficients, representing polynomials
% of degrees DA and DB. Return DG, the degree of the gcd;
  BEGIN
    SCALAR W;
    IF DA=0 OR DB=0 THEN << PUTV(A,0,1); RETURN 0 >>
    ELSE IF DA#<0 OR DB#<0 THEN ERRORF "GCD WITH ZERO NOT ALLOWED";
TOP:
% Reduce the degree of A;
    DA:=REMAINDER!-IN!-VECTOR(A,DA,B,DB);
    IF DA=0 THEN << PUTV(A,0,1); RETURN 0 >>
    ELSE IF DA=MINUS!-ONE THEN <<
      W:=MODULAR!-RECIPROCAL GETV(B,DB);
      FOR I:=0:DB DO PUTV(A,I,MODULAR!-TIMES(GETV(B,I),W));
      RETURN DB >>;
% Now reduce degree of B;
    DB:=REMAINDER!-IN!-VECTOR(B,DB,A,DA);
    IF DB=0 THEN << PUTV(A,0,1); RETURN 0 >>
    ELSE IF DB=MINUS!-ONE THEN <<
      W:=MODULAR!-RECIPROCAL GETV(A,DA);
      IF NOT (W=1) THEN
        FOR I:=0:DA DO PUTV(A,I,MODULAR!-TIMES(GETV(A,I),W));
      RETURN DA >>;
    GO TO TOP
  END;



CARCHECK SAFE!-FLAG;


ENDMODULE;


END;
