/****************************************************************************
**
*A  update_generators.c         ANUPQ source                   Eamonn O'Brien
**
*Y  Copyright 1995-2001,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
*Y  Copyright 1995-2001,  School of Mathematical Sciences, ANU,     Australia
**
*/

#include "pq_defs.h"
#include "pcp_vars.h"
#include "pq_functions.h"

/* add pseudo-generators to redundant defining generators;
   also recompute required inverses of defining generators;

   this routine must be called before a call to collect defining
   relations; if there are redundant defining generators, calls to
   eliminate should only be done after calling update_generator
   because the space reserved for the pseudo-generator(s) added
   by update_generator in structure is not set up yet */

void update_generators(struct pcp_vars *pcp)
{
   register int *y = y_address;

   register int f;
   register int i;
   register int cp;
   register int start;
   register int ycol;
   register int length;
   register int extra;
   register int value;

   register int prime = pcp->p;
   register int dgen = pcp->dgen;
   register int ndgen = pcp->ndgen;
   register int lused;
   register int lastg;

#include "access.h"

   /* first, add pseudo-generators to redundant defining generators */

   for (f = 1; f <= ndgen; f++) {
      value = y[dgen + f];
      if (value == 0) {
         /* defining generator f was trivial; insert pseudo-generator */

         if (is_space_exhausted(3, pcp))
            return;

         pcp->lused += 3;
         lused = pcp->lused;

         /* set up block header block and pointer to it */
         y[lused - 2] = dgen + f;
         y[lused - 1] = 1;
         y[dgen + f] = -(lused - 2);

         /* add pseudo-generator */
         pcp->lastg++;
         y[lused] = PACK2(1, pcp->lastg);

         /* if there are greater than MAXGENS defining generators
            then this field will overflow; such an overflow causes
            some output idiocies, but no logical errors */

         y[pcp->structure + pcp->lastg] = PACK3(0, 0, f) + INSWT(pcp->cc);

      } else if (value < 0) {
         /* old entry was non-trivial so we deallocate it
            and insert pseudo-generator */
         extend_tail(dgen + f, 0, f, pcp);
         if (pcp->overflow)
            return;
      }
   }

   /* update submlg to account for any new pseudo-generators introduced */
   pcp->submlg = pcp->subgrp - pcp->lastg;

   /* now, recompute required inverses --
      we know the inverse of f to the end of class pcp->cc - 1;
      denote this by f'; evaluate f * f' and take the inverse of
      this result to give the class pcp->cc part of f^-1 */

   for (f = 1; f <= ndgen; f++) {
      if (y[dgen - f] > 0)
         continue;

      if (is_space_exhausted(2 * pcp->lastg + 2, pcp))
         return;

      lastg = pcp->lastg;
      lused = pcp->lused;
      cp = lused + lastg + 2;
      for (i = 1; i <= lastg; ++i)
         y[cp + i] = 0;
      ycol = y[dgen + f];
      collect(ycol, cp, pcp);
      ycol = y[dgen - f];
      collect(ycol, cp, pcp);

      /* inverse of the class pcp->cc part of f^(-1) is now in
         y[cp + pcp->ccbeg] to y[cp + pcp->lastg] in exponent form;
         convert it to string form */

      length = 0;
      for (i = pcp->ccbeg; i <= lastg; i++) {
         if ((ycol = y[cp + i]) > 0) {
            ++length;
            y[lused + 2 + length] = PACK2(prime - ycol, i);
         }
      }
      if (length == 0)
         continue;

      /* the class pcp->cc part of f^(-1) is nontrivial */

      if (y[dgen - f] >= 0) {

         /* f^(-1) was previously trivial */
         y[lused + 1] = dgen - f;
         y[lused + 2] = length;
         y[dgen - f] = -(lused + 1);
         pcp->lused += length + 2;
         lused = pcp->lused;
      } else {

         /* f^(-1) was nontrivial, so make room for lower class entries */
         start = -y[dgen - f];
         extra = y[start + 1];
         ycol = lused + length + 3;
         for (i = 1; i <= length; i++)
            y[ycol + extra - i] = y[ycol - i];

         /* copy header block and lower class entries */
         for (i = 1; i <= extra; i++)
            y[lused + i + 2] = y[start + i + 1];

         /* fix header block */
         y[lused + 1] = y[start];
         y[lused + 2] = length + extra;

         /* deallocate old entry */
         y[start] = 0;

         /* set up pointer to new entry */
         y[dgen - f] = -(lused + 1);
         pcp->lused += length + extra + 2;
      }
   }
}
