(* ----------------------------------------------------------------------------
 * $Id: GSYMFUIN.mi,v 1.1 1995/11/05 15:57:27 pesch Exp $
 * ----------------------------------------------------------------------------
 * This file is part of MAS.
 * ----------------------------------------------------------------------------
 * Copyright (c) 1995 Universitaet Passau
 * ----------------------------------------------------------------------------
 * $Log: GSYMFUIN.mi,v $
 * Revision 1.1  1995/11/05 15:57:27  pesch
 * Diplomarbeit Manfred Goebel, Reduktion G-symmetrischer Polynome fuer
 * beliebige Permutationsgruppen G, slightly edited.
 *
 * ----------------------------------------------------------------------------
 *)

IMPLEMENTATION MODULE GSYMFUIN;
(* G-Symmetric Integral Polynomial System Implementation Module. *)

FROM MASELEM	IMPORT	GAMMAINT;

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

FROM MASBIOS	IMPORT	BLINES, SWRITE;

FROM SACLIST	IMPORT	CINV, EQUAL, LEINST, LELT, LREAD, MEMBER, OWRITE,
			SLELT;

FROM SACSET	IMPORT	LBIBS;

FROM SACLDIO	IMPORT	LDSMKB;

FROM DIPI	IMPORT	DIIPDF, DIIPEX, DIIPIP, DIIPPR, DIIPSM;

FROM DIPC	IMPORT	DIPFMO, DIPMAD, EVCOMP, EVDEL, EVDIF, EVILCI, EVSIGN;

CONST rcsidi = "$Id: GSYMFUIN.mi,v 1.1 1995/11/05 15:57:27 pesch Exp $";
CONST copyrighti = "Copyright (c) 1995 Universitaet Passau";

PROCEDURE GSYINF();
BEGIN
BLINES(1);
SWRITE("G-Symmetric Polynomial System Package:");
BLINES(0);
SWRITE("--------------------------------------");
BLINES(1);
SWRITE("              PG := GSYPGR(Number_of_Variables).");
BLINES(0);
SWRITE("    Symmetric_PG := GSYSPG(Number_of_Variables).");
BLINES(0);
SWRITE("           Order := GSYORD(PG).");
BLINES(0);
SWRITE("GSYNSP(PG).");
BLINES(0);
SWRITE("GSYPGW(PG).");
BLINES(0);
SWRITE("GSYINF().");
BLINES(1);
SWRITE("           Orbit := GINORP(PG, Monom).");
BLINES(0);
SWRITE("      Orbit_List := GINOPL(PG, Monom_List).");
BLINES(0);
SWRITE("         Polynom := GINCHK(PG, Base, Base_Polynom).");
BLINES(0);
SWRITE("        Base_HTL := GINBAS(PG).");
BLINES(0);
SWRITE("GINCUT(PG, Polynom, PG_Symmetric_Polynom, Remainder_Polynom).");
BLINES(0);
SWRITE("GINRED(PG, Polynom, Base, Base_Polynom, Remainder_Polynom).");
BLINES(1);
SWRITE("           Orbit := GRNORP(PG, Monom).");
BLINES(0);
SWRITE("      Orbit_List := GRNOPL(PG, Monom_List).");
BLINES(0);
SWRITE("         Polynom := GRNCHK(PG, Base, Base_Polynom).");
BLINES(0);
SWRITE("        Base_HTL := GRNBAS(PG).");
BLINES(0);
SWRITE("        Base_HTL := GRNGGB(PG).");
BLINES(0);
SWRITE("GRNCUT(PG, Polynom, PG_Symmetric_Polynom, Remainder_Polynom).");
BLINES(0);
SWRITE("GRNRED(PG, Polynom, Base, Base_Polynom, Remainder_Polynom).");
BLINES(1);
END GSYINF;

PROCEDURE GSYPGR(N: GAMMAINT): LIST;
VAR PG, X: LIST;
    I: GAMMAINT;
BEGIN
PG := SIL;
IF N < 1 THEN RETURN(PG); END;
X := LREAD();
WHILE X # SIL DO
    IF LENGTH(X) # N THEN SWRITE("Length error, try again! ");
    ELSE I := 1;
         LOOP IF I > N THEN EXIT; END;
              IF MEMBER(I, X) = 0 THEN EXIT; END;
              I := I + 1;
              END; (* of loop *)
         IF I > N THEN PG := COMP(X, PG);
         ELSE SWRITE("No permutation, try again! "); END;
         END; (* of if *)
    X:= LREAD();
    END; (* of while *)
RETURN(PG);
END GSYPGR;

PROCEDURE GSYPGW(PG: LIST);
VAR F1, F2: LIST;
    N, I: GAMMAINT;
BEGIN
IF PG = SIL THEN BLINES(0); SWRITE("()"); RETURN; END;
N := LENGTH(FIRST(PG));
IF N < 1 THEN RETURN; END;
F1 := SIL;
FOR I := N TO 1 BY -1 DO F1 := COMP(I, F1); END;
WHILE PG # SIL DO
    ADV(PG, F2, PG);
    BLINES(0);
    OWRITE(F1); SWRITE(" --> "); OWRITE(F2);
    END; (* of while *)
END GSYPGW;

PROCEDURE GINORP(PG, MO: LIST): LIST;
VAR HK, HT, HTL, TERM, RES, NRES, NPG, XX, DUMMY: LIST;
    I, N, L, NL: GAMMAINT;
