/** Main run method. */
 public void run() {
   if (logger.isDebugEnabled()) {
     logger.debug("ht(H) = " + H.leadingExpVector());
   }
   H = red.normalform(G, H); // mod
   done.release(); // done.V();
   if (logger.isDebugEnabled()) {
     logger.debug("ht(H) = " + H.leadingExpVector());
   }
   // H = H.monic();
 }
  /** Main run method. */
  public void run() {
    logger.debug("reducer client running");
    Pair<C> pair = null;
    GenPolynomial<C> pi, pj, ps;
    GenPolynomial<C> S;
    GenPolynomial<C> H = null;
    // boolean set = false;
    boolean goon = true;
    int reduction = 0;
    // int sleeps = 0;
    Integer pix, pjx, psx;

    while (goon) {
      /* protocol:
       * request pair, process pair, send result
       */
      // pair = (Pair) pairlist.removeNext();
      Object req = new GBTransportMessReq();
      logger.debug("send request");
      try {
        pairChannel.send(req);
      } catch (IOException e) {
        goon = false;
        e.printStackTrace();
        break;
      } catch (MPIException e) {
        goon = false;
        e.printStackTrace();
        break;
      }
      logger.debug("receive pair, goon");
      Object pp = null;
      try {
        pp = pairChannel.receive();
      } catch (IOException e) {
        goon = false;
        if (logger.isDebugEnabled()) {
          e.printStackTrace();
        }
        break;
      } catch (MPIException e) {
        goon = false;
        if (logger.isDebugEnabled()) {
          e.printStackTrace();
        }
        break;
      } catch (ClassNotFoundException e) {
        goon = false;
        e.printStackTrace();
      }
      if (logger.isDebugEnabled()) {
        logger.debug("received pair = " + pp);
      }
      H = null;
      if (pp == null) { // should not happen
        continue;
      }
      if (pp instanceof GBTransportMessEnd) {
        goon = false;
        continue;
      }
      if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) {
        pi = pj = ps = null;
        if (pp instanceof GBTransportMessPair) {
          pair = ((GBTransportMessPair<C>) pp).pair;
          if (pair != null) {
            pi = pair.pi;
            pj = pair.pj;
            // logger.debug("pair: pix = " + pair.i
            //               + ", pjx = " + pair.j);
          }
        }
        if (pp instanceof GBTransportMessPairIndex) {
          pix = ((GBTransportMessPairIndex) pp).i;
          pjx = ((GBTransportMessPairIndex) pp).j;
          psx = ((GBTransportMessPairIndex) pp).s;
          pi = theList.getWait(pix);
          pj = theList.getWait(pjx);
          ps = theList.getWait(psx);
          // logger.info("pix = " + pix + ", pjx = " +pjx + ", psx = " +psx);
        }

        if (pi != null && pj != null) {
          S = red.SPolynomial(pi, pj);
          // System.out.println("S   = " + S);
          if (S.isZERO()) {
            // pair.setZero(); does not work in dist
          } else {
            if (logger.isDebugEnabled()) {
              logger.info("ht(S) = " + S.leadingExpVector());
            }
            H = red.normalform(theList, S);
            reduction++;
            if (H.isZERO()) {
              // pair.setZero(); does not work in dist
            } else {
              H = H.monic();
              if (logger.isInfoEnabled()) {
                logger.info("ht(H) = " + H.leadingExpVector());
              }
            }
          }
        }
      }

      // send H or must send null
      if (logger.isDebugEnabled()) {
        logger.debug("#distributed list = " + theList.size());
        logger.debug("send H polynomial = " + H);
      }
      try {
        pairChannel.send(new GBTransportMessPoly<C>(H));
      } catch (IOException e) {
        goon = false;
        e.printStackTrace();
      } catch (MPIException e) {
        goon = false;
        e.printStackTrace();
      }
    }
    logger.info("terminated, done " + reduction + " reductions");
    pairChannel.close();
  }
  /**
   * Minimal ordered groebner basis.
   *
   * @param Fp a Groebner base.
   * @return a reduced Groebner base of Fp.
   */
  @SuppressWarnings("cast")
  @Override
  public List<GenPolynomial<C>> minimalGB(List<GenPolynomial<C>> Fp) {
    GenPolynomial<C> a;
    ArrayList<GenPolynomial<C>> G;
    G = new ArrayList<GenPolynomial<C>>(Fp.size());
    ListIterator<GenPolynomial<C>> it = Fp.listIterator();
    while (it.hasNext()) {
      a = it.next();
      if (a.length() != 0) { // always true
        // already monic  a = a.monic();
        G.add(a);
      }
    }
    if (G.size() <= 1) {
      return G;
    }

    ExpVector e;
    ExpVector f;
    GenPolynomial<C> p;
    ArrayList<GenPolynomial<C>> F;
    F = new ArrayList<GenPolynomial<C>>(G.size());
    boolean mt;

    while (G.size() > 0) {
      a = G.remove(0);
      e = a.leadingExpVector();

      it = G.listIterator();
      mt = false;
      while (it.hasNext() && !mt) {
        p = it.next();
        f = p.leadingExpVector();
        mt = e.multipleOf(f);
      }
      it = F.listIterator();
      while (it.hasNext() && !mt) {
        p = it.next();
        f = p.leadingExpVector();
        mt = e.multipleOf(f);
      }
      if (!mt) {
        F.add(a);
      } else {
        // System.out.println("dropped " + a.length());
      }
    }
    G = F;
    if (G.size() <= 1) {
      return G;
    }
    Collections.reverse(G); // important for lex GB

    MiMPIReducerServer<C>[] mirs = (MiMPIReducerServer<C>[]) new MiMPIReducerServer[G.size()];
    int i = 0;
    F = new ArrayList<GenPolynomial<C>>(G.size());
    while (G.size() > 0) {
      a = G.remove(0);
      // System.out.println("doing " + a.length());
      List<GenPolynomial<C>> R = new ArrayList<GenPolynomial<C>>(G.size() + F.size());
      R.addAll(G);
      R.addAll(F);
      mirs[i] = new MiMPIReducerServer<C>(R, a);
      pool.addJob(mirs[i]);
      i++;
      F.add(a);
    }
    G = F;
    F = new ArrayList<GenPolynomial<C>>(G.size());
    for (i = 0; i < mirs.length; i++) {
      a = mirs[i].getNF();
      F.add(a);
    }
    return F;
  }