code: func (g *AcyclicGraph) TransitiveReduction() {
  	// For each vertex u in graph g, do a DFS starting from each vertex
  	// v such that the edge (u,v) exists (v is a direct descendant of u).
  	//
  	// For each v-prime reachable from v, remove the edge (u, v-prime).
  	defer g.debug.BeginOperation("TransitiveReduction", "").End("")
  
  	for _, u := range g.Vertices() {
  		uTargets := g.DownEdges(u)
  		vs := AsVertexList(g.DownEdges(u))
  
  		g.depthFirstWalk(vs, false, func(v Vertex, d int) error {
  			shared := uTargets.Intersection(g.DownEdges(v))
  			for _, vPrime := range AsVertexList(shared) {
  				g.RemoveEdge(BasicEdge(u, vPrime))
  			}
  
  			return nil
  		})
  	}
  }
docs: // TransitiveReduction performs the transitive reduction of graph g in place.
  // The transitive reduction of a graph is a graph with as few edges as
  // possible with the same reachability as the original graph. This means
  // that if there are three nodes A => B => C, and A connects to both
  // B and C, and B connects to C, then the transitive reduction is the
  // same graph with only a single edge between A and B, and a single edge
  // between B and C.
  //
  // The graph must be valid for this operation to behave properly. If
  // Validate() returns an error, the behavior is undefined and the results
  // will likely be unexpected.
  //
  // Complexity: O(V(V+E)), or asymptotically O(VE)