BEGIN
RES := 0;
L := 0;
IF PG = SIL THEN RETURN(RES); END;
N := LENGTH(FIRST(PG));
IF MO = 0 THEN RETURN(RES); END;
IF LENGTH(MO) # 2 THEN RETURN(-1); END;
IF LENGTH(FIRST(MO)) # N THEN RETURN(-1); END;
DIPMAD(MO, HK, HT, DUMMY);
HTL := SIL;
HTL := COMP(HT, HTL);
WHILE HTL # SIL DO
    ADV(HTL, HT, HTL);
    NPG := PG;
    WHILE NPG # SIL DO
         ADV(NPG, XX, NPG);
         TERM := INV(CINV(HT));
         FOR I := 1 TO N DO
              SLELT(TERM, N+1-LELT(XX, I), LELT(HT, N+1-I));
              END; (* of for *)
         NRES := DIIPSM(RES, DIPFMO(HK, TERM));
         IF NRES # 0 THEN NL := LENGTH(NRES); ELSE NL := 0; END;
         IF NL > L THEN
              RES := NRES;
              L := NL;
              HTL := COMP(TERM, HTL);
              END; (* of if *)
         END; (* of while *)
    END; (* of while *)
RETURN(RES);
END GINORP;

PROCEDURE GSYORD(PG: LIST): GAMMAINT;
VAR HK, HT, POL: LIST;
    ORDER, I, N: GAMMAINT;
BEGIN
ORDER := 0;
IF PG = SIL THEN RETURN(ORDER); END;
N := LENGTH(FIRST(PG));
HT := SIL;
FOR I := 0 TO N-1 DO HT := COMP(I, HT); END;
POL := GINORP(PG, DIPFMO(1, HT));
IF POL = 0 THEN POL := SIL; END;
WHILE POL # SIL DO
    DIPMAD(POL, HK, HT, POL);
    ORDER := ORDER + 1;
    END; (* of while *)
RETURN(ORDER);
END GSYORD;

PROCEDURE GSYNSP(PG: LIST);
VAR SPG, ORBIT_SPG, ORBIT_PG, TERM: LIST;
    I, N, MAX, NR: GAMMAINT;
BEGIN
NR := 0;
IF PG = SIL THEN RETURN; END;
N := LENGTH(FIRST(PG));
SPG := GSYSPG(N);
IF N <= 2 THEN MAX := 1; END;
IF N > 2 THEN  MAX := N - 1; END;
TERM := SIL;
FOR I := 1 TO N DO TERM := COMP(0, TERM); END;

LOOP TERM := GSYADD(TERM);
    IF FIRST(TERM) > MAX THEN EXIT; END; (* of if *)
    ORBIT_SPG := GINORP(SPG, DIPFMO(1, TERM));
    WHILE ORBIT_SPG # 0 DO
         NR := NR + 1;
         ORBIT_PG := GINORP(PG, DIPFMO(1, FIRST(ORBIT_SPG)));
         ORBIT_SPG := DIIPDF(ORBIT_SPG, ORBIT_PG);
         END; (* of while *);
    END; (* of loop *)
BLINES(0); SWRITE("There are "); OWRITE(NR); SWRITE(" special polynomial(s).");
END GSYNSP;

PROCEDURE GSYSPG(N: GAMMAINT): LIST;
VAR PG, PERM: LIST;
    I, K: GAMMAINT;
BEGIN
PG := SIL;
IF N < 1 THEN RETURN(SIL); END;
FOR I := 1 TO N DO
    PERM := SIL;
    FOR K := 1 TO N DO PERM := LEINST(PERM, K-1, K); END;
    K := I + 1;
    IF K > N THEN K := 1; END;
    SLELT(PERM, K, I);
    SLELT(PERM, I, K);
    PG := LEINST(PG, I-1, PERM);
    END; (* of for *)
RETURN(PG);
END GSYSPG;

PROCEDURE GINOPL(PG, ML: LIST): LIST;
VAR HM, RES: LIST;
BEGIN
RES := SIL;
WHILE ML # SIL DO
    ADV(ML, HM, ML);
    RES := COMP(GINORP(PG, HM), RES);
    END; (* of while *)
RETURN(INV(RES));
END GINOPL;

PROCEDURE GINCUT(PG, POL: LIST; VAR POL1, POL2: LIST);
VAR ORBIT, HM, HT, HK, DUMMY: LIST;
BEGIN
POL1 := 0;
POL2 := 0;
WHILE POL # 0 DO
    DIPMAD(POL, HK, HT, DUMMY);
    HM := DIPFMO(HK, HT);
    ORBIT := GINORP(PG, HM);
    IF EQUAL(HT, FIRST(ORBIT)) = 1 THEN
         POL1 := DIIPSM(POL1, ORBIT);
         POL := DIIPDF(POL, ORBIT);
    ELSE POL2 := DIIPSM(POL2, HM);
         POL := DIIPDF(POL, HM);
         END; (* of if *)
    END; (* of while *)
END GINCUT;

PROCEDURE GINCHK(PG, BASE, POL: LIST): LIST;
VAR RES, HK, HT, BASE_ORBIT, PROD: LIST;
    I, N: GAMMAINT;
