code: public Pair<IntDiGraph, IntObjectBimap<DiEdge>> edgeGraph(boolean selfAvoiding) {
          IntDiGraph g = new IntDiGraph();
          IntObjectBimap<DiEdge> edgeToNodeMap = new IntObjectBimap<>(g.edges.size());
          edgeToNodeMap.startGrowth();
          for (DiEdge e : edges) {
              g.addNode(edgeToNodeMap.lookupIndex(e));
          }
          edgeToNodeMap.stopGrowth();
          // loop over edges
          for (Indexed<DiEdge> e : enumerate(edges)) {
              int newS = e.index();
              int oldS = e.get().get1();
              int oldT = e.get().get2();
              // loop over successors
              for (int oldV : successors.get(oldT)) {
                  // skip if self avoiding and s == v
                  if (selfAvoiding && oldS == oldV) {
                      continue;
                  }
                  int newT = edgeToNodeMap.lookupIndex(edge(oldT, oldV));
                  g.addEdge(newS, newT);
              }
          }
          return new Pair<>(g, edgeToNodeMap);
      }
docs: Returns a new graph whose nodes are the edges of this graph with and edge
  from (i,j) to (s,t) if j == s and i != t; if selfAvoiding is false, then
  i = t is allowed; the id of the nodes correspond to the position in the edgeList of this graph;
  the nodes are added in that order; edges are created in the order of the source nodes following successor pointers