/**
  * Augments the path the vertex
  *
  * @param g the {@link Graph}
  * @param v the {@link Vertex} to start from
  * @param pred a {@link VertexArray}
  */
 private void augmentPathTo(Graph g, Vertex v, final VertexArray pred) {
   Edge e = (Edge) pred.getVertexProperty(v);
   while (e != null) {
     e.turnOverEdgeDirection();
     e = (Edge) pred.getVertexProperty(GraphUtilities.getEdgeTargetVertex(g, e));
   }
 }
  /**
   * Run the algorithm
   *
   * @return an {@link EdgesSet}
   */
  public EdgesSet runAlgorithm() {
    EdgesSet result = new EdgesSet(g.getEdgesSet().getVc());
    // for all nodes(v,G) pot[v] = 0;
    // this will be done by giving pot:= VertexArray(g,new Double(0))
    if (g.getEdgesSet().isEmpty()) return new EdgesSet(g.getEdgesSet().getVc());
    // check that all edges are directed from A to B
    // this should be a precondition also
    VertexArray free = new VertexArray(g, new Boolean(true));
    VertexArray pred = new VertexArray(g, null);
    VertexArray dist = new VertexArray(g, new Double(0));
    VertexPQ PQ = new VertexPQ(g);

    switch (heuristic) {
      case NAIVE_HEURISTIC:
        Double C = new Double(0);
        Iterator<Edge> edgesIterator = g.getEdgesIterator();
        while (edgesIterator.hasNext()) {
          Edge e = edgesIterator.next();
          Double edgeC = (Double) c.getEdgeProperty(e);
          if (edgeC.compareTo(C) == 1) // bigger than...
          C = edgeC;
        }
        Iterator<Vertex> leftVertexesIterator = g.getLeftVertexSetIterator();
        while (leftVertexesIterator.hasNext()) {
          pot.setVertexProperty(leftVertexesIterator.next(), C);
        }
        break;
      case SIMPLE_HEURISTIC:
        Iterator<Vertex> leftVertexesIterator1 = g.getLeftVertexSetIterator();
        while (leftVertexesIterator1.hasNext()) {
          Vertex a = leftVertexesIterator1.next();
          Edge eMax = null;
          double C_max = 0;
          Iterator<Edge> vertexAdjEdgesIterator =
              GraphUtilities.getVertexAdjEdges(g, a).getMembers().iterator();
          while (vertexAdjEdgesIterator.hasNext()) {
            Edge e = vertexAdjEdgesIterator.next();
            if (((Double) c.getEdgeProperty(e)).doubleValue() > C_max) {
              eMax = e;
              C_max = ((Double) c.getEdgeProperty(e)).doubleValue();
            }
          }
          pot.setVertexProperty(a, new Double(C_max));
          Vertex b;
          if (eMax != null
              && ((Boolean)
                      free.getVertexProperty((b = GraphUtilities.getEdgeTargetVertex(g, eMax))))
                  .booleanValue()) {
            eMax.turnOverEdgeDirection();
            free.setVertexProperty(a, new Boolean(false));
            free.setVertexProperty(b, new Boolean(false));
          }
        }
        break;
      default:
        // REFINED_HEURISTIC
        mwbmHeuristic(g, c, pot, free);
        break;
    }
    Iterator<Vertex> leftVertexesIterator = g.getLeftVertexSetIterator();
    while (leftVertexesIterator.hasNext()) {
      Vertex a = leftVertexesIterator.next();
      if (((Boolean) free.getVertexProperty(a)).booleanValue())
        augment(g, a, c, pot, free, pred, dist, PQ);
    }
    Iterator<Vertex> rightVertexesIterator = g.getRightVertexSetIterator();
    while (rightVertexesIterator.hasNext()) {
      Vertex b = rightVertexesIterator.next();
      Iterator<Edge> outEdgesIterator =
          GraphUtilities.getVertexOutEdges(g, b).getMembers().iterator();
      while (outEdgesIterator.hasNext()) {
        result.addMember(outEdgesIterator.next());
      }
    }
    result.turnOverEdges(false);
    return result;
  }
 /**
  * The maximum weight bipartite matching heuristis
  *
  * @param g {@link BipartiteGraph}
  * @param c an {@link EdgeArray}
  * @param pot a {@link VertexArray}
  * @param free free {@link VertexArray}
  */
 private void mwbmHeuristic(BipartiteGraph g, EdgeArray c, VertexArray pot, VertexArray free) {
   Vertex a, b;
   Edge e, e2, eb;
   VertexArray secEdge = new VertexArray(g, null);
   Iterator<Vertex> leftVertexSetIterator = g.getLeftVertexSetIterator();
   while (leftVertexSetIterator.hasNext()) {
     a = (Vertex) leftVertexSetIterator.next();
     double max2 = 0, max = 0;
     eb = null;
     e2 = null;
     // compute edges with largest and second largest slack
     Iterator<Edge> aAdjEdgesIterator =
         GraphUtilities.getVertexAdjEdges(g, a).getMembers().iterator();
     while (aAdjEdgesIterator.hasNext()) {
       e = (Edge) aAdjEdgesIterator.next();
       double we =
           ((Double) c.getEdgeProperty(e)).doubleValue()
               - ((Double) pot.getVertexProperty(GraphUtilities.getEdgeTargetVertex(g, e)))
                   .doubleValue();
       if (we >= max2) {
         if (we >= max) {
           max2 = max;
           e2 = eb;
           max = we;
           eb = e;
         } else {
           max2 = we;
           e2 = e;
         }
       }
     }
     if (eb != null) {
       b = GraphUtilities.getEdgeTargetVertex(g, eb);
       if (((Boolean) free.getVertexProperty(b)).booleanValue()) {
         // match eb and change pot[] to make slack of e2 zero
         secEdge.setVertexProperty(a, e2);
         pot.setVertexProperty(a, new Double(max2));
         pot.setVertexProperty(b, new Double(max - max2));
         eb.turnOverEdgeDirection();
         free.setVertexProperty(a, new Boolean(false));
         free.setVertexProperty(b, new Boolean(false));
       } else {
         // try to augment matching along
         // path of length 3 given by sec_edge[]
         pot.setVertexProperty(a, new Double(max));
         e2 = GraphUtilities.getVertexFirstAdjEdge(g, b);
         e = (Edge) secEdge.getVertexProperty(GraphUtilities.getEdgeTargetVertex(g, e2));
         if (e != null
             && GraphUtilities.getVertexOutDeg(g, GraphUtilities.getEdgeTargetVertex(g, e)) == 0) {
           free.setVertexProperty(a, new Boolean(false));
           free.setVertexProperty(GraphUtilities.getEdgeTargetVertex(g, e), new Boolean(false));
           e.turnOverEdgeDirection();
           e2.turnOverEdgeDirection();
           eb.turnOverEdgeDirection();
         }
       }
     } else {
       pot.setVertexProperty(a, new Double(0));
     }
   }
 }