/** 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();
  }
  /**
   * Distributed Groebner base, part for MPI master.
   *
   * @param modv number of module variables.
   * @param F polynomial list.
   * @return GB(F) a Groebner base of F or null, if a IOException occurs.
   */
  public List<GenPolynomial<C>> GBmaster(int modv, List<GenPolynomial<C>> F)
      throws MPIException, IOException {
    List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>();
    GenPolynomial<C> p;
    PairList<C> pairlist = null;
    boolean oneInGB = false;
    // int l = F.size();
    int unused = 0;
    ListIterator<GenPolynomial<C>> it = F.listIterator();
    while (it.hasNext()) {
      p = it.next();
      if (p.length() > 0) {
        p = p.monic();
        if (p.isONE()) {
          oneInGB = true;
          G.clear();
          G.add(p);
          // return G; must signal termination to others
        }
        if (!oneInGB) {
          G.add(p);
        }
        if (pairlist == null) {
          pairlist = strategy.create(modv, p.ring);
          if (!p.ring.coFac.isField()) {
            throw new IllegalArgumentException("coefficients not from a field");
          }
        }
        // theList not updated here
        if (p.isONE()) {
          unused = pairlist.putOne();
        } else {
          unused = pairlist.put(p);
        }
      } else {
        // l--;
      }
    }
    // if (l <= 1) {
    // return G; must signal termination to others
    // }
    logger.info("done pairlist, initialize DHT: " + unused);

    DistHashTableMPI<Integer, GenPolynomial<C>> theList =
        new DistHashTableMPI<Integer, GenPolynomial<C>>(engine);
    theList.init();
    // logger.info("done DHT: " + theList);

    List<GenPolynomial<C>> al = pairlist.getList();
    for (int i = 0; i < al.size(); i++) {
      // no wait required
      GenPolynomial<C> nn = theList.put(Integer.valueOf(i), al.get(i));
      if (nn != null) {
        logger.info("double polynomials " + i + ", nn = " + nn + ", al(i) = " + al.get(i));
      }
    }

    Terminator fin = new Terminator(threads - 1);
    MPIReducerServer<C> R;
    for (int i = 1; i < threads; i++) {
      logger.debug("addJob " + i + " of " + threads);
      MPIChannel chan = new MPIChannel(engine, i); // closed in server
      R = new MPIReducerServer<C>(i, fin, chan, theList, pairlist);
      pool.addJob(R);
    }
    logger.debug("main loop waiting");
    fin.waitDone();
    int ps = theList.size();
    logger.info("#distributed list = " + ps);
    // make sure all polynomials arrived: not needed in master
    // G = (ArrayList)theList.values();
    G = pairlist.getList();
    if (ps != G.size()) {
      logger.info("#distributed list = " + theList.size() + " #pairlist list = " + G.size());
    }
    long time = System.currentTimeMillis();
    List<GenPolynomial<C>> Gp = minimalGB(G); // not jet distributed but threaded
    time = System.currentTimeMillis() - time;
    logger.debug("parallel gbmi = " + time);
    G = Gp;
    logger.info("theList.terminate()");
    theList.terminate();
    logger.info("end" + pairlist);
    return G;
  }