protected int getIndex(Graph<V, E> graph, E e, V v) {
   Collection<E> commonEdgeSet = new HashSet<E>();
   for (E another : graph.getIncidentEdges(v)) {
     V u = graph.getOpposite(v, another);
     if (u.equals(v)) {
       commonEdgeSet.add(another);
     }
   }
   int count = 0;
   for (E other : commonEdgeSet) {
     if (e.equals(other) == false) {
       edge_index.put(other, count);
       count++;
     }
   }
   edge_index.put(e, count);
   return count;
 }
  protected void computeBetweenness(Queue<V> queue, Transformer<E, ? extends Number> edge_weights) {
    for (V v : graph.getVertices()) {
      // initialize the betweenness data for this new vertex
      for (V s : graph.getVertices()) this.vertex_data.put(s, new BetweennessData());

      // if (v.equals(new Integer(0)))
      // System.out.println("pause");

      vertex_data.get(v).numSPs = 1;
      vertex_data.get(v).distance = 0;

      Stack<V> stack = new Stack<V>();
      // Buffer<V> queue = new UnboundedFifoBuffer<V>();
      // queue.add(v);
      queue.offer(v);

      while (!queue.isEmpty()) {
        // V w = queue.remove();
        V w = queue.poll();
        stack.push(w);
        BetweennessData w_data = vertex_data.get(w);

        for (E e : graph.getOutEdges(w)) {
          // TODO (jrtom): change this to getOtherVertices(w, e)
          V x = graph.getOpposite(w, e);
          if (x.equals(w)) continue;
          double wx_weight = edge_weights.transform(e).doubleValue();

          // for(V x : graph.getSuccessors(w))
          // {
          // if (x.equals(w))
          // continue;

          // FIXME: the other problem is that I need to
          // keep putting the neighbors of things we've just
          // discovered in the queue, if they're undiscovered or
          // at greater distance.

          // FIXME: this is the problem, right here, I think:
          // need to update position in queue if distance changes
          // (which can only happen with weighted edges).
          // for each outgoing edge e from w, get other end x
          // if x not already visited (dist x < 0)
          // set x's distance to w's dist + edge weight
          // add x to queue; pri in queue is x's dist
          // if w's dist + edge weight < x's dist
          // update x's dist
          // update x in queue (MapBinaryHeap)
          // clear x's incoming edge list
          // if w's dist + edge weight = x's dist
          // add e to x's incoming edge list

          BetweennessData x_data = vertex_data.get(x);
          double x_potential_dist = w_data.distance + wx_weight;

          if (x_data.distance < 0) {
            // queue.add(x);
            // vertex_data.get(x).distance =
            // vertex_data.get(w).distance + 1;
            x_data.distance = x_potential_dist;
            queue.offer(x);
          }

          // note:
          // (1) this can only happen with weighted edges
          // (2) x's SP count and incoming edges are updated below
          if (x_data.distance > x_potential_dist) {
            x_data.distance = x_potential_dist;
            // invalidate previously identified incoming edges
            // (we have a new shortest path distance to x)
            x_data.incomingEdges.clear();
            // update x's position in queue
            ((MapBinaryHeap<V>) queue).update(x);
          }
          // if (vertex_data.get(x).distance ==
          // vertex_data.get(w).distance + 1)
          //
          // if (x_data.distance == x_potential_dist)
          // {
          // x_data.numSPs += w_data.numSPs;
          //// vertex_data.get(x).predecessors.add(w);
          // x_data.incomingEdges.add(e);
          // }
        }
        for (E e : graph.getOutEdges(w)) {
          V x = graph.getOpposite(w, e);
          if (x.equals(w)) continue;
          double e_weight = edge_weights.transform(e).doubleValue();
          BetweennessData x_data = vertex_data.get(x);
          double x_potential_dist = w_data.distance + e_weight;
          if (x_data.distance == x_potential_dist) {
            x_data.numSPs += w_data.numSPs;
            // vertex_data.get(x).predecessors.add(w);
            x_data.incomingEdges.add(e);
          }
        }
      }
      while (!stack.isEmpty()) {
        V x = stack.pop();

        // for (V w : vertex_data.get(x).predecessors)
        for (E e : vertex_data.get(x).incomingEdges) {
          V w = graph.getOpposite(x, e);
          double partialDependency =
              vertex_data.get(w).numSPs
                  / vertex_data.get(x).numSPs
                  * (1.0 + vertex_data.get(x).dependency);
          vertex_data.get(w).dependency += partialDependency;
          // E w_x = graph.findEdge(w, x);
          // double w_x_score = edge_scores.get(w_x).doubleValue();
          // w_x_score += partialDependency;
          // edge_scores.put(w_x, w_x_score);
          double e_score = edge_scores.get(e).doubleValue();
          edge_scores.put(e, e_score + partialDependency);
        }
        if (!x.equals(v)) {
          double x_score = vertex_scores.get(x).doubleValue();
          x_score += vertex_data.get(x).dependency;
          vertex_scores.put(x, x_score);
        }
      }
    }

    if (graph instanceof UndirectedGraph) {
      for (V v : graph.getVertices()) {
        double v_score = vertex_scores.get(v).doubleValue();
        v_score /= 2.0;
        vertex_scores.put(v, v_score);
      }
      for (E e : graph.getEdges()) {
        double e_score = edge_scores.get(e).doubleValue();
        e_score /= 2.0;
        edge_scores.put(e, e_score);
      }
    }

    vertex_data.clear();
  }