/**
  * Distributed Groebner base.
  *
  * @param modv number of module variables.
  * @param F polynomial list.
  * @return GB(F) a Groebner base of F or null, if a IOException occurs or on MPI client part.
  */
 public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) {
   try {
     if (engine.Rank() == 0) {
       return GBmaster(modv, F);
     }
   } catch (MPIException e) {
     logger.info("GBmaster: " + e);
     e.printStackTrace();
     return null;
   } catch (IOException e) {
     logger.info("GBmaster: " + e);
     e.printStackTrace();
     return null;
   }
   pool.terminate(); // not used on clients
   try {
     clientPart(0);
   } catch (IOException e) {
     logger.info("clientPart: " + e);
     e.printStackTrace();
   } catch (MPIException e) {
     logger.info("clientPart: " + e);
     e.printStackTrace();
   }
   return null;
 }
  /** 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();
  }
  /** Main method. */
  public void run() {
    logger.debug("reducer server running: "); // + rank);
    // try {
    //     pairChannel = new MPIChannel(engine, rank);
    // } catch (IOException e) {
    //     e.printStackTrace();
    //     return;
    // } catch (MPIException e) {
    //     e.printStackTrace();
    //     return;
    // }
    if (logger.isInfoEnabled()) {
      logger.info("reducer server running: pairChannel = " + pairChannel);
    }
    Pair<C> pair;
    GenPolynomial<C> H = null;
    boolean set = false;
    boolean goon = true;
    int polIndex = -1;
    int red = 0;
    int sleeps = 0;

    // while more requests
    while (goon) {
      // receive request
      logger.debug("receive request");
      Object req = null;
      try {
        req = pairChannel.receive();
      } catch (IOException e) {
        goon = false;
        e.printStackTrace();
      } catch (MPIException e) {
        goon = false;
        e.printStackTrace();
      } catch (ClassNotFoundException e) {
        goon = false;
        e.printStackTrace();
      }
      // logger.debug("received request, req = " + req);
      if (req == null) {
        goon = false;
        break;
      }
      if (!(req instanceof GBTransportMessReq)) {
        goon = false;
        break;
      }

      // find pair
      logger.debug("find pair");
      while (!pairlist.hasNext()) { // wait
        if (!set) {
          finaler.beIdle();
          set = true;
        }
        if (!finaler.hasJobs() && !pairlist.hasNext()) {
          goon = false;
          break;
        }
        try {
          sleeps++;
          if (sleeps % 10 == 0) {
            logger.info(" reducer is sleeping");
          }
          Thread.sleep(100);
        } catch (InterruptedException e) {
          goon = false;
          break;
        }
      }
      if (!pairlist.hasNext() && !finaler.hasJobs()) {
        goon = false;
        break; // continue; //break?
      }
      if (set) {
        set = false;
        finaler.notIdle();
      }

      pair = pairlist.removeNext();
      /*
       * send pair to client, receive H
       */
      logger.debug("send pair = " + pair);
      GBTransportMess msg = null;
      if (pair != null) {
        msg = new GBTransportMessPairIndex(pair);
      } else {
        msg = new GBTransportMess(); // End();
        // goon ?= false;
      }
      try {
        pairChannel.send(msg);
      } catch (IOException e) {
        e.printStackTrace();
        goon = false;
        break;
      } catch (MPIException e) {
        e.printStackTrace();
        goon = false;
        break;
      }
      logger.debug("#distributed list = " + theList.size());
      Object rh = null;
      try {
        rh = pairChannel.receive();
      } catch (IOException e) {
        e.printStackTrace();
        goon = false;
        break;
      } catch (MPIException e) {
        e.printStackTrace();
        goon = false;
        break;
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
        goon = false;
        break;
      }
      // logger.debug("received H polynomial");
      if (rh == null) {
        if (pair != null) {
          pair.setZero();
        }
      } else if (rh instanceof GBTransportMessPoly) {
        // update pair list
        red++;
        H = ((GBTransportMessPoly<C>) rh).pol;
        if (logger.isDebugEnabled()) {
          logger.debug("H = " + H);
        }
        if (H == null) {
          if (pair != null) {
            pair.setZero();
          }
        } else {
          if (H.isZERO()) {
            pair.setZero();
          } else {
            if (H.isONE()) {
              polIndex = pairlist.putOne();
              // GenPolynomial<C> nn =
              theList.putWait(Integer.valueOf(polIndex), H);
              goon = false;
              break;
            }
            polIndex = pairlist.put(H);
            // use putWait ? but still not all distributed
            // GenPolynomial<C> nn =
            theList.putWait(Integer.valueOf(polIndex), H);
          }
        }
      }
    }
    logger.info("terminated, done " + red + " reductions");

    /*
     * send end mark to client
     */
    logger.debug("send end");
    try {
      pairChannel.send(new GBTransportMessEnd());
    } catch (IOException e) {
      if (logger.isDebugEnabled()) {
        e.printStackTrace();
      }
    } catch (MPIException e) {
      if (logger.isDebugEnabled()) {
        e.printStackTrace();
      }
    }
    finaler.beIdle();
    pairChannel.close();
  }