BEGIN
RES := 0;
IF POL = 0 THEN RETURN(RES); END;
N := LENGTH(BASE);
IF N = 0 THEN RETURN(RES); END;
BASE_ORBIT := GINOPL(PG, BASE);
WHILE POL # 0 DO
    DIPMAD(POL, HK, HT, POL);
    IF POL = SIL THEN POL := 0; END;
    PROD := DIIPEX(LELT(BASE_ORBIT, 1), 0);
    FOR I := 1 TO N DO
         PROD := DIIPPR(PROD, DIIPEX(LELT(BASE_ORBIT, I), LELT(HT, I)));
         END; (* of for *)
    RES := DIIPSM(RES, DIIPIP(PROD, HK));
    END; (* of while *)
RETURN(RES);
END GINCHK;

PROCEDURE GINCHKBAS(VAR BASE, POL: LIST);
VAR NBASE, NPOL, HT, HK, POS, DUMMY: LIST;
    I, J, N1, N2: GAMMAINT;
BEGIN
IF POL = 0 THEN BASE := SIL; END;
IF BASE = SIL THEN RETURN; END;
N1 := LENGTH(BASE);
NBASE := BASE;
BASE := SIL;
FOR I := 1 TO N1 DO
    NPOL := POL;
    LOOP IF NPOL = SIL THEN EXIT; END;
         DIPMAD(NPOL, HK, HT, NPOL);
         IF LELT(HT, I) # 0 THEN
              BASE := COMP(LELT(NBASE, I), BASE);
              EXIT; END; (* of if *)
         END; (* of loop *)
    END; (* of for *)
BASE := INV(BASE);
N2 := LENGTH(BASE);
IF N1 = N2 THEN RETURN; END; (* nothing has changed *)

NPOL := POL;
POL := 0;
J := 1;
POS := SIL;
FOR I := 1 TO N1 DO
    IF (J<=N2) AND (EQUAL(LELT(NBASE, I), LELT(BASE, J)) = 1) THEN J := J + 1;
    ELSE POS := COMP(I, POS); END; (* of if *)
    END; (* of for *)
WHILE NPOL # SIL DO
    DIPMAD(NPOL, HK, HT, NPOL);
    FOR I := 1 TO LENGTH(POS) DO
         EVDEL(HT, LELT(POS, I), HT, DUMMY);
         END; (* of for *)
    POL := DIIPSM(POL, DIPFMO(HK, HT));
    END; (* of while *)
END GINCHKBAS;

PROCEDURE GSYMLT(N: GAMMAINT): LIST;
VAR TL, SIGMA, SPG, ORBIT, HK, HT: LIST;
    I, J: GAMMAINT;
BEGIN
TL := SIL;
IF N = 0 THEN RETURN(SIL); END;
SPG := GSYSPG(N);
FOR I := 1 TO N DO
    SIGMA := SIL;
    FOR J := 1 TO I DO SIGMA := COMP(1, SIGMA); END;
    FOR J := I+1 TO N DO SIGMA := COMP(0, SIGMA); END;
    ORBIT := GINORP(SPG, DIPFMO(1, SIGMA));
    WHILE ORBIT # SIL DO
         DIPMAD(ORBIT, HK, HT, ORBIT);
         TL := COMP(HT, TL);
         END; (* of while *)
    END; (* of for *)
RETURN(INV(TL));
END GSYMLT;

PROCEDURE GSYTWG(TERM1, TERM2: LIST): GAMMAINT;
VAR S_TERM1, S_TERM2: LIST;
    SIGN: GAMMAINT;
BEGIN (*  1, if wg(TERM1)>wg(TERM2) or (wg(TERM1)=wg(TERM2) and TERM1>TERM2) *)
      (*  0, if wg(TERM1) = wg(TERM2) and TERM1 = TERM2                      *)
      (* -1, otherwise                                                       *)
S_TERM1 := CINV(TERM1);
S_TERM2 := CINV(TERM2);
LBIBS(S_TERM1);
LBIBS(S_TERM2);
SIGN := EVILCI(S_TERM1, S_TERM2);
IF SIGN = 1 THEN RETURN(1); END;
IF SIGN = 0 THEN RETURN(EVCOMP(TERM1, TERM2)); END;
RETURN(-1);
END GSYTWG;

PROCEDURE EXTRACT(PG, POL_1, POL_2, POL_3: LIST; VAR BASE, POL: LIST);
VAR NPOL, TERM, TERM1, HT, HK, HM, ORBIT, DUMMY: LIST;
    POS, I, N, SIGN: GAMMAINT;
