public Graph<T> reduce(Graph<T> g) {
        boolean subgraph = nodes.containsAll(g.nodes) &&
                g.edges.keySet().stream()
                       .allMatch(u -> adjacentNodes(u).containsAll(g.adjacentNodes(u)));
        if (!subgraph) {
            throw new IllegalArgumentException(g + " is not a subgraph of " + this);
        }

        Builder<T> builder = new Builder<>();
        nodes.stream()
                .forEach(u -> {
                    builder.addNode(u);
                    // filter the edge if there exists a path from u to v in the given g
                    // or there exists another path from u to v in this graph
                    edges.get(u).stream()
                         .filter(v -> !g.pathExists(u, v) && !pathExists(u, v, false))
                         .forEach(v -> builder.addEdge(u, v));
                });

        // add the overlapped edges from this graph and the given g
        g.edges().keySet().stream()
                .forEach(u -> g.adjacentNodes(u).stream()
                                .filter(v -> isAdjacent(u, v))
                                .forEach(v -> builder.addEdge(u, v)));
        return builder.build().reduce();
    }
public Graph < T > reduce ( Graph < T > g ) { boolean subgraph = nodes . containsAll ( g . nodes ) && g . edges . keySet ( ) . stream ( ) . allMatch ( u -> adjacentNodes ( u ) . containsAll ( g . adjacentNodes ( u ) ) ) ; if ( ! subgraph ) { throw new IllegalArgumentException ( g + " is not a subgraph of " + this ) ; } Builder < T > builder = new Builder < > ( ) ; nodes . stream ( ) . forEach ( u -> { builder . addNode ( u ) ; edges . get ( u ) . stream ( ) . filter ( v -> ! g . pathExists ( u , v ) && ! pathExists ( u , v , false ) ) . forEach ( v -> builder . addEdge ( u , v ) ) ; } ) ; g . edges ( ) . keySet ( ) . stream ( ) . forEach ( u -> g . adjacentNodes ( u ) . stream ( ) . filter ( v -> isAdjacent ( u , v ) ) . forEach ( v -> builder . addEdge ( u , v ) ) ) ; return builder . build ( ) . reduce ( ) ; }
Returns a new Graph after transitive reduction.  All edges in
the given g takes precedence over this graph.

@throw IllegalArgumentException g must be a subgraph this graph