BEGIN
BASE := SIL;
POL := SIL;
IF (POL_1 # 0) AND (POL_2 # 0) THEN
    TERM := FIRST(POL_1);
    TERM1 := FIRST(POL_2);
    SIGN := GSYTWG(TERM, TERM1);
    IF SIGN = 0 THEN
         POL := DIPFMO(1, LIST1(2));
         BASE := LIST1(DIPFMO(1, TERM));
    ELSE
         SIGN := SIGN + 1;
         IF SIGN = 2 THEN SIGN := 1; END;
         POL := DIPFMO(1, COMP(1, LIST1(1)));
         BASE := LEINST(LIST1(DIPFMO(1, TERM)),SIGN,DIPFMO(1,TERM1));
         END; (* of if *)
    END; (* of if *)

WHILE POL_3 # 0 DO
    DIPMAD(POL_3, HK, HT, DUMMY);
    HM := DIPFMO(HK, HT);
    ORBIT := GINORP(PG, HM);
    POL_3 := DIIPDF(POL_3, ORBIT);
    IF BASE = SIL THEN
         POL := DIPFMO(HK, LIST1(1));
         BASE := LIST1(DIPFMO(1, HT));
    ELSE
         N := LENGTH(BASE);
         POS := 0;
         LOOP POS := POS + 1;
              IF POS > N THEN EXIT; END;
              HM := LELT(BASE, POS);
              IF GSYTWG(FIRST(HM), HT) <= 0 THEN EXIT; END;
              END; (* of loop *)
         POS := POS - 1;
         BASE := LEINST(BASE, POS, DIPFMO(1, HT));
         NPOL := POL;
         HT := SIL;
         FOR I := 1 TO N DO HT := COMP(0, HT); END; (* of for *)
         HT := LEINST(HT, POS, 1);
         POL := DIPFMO(HK, HT);
         WHILE NPOL # SIL DO
              DIPMAD(NPOL, HK, HT, NPOL);
              HT := LEINST(HT, POS, 0);
              POL := DIIPSM(DIPFMO(HK, HT), POL);
              END; (* of while *)
         END; (* of if *)
    END; (* of while *)
END EXTRACT;

PROCEDURE MERGE(K: GAMMAINT; BASE_1, POL_1: LIST; VAR BASE_2, POL_2: LIST);
VAR XBASE, NPOL1, NPOL2, HK1, HT1, HM1, HK2, HT2, HM2, POS1, POS2, DUMMY: LIST;
    I, J, L1, L2, N, EL, SIGN: GAMMAINT;
BEGIN
L1 := LENGTH(BASE_1);
L2 := LENGTH(BASE_2);
XBASE := SIL;
POS1 := SIL;
POS2 := SIL;
I := 0;
J := 0;
WHILE BASE_2 # SIL DO
    ADV(BASE_2, HM2, BASE_2);
    HT2 := FIRST(HM2);
    LOOP IF BASE_1 # SIL THEN
              ADV(BASE_1, HM1, DUMMY);
              HT1 := FIRST(HM1);
              SIGN := GSYTWG(HT2, HT1);
         ELSE SIGN := 1; END; (* of if *)
         IF SIGN = 1 THEN
              IF J < L2 THEN J := J + 1; END;
              POS1 := COMP(I, POS1);
              IF J # K THEN XBASE := COMP(HM2, XBASE); END;
              EXIT;
              END; (* of if *)
         IF SIGN = 0 THEN
              IF I < L1 THEN I := I + 1; END;
              IF J < L2 THEN J := J + 1; END;
              XBASE := COMP(HM2, XBASE);
              BASE_1 := RED(BASE_1);
              EXIT;
              END; (* of if *)
         IF SIGN = -1 THEN
              IF I < L1 THEN I := I + 1; END;
              POS2 := COMP(J, POS2);
              XBASE := COMP(HM1, XBASE);
              BASE_1 := RED(BASE_1);
              END; (* of if *)
         END; (* of loop *)
    END; (* of while *)

WHILE BASE_1 # SIL DO
    ADV(BASE_1, HM1, BASE_1);
    XBASE := COMP(HM1, XBASE);
    POS2 := COMP(J, POS2);
    END; (* of while *)

BASE_2 := INV(XBASE);
N := LENGTH(BASE_2);

NPOL1 := 0;
IF POL_1 = 0 THEN POL_1 := SIL; END;
WHILE POL_1 # SIL DO
    DIPMAD(POL_1, HK1, HT1, POL_1);
    FOR I := 1 TO LENGTH(POS1) DO
         HT1 := LEINST(HT1, LELT(POS1, I), 0);
         END; (* of for *)
    NPOL1 := DIIPSM(DIPFMO(HK1, HT1), NPOL1);
    END; (* of while *)

NPOL2 := 0;
IF POL_2 = 0 THEN POL_2 := SIL; END;
WHILE POL_2 # SIL DO
    DIPMAD(POL_2, HK2, HT2, POL_2);
    FOR I := 1 TO LENGTH(POS2) DO
         HT2 := LEINST(HT2, LELT(POS2, I), 0);
         END; (* of for *)
    NPOL2 := DIIPSM(DIPFMO(HK2, HT2), NPOL2);
    END; (* of while *)

IF K = 0 THEN POL_2 := DIIPSM(NPOL1, NPOL2); RETURN; END;
POL_1 := 0;
IF NPOL1 = 0 THEN NPOL1 := SIL; END;
WHILE NPOL1 # SIL DO
    DIPMAD(NPOL1, HK1, HT1, NPOL1);
    EVDEL(HT1, K, HT1, DUMMY);
    POL_1 := DIIPSM(POL_1, DIPFMO(HK1, HT1));
    END; (* of while *)

POL_2 := 0;
IF NPOL2 = 0 THEN NPOL2 := SIL; END;
WHILE NPOL2 # SIL DO
    DIPMAD(NPOL2, HK2, HT2, NPOL2);
    EVDEL(HT2, K, HT2, EL);
    POL_2 := DIIPSM(POL_2, DIIPPR(DIIPEX(POL_1, EL), DIPFMO(HK2, HT2)));
    END; (* of while *)
END MERGE;

PROCEDURE REDUCE(PG, ORBIT: LIST; VAR BASE, POL: LIST);
VAR HK, HT, HM, RED_HT, BHM, BHT, PHM, PHK, PHT, TERM, XX, XHT, XHK, SIGMA,
    SIGMA_TL, BTL, NBTL, ORBIT_S, ORBIT_RED, OMEGA, PBASE, PPOL, SPG, PAIRS,
    MAT, NMAT, RS, ROW, NROW, SIGN, XLS, KOEFF, POS, DUMMY: LIST;
    ACT, LOW, MINI, MAXI, I, J, L, N: GAMMAINT;
    FLAG: BOOLEAN;
BEGIN
BASE := SIL;
POL := 0;
IF ORBIT = 0 THEN RETURN; END;
DIPMAD(ORBIT, HK, HT, DUMMY);
N := LENGTH(HT);
HM := DIPFMO(HK, HT);

SIGMA := SIL;
RED_HT := SIL;
(*-------------------------------------------------------------------------*)
(* ORBIT is a constant polynomial                                          *)
(*-------------------------------------------------------------------------*)
IF EVSIGN(HT) = 0 THEN EXTRACT(PG, 0, 0, ORBIT, BASE, POL); RETURN; END;

MAXI := 0;
MINI := 999999;
FOR I := 1 TO N DO
    ACT := LELT(HT, I);
    IF ACT > MAXI THEN MAXI := ACT; END;
    IF ACT < MINI THEN MINI := ACT; END;
    END; (* of for *)

LOW := MAXI;
I := MAXI - 1;
WHILE I >= MINI DO
    J := 1;
    WHILE (J <= N) AND (LELT(HT, J) # I) DO J:=J+1; END; (* of while *)
    IF J = (N+1) THEN I := -1;
    ELSE LOW := I; END; (* of if *)
    I := I - 1;
    END; (* of while *)

(*-------------------------------------------------------------------------*)
(* ORBIT is not max. n-linked or max. n-linked with no zero exponents      *)
(*-------------------------------------------------------------------------*)
IF (LOW # MINI) OR ((LOW # 0) AND (MAXI > 1)) THEN
    FOR I := N TO 1 BY -1 DO
         ACT := LELT(HT, I);
         IF ACT >= LOW THEN RED_HT := COMP(ACT-1, RED_HT);
         ELSE RED_HT := COMP(ACT, RED_HT); END; (* of if *)
         END; (* of for *)
    SIGMA := EVDIF(HT, RED_HT);
    ORBIT_S := GINORP(PG, DIPFMO(1, SIGMA));
    ORBIT_RED := GINORP(PG, DIPFMO(1, RED_HT));
    OMEGA := DIIPDF(ORBIT, DIIPPR(ORBIT_RED, ORBIT_S));
    EXTRACT(PG, ORBIT_RED, ORBIT_S, OMEGA, BASE, POL);
    RETURN; END; (* of if *)

(*-------------------------------------------------------------------------*)
(* ORBIT is max. n-linked and not multilinear --> try simple reduction     *)
(*-------------------------------------------------------------------------*)
IF MAXI > 1 THEN
    FOR LOW := 1 TO MAXI DO
         RED_HT := SIL;
         FOR I := N TO 1 BY -1 DO
              ACT := LELT(HT, I);
              IF ACT >= LOW THEN RED_HT := COMP(ACT-1, RED_HT);
              ELSE RED_HT := COMP(ACT, RED_HT); END; (* of if *)
              END; (* of for *)
         SIGMA := EVDIF(HT, RED_HT);
         ORBIT_S := GINORP(PG, DIPFMO(1, SIGMA));
         ORBIT_RED := GINORP(PG, DIPFMO(1, RED_HT));
         OMEGA := DIIPDF(ORBIT, DIIPPR(ORBIT_RED, ORBIT_S));
         EXTRACT(PG, ORBIT_RED, ORBIT_S, OMEGA, BASE, POL);
         IF GSYTWG(HT, FIRST(FIRST(BASE))) = 1 THEN RETURN; END;
         END; (* of for *)
    END; (* of if *)

(*-------------------------------------------------------------------------*)
(* ORBIT is max. n-linked and not multilinear --> try extended reduction 1 *)
(*-------------------------------------------------------------------------*)
BLINES(0); SWRITE("HT = "); OWRITE(HT);
BASE := SIL;
POL := SIL;
SPG := GSYSPG(N);
BTL := SIL;
PAIRS := SIL;
MAT := SIL;
RS := SIL;
SIGMA_TL := GSYMLT(N);

WHILE SIGMA_TL # SIL DO
    ADV(SIGMA_TL, SIGMA, SIGMA_TL);
    RED_HT := EVDIF(HT, SIGMA);
    IF EVSIGN(RED_HT) > 0 THEN
         ORBIT_RED := GINORP(PG, DIPFMO(1, RED_HT));
         XX := GINORP(SPG, DIPFMO(1, SIGMA));
    ELSE XX := 0; END; (* of if *)

    WHILE XX # 0 DO
         DIPMAD(XX, XHK, XHT, DUMMY);
         XX := DIIPDF(XX, GINORP(PG, DIPFMO(1, XHT)));
         ORBIT_S := GINORP(PG, DIPFMO(1, XHT));
         EXTRACT(PG, ORBIT_RED, ORBIT_S, 0, PBASE, DUMMY);
         FLAG := FALSE;
         IF MEMBER(PBASE, PAIRS) # 1 THEN
              PAIRS := COMP(PBASE, PAIRS);
              PPOL := DIIPPR(ORBIT_RED, ORBIT_S);
              FLAG := TRUE;
         ELSE PPOL := 0; END; (* of if *)

         KOEFF := SIL;
         PBASE := SIL;
         WHILE PPOL # 0 DO
              DIPMAD(PPOL, PHK, PHT, DUMMY);
              PPOL := DIIPDF(PPOL, GINORP(PG, DIPFMO(PHK, PHT)));
              L := LENGTH(PBASE);
              I := 0;
              LOOP I := I + 1;
                   IF I > L THEN EXIT; END;
                   PHM := LELT(PBASE, I);
                   IF GSYTWG(FIRST(PHM), PHT) <= 0 THEN EXIT; END;
                   END; (* of loop *)
              I := I - 1;
              PBASE := LEINST(PBASE, I, DIPFMO(1, PHT));
              KOEFF := LEINST(KOEFF, I, PHK);
              END; (* of while *)

         ROW := SIL;
         POS := SIL;
         L := LENGTH(BTL);
         NBTL := INV(BTL);
         BTL := SIL;
         LOOP IF PBASE = SIL THEN EXIT; END;
              ADV(PBASE, BHM, PBASE);
              BHT := FIRST(BHM);
              ADV(KOEFF, PHK, KOEFF);
              IF GSYTWG(BHT, HT) < 0 THEN EXIT; END;
              LOOP IF NBTL # SIL THEN
                        ADV(NBTL, TERM, DUMMY);
                        SIGN := GSYTWG(TERM, BHT);
                   ELSE SIGN := -1; END;
                   IF SIGN = 1 THEN
                        L := L - 1;
                        BTL := COMP(TERM, BTL);
                        ROW := COMP(0, ROW);
                        NBTL := RED(NBTL);
                        END; (* of if *)
                   IF SIGN = 0 THEN
                        L := L - 1;
                        BTL := COMP(TERM, BTL);
                        ROW := COMP(PHK, ROW);
                        NBTL := RED(NBTL);
                        EXIT; END; (* of if *)
                   IF SIGN = -1 THEN
                        POS := COMP(L, POS);
                        BTL := COMP(BHT, BTL);
                        ROW := COMP(PHK, ROW);
                        EXIT; END; (* of if *)
                   END; (* of loop *)
              END; (* of loop *)

         WHILE NBTL # SIL DO
              ADV(NBTL, TERM, NBTL);
              BTL := COMP(TERM, BTL);
              ROW := COMP(0, ROW);
              END; (* of while *)

         POS := INV(POS);
         NMAT := INV(MAT);
         MAT := SIL;
         WHILE NMAT # SIL DO
              ADV(NMAT, NROW, NMAT);
              FOR I := 1 TO LENGTH(POS) DO
                   NROW := LEINST(NROW, LELT(POS,I), 0);
                   END; (* of for *)
              MAT := COMP(NROW, MAT);
              END; (* of while *)

         IF EVSIGN(ROW) # 0 THEN  MAT := COMP(ROW, MAT);
         ELSE IF FLAG THEN PAIRS := RED(PAIRS); END; END; (* of if *)
         END; (* of while *)
    END; (* of while *)

XLS := SIL;
IF MAT # SIL THEN
BLINES(0); SWRITE("C/R = "); OWRITE(LENGTH(MAT));
           SWRITE("/"); OWRITE(LENGTH(FIRST(MAT)));
    FOR I := 1 TO LENGTH(FIRST(MAT))-1 DO RS := COMP(0, RS); END;
    RS := COMP(1, RS);
    LDSMKB(MAT, RS, XLS, DUMMY);
    SWRITE(" XLS = "); OWRITE(XLS);
    END; (* of if *)
IF XLS # SIL THEN 
    OMEGA := ORBIT;
    WHILE XLS # SIL DO
         ADV(XLS, XHK, XLS);
         ADV(PAIRS, PBASE, PAIRS);
         IF XHK # 0 THEN
              IF LENGTH(PBASE) = 1 THEN PPOL := DIPFMO(1, LIST1(2));
              ELSE PPOL := DIPFMO(1, COMP(1, LIST1(1))); END;
              PPOL := DIIPIP(PPOL, XHK);
              OMEGA := DIIPDF(OMEGA, GINCHK(PG, PBASE, PPOL));
              MERGE(0, PBASE, PPOL, BASE, POL);
              END; (* of if *)
         END; (* of while *)
     EXTRACT(PG, 0, 0, OMEGA, PBASE, PPOL);
     MERGE(0, PBASE, PPOL, BASE, POL);
     GINCHKBAS(BASE, POL);
     RETURN; END; (* of if *)

(*-------------------------------------------------------------------------*)
(* ORBIT is max. n-linked and not multilinear --> try extended reduction 2 *)
(*-------------------------------------------------------------------------*)
BASE := SIL;
POL := SIL;
SPG := GSYSPG(N);
BTL := SIL;
PAIRS := SIL;
MAT := SIL;
RS := SIL;
SIGMA_TL := GSYMLT(N);

WHILE SIGMA_TL # SIL DO
    ADV(SIGMA_TL, SIGMA, SIGMA_TL);
    RED_HT := EVDIF(HT, SIGMA);
    IF EVSIGN(RED_HT) > 0 THEN
         ORBIT_S := GINORP(PG, DIPFMO(1, SIGMA));
         XX := GINORP(SPG, DIPFMO(1, RED_HT));
    ELSE XX := 0; END; (* of if *)

    WHILE XX # 0 DO
         DIPMAD(XX, XHK, XHT, DUMMY);
         XX := DIIPDF(XX, GINORP(PG, DIPFMO(1, XHT)));
         ORBIT_RED := GINORP(PG, DIPFMO(1, XHT));
         EXTRACT(PG, ORBIT_RED, ORBIT_S, 0, PBASE, DUMMY);
         FLAG := FALSE;
         IF MEMBER(PBASE, PAIRS) # 1 THEN
              PAIRS := COMP(PBASE, PAIRS);
              PPOL := DIIPPR(ORBIT_RED, ORBIT_S);
              FLAG := TRUE;
         ELSE PPOL := 0; END; (* of if *)

         KOEFF := SIL;
         PBASE := SIL;
         WHILE PPOL # 0 DO
              DIPMAD(PPOL, PHK, PHT, DUMMY);
              PPOL := DIIPDF(PPOL, GINORP(PG, DIPFMO(PHK, PHT)));
              L := LENGTH(PBASE);
              I := 0;
              LOOP I := I + 1;
                   IF I > L THEN EXIT; END;
                   PHM := LELT(PBASE, I);
                   IF GSYTWG(FIRST(PHM), PHT) <= 0 THEN EXIT; END;
                   END; (* of loop *)
              I := I - 1;
              PBASE := LEINST(PBASE, I, DIPFMO(1, PHT));
              KOEFF := LEINST(KOEFF, I, PHK);
              END; (* of while *)

         ROW := SIL;
         POS := SIL;
         L := LENGTH(BTL);
         NBTL := INV(BTL);
         BTL := SIL;
         LOOP IF PBASE = SIL THEN EXIT; END;
              ADV(PBASE, BHM, PBASE);
              BHT := FIRST(BHM);
              ADV(KOEFF, PHK, KOEFF);
              IF GSYTWG(BHT, HT) < 0 THEN EXIT; END;
              LOOP IF NBTL # SIL THEN
                        ADV(NBTL, TERM, DUMMY);
                        SIGN := GSYTWG(TERM, BHT);
                   ELSE SIGN := -1; END;
                   IF SIGN = 1 THEN
                        L := L - 1;
                        BTL := COMP(TERM, BTL);
                        ROW := COMP(0, ROW);
                        NBTL := RED(NBTL);
                        END; (* of if *)
                   IF SIGN = 0 THEN
                        L := L - 1;
                        BTL := COMP(TERM, BTL);
                        ROW := COMP(PHK, ROW);
                        NBTL := RED(NBTL);
                        EXIT; END; (* of if *)
                   IF SIGN = -1 THEN
                        POS := COMP(L, POS);
                        BTL := COMP(BHT, BTL);
                        ROW := COMP(PHK, ROW);
                        EXIT; END; (* of if *)
                   END; (* of loop *)
              END; (* of loop *)

         WHILE NBTL # SIL DO
              ADV(NBTL, TERM, NBTL);
              BTL := COMP(TERM, BTL);
              ROW := COMP(0, ROW);
              END; (* of while *)

         POS := INV(POS);
         NMAT := INV(MAT);
         MAT := SIL;
         WHILE NMAT # SIL DO
              ADV(NMAT, NROW, NMAT);
              FOR I := 1 TO LENGTH(POS) DO
                   NROW := LEINST(NROW, LELT(POS,I), 0);
                   END; (* of for *)
              MAT := COMP(NROW, MAT);
              END; (* of while *)

         IF EVSIGN(ROW) # 0 THEN  MAT := COMP(ROW, MAT);
         ELSE IF FLAG THEN PAIRS := RED(PAIRS); END; END; (* of if *)
         END; (* of while *)
    END; (* of while *)

XLS := SIL;
IF MAT # SIL THEN
BLINES(0); SWRITE("C/R = "); OWRITE(LENGTH(MAT));
           SWRITE("/"); OWRITE(LENGTH(FIRST(MAT)));
    FOR I := 1 TO LENGTH(FIRST(MAT))-1 DO RS := COMP(0, RS); END;
    RS := COMP(1, RS);
    LDSMKB(MAT, RS, XLS, DUMMY);
    SWRITE(" XLS = "); OWRITE(XLS);
    END; (* of if *)
(*-------------------------------------------------------------------------*)
(* return ORBIT without reduction                                          *)
(*-------------------------------------------------------------------------*)
IF XLS = SIL THEN EXTRACT(PG, 0, 0, ORBIT, BASE, POL); RETURN; END;

OMEGA := ORBIT;
WHILE XLS # SIL DO
    ADV(XLS, XHK, XLS);
    ADV(PAIRS, PBASE, PAIRS);
    IF XHK # 0 THEN
         IF LENGTH(PBASE) = 1 THEN PPOL := DIPFMO(1, LIST1(2));
         ELSE PPOL := DIPFMO(1, COMP(1, LIST1(1))); END;
         PPOL := DIIPIP(PPOL, XHK);
         OMEGA := DIIPDF(OMEGA, GINCHK(PG, PBASE, PPOL));
         MERGE(0, PBASE, PPOL, BASE, POL);
         END; (* of if *)
    END; (* of while *)
EXTRACT(PG, 0, 0, OMEGA, PBASE, PPOL);
MERGE(0, PBASE, PPOL, BASE, POL);
GINCHKBAS(BASE, POL);
END REDUCE;

PROCEDURE GINRED(PG, POL: LIST; VAR BASE, BASE_POL, REM_POL: LIST);
VAR HK, HT, HM, ORBIT, BASE_1, BASE_POL_1, DUMMY: LIST;
    I: GAMMAINT;
BEGIN
BASE := SIL;
BASE_POL := SIL;
REM_POL := 0;
IF POL = 0 THEN RETURN; END;
WHILE POL # 0 DO
    DIPMAD(POL, HK, HT, DUMMY);
    HM := DIPFMO(HK, HT);
    ORBIT := GINORP(PG, HM);
    IF EQUAL(HT, FIRST(ORBIT)) = 1 THEN
         POL := DIIPDF(POL, ORBIT);
         EXTRACT(PG, 0, 0, ORBIT, BASE_1, BASE_POL_1);
         MERGE(0, BASE_1, BASE_POL_1, BASE, BASE_POL);
    ELSE POL := DIIPDF(POL, HM);
         REM_POL := DIIPSM(REM_POL, HM);
         END; (* of if *)
    END; (* of while *)

I := 1;
WHILE I <= LENGTH(BASE) DO
    BLINES(0); SWRITE("GINRED working... (BASE) "); OWRITE(BASE);
    HM := LELT(BASE,I);
    ORBIT := GINORP(PG, HM);
    REDUCE(PG, ORBIT, BASE_1, BASE_POL_1);
    HT := FIRST(HM);
    IF EQUAL(HT, FIRST(FIRST(BASE_1))) = 1 THEN I := I + 1;
    ELSE MERGE(I, BASE_1, BASE_POL_1, BASE, BASE_POL); END; (* of if *)
    END; (* of while *)

GINCHKBAS(BASE, BASE_POL);
BLINES(1); SWRITE("GINRED exit (BASE): "); OWRITE(BASE);
BLINES(0); SWRITE("GINRED exit (BASE_POL): "); OWRITE(BASE_POL);
BLINES(0); SWRITE("GINRED exit (REM_POL): "); OWRITE(REM_POL);
END GINRED;

PROCEDURE GSYADD(TERM: LIST): LIST;
VAR ADDTERM, EL: LIST;
    I, N, POS: GAMMAINT;
BEGIN
ADDTERM := TERM;
N := LENGTH(TERM);
IF (N <= 2) AND (LELT(TERM,1) = 2) THEN RETURN(ADDTERM); END;
IF (N > 2) AND (LELT(TERM,1) = N) THEN RETURN(ADDTERM); END;
POS := 1;
EL := LELT(TERM, POS);
FOR I := 2 TO N DO
    IF EL > LELT(TERM, I) THEN
         POS := I;
         EL := LELT(TERM, POS);
         END; (* of if *)
    END; (* of for *)
SLELT(ADDTERM, POS, EL+1);
IF POS < N THEN
    FOR I := POS+1 TO N DO SLELT(ADDTERM, I, 0); END;
    END; (* of if *)

I := 1;
LOOP IF I+1 > N THEN EXIT; END;
     IF (LELT(ADDTERM, I) - LELT(ADDTERM, I+1)) > 1 THEN EXIT; END;
     I := I + 1;
     END; (* of loop *)

IF (I = N) AND (LELT(ADDTERM, N) = 0) THEN RETURN(ADDTERM); END;
IF (LELT(ADDTERM,1) = 1) THEN RETURN(ADDTERM); END;
RETURN(GSYADD(ADDTERM));
END GSYADD;

PROCEDURE GINBAS(PG: LIST): LIST;
VAR BASE, XBASE, SPG, ORBIT_SPG, ORBIT_PG, POL, TERM, HK, HT: LIST;
    I, N, MAX, NR1, NR2: GAMMAINT;
BEGIN
NR1 := 0;
NR2 := 0;
XBASE := 0;
BASE := SIL;
IF PG = SIL THEN RETURN(BASE); END;
N := LENGTH(FIRST(PG));
SPG := GSYSPG(N);
IF N <= 2 THEN MAX := 1; END;
IF N > 2 THEN  MAX := N - 1; END;
TERM := SIL;
FOR I := 1 TO N DO TERM := COMP(0, TERM); END;

LOOP TERM := GSYADD(TERM);
    IF FIRST(TERM) > MAX THEN EXIT; END; (* of if *)
    ORBIT_SPG := GINORP(SPG, DIPFMO(1, TERM));
    WHILE ORBIT_SPG # 0 DO
         NR1 := NR1 + 1;
         HT := FIRST(ORBIT_SPG);
         ORBIT_PG := GINORP(PG, DIPFMO(1, HT));
         ORBIT_SPG := DIIPDF(ORBIT_SPG, ORBIT_PG);
         REDUCE(PG, ORBIT_PG, BASE, POL);
         IF EQUAL(HT, FIRST(FIRST(BASE))) = 1 THEN
              NR2 := NR2 + 1;
              BLINES(0); SWRITE("GINBAS working... (Term ");
              OWRITE(NR1); SWRITE("/"); OWRITE(NR2); SWRITE("): "); OWRITE(HT);
              XBASE := DIIPSM(XBASE, DIPFMO(1, HT));
              END; (* of if *)
         END; (* of while *);
    END; (* of loop *)

BASE := SIL;
IF XBASE = 0 THEN XBASE := SIL; END;
WHILE XBASE # SIL DO
    DIPMAD(XBASE, HK, HT, XBASE);
    BASE := COMP(DIPFMO(1, HT), BASE);
    END; (* of while *)
BLINES(1); SWRITE("GINBAS exit (BASE): "); OWRITE(BASE);
BLINES(0); SWRITE("Number of special polynomials: ");OWRITE(NR1);
BLINES(0); SWRITE("Number of base polynomials:    ");OWRITE(NR2);
RETURN(BASE);
END GINBAS;

END GSYMFUIN.
(* -EOF- *)