/** * Returns the subgraph of {@code graph} induced by {@code nodes}. This subgraph is a new graph * that contains all of the nodes in {@code nodes}, and all of the {@link Graph#edges() edges} * (and associated edge values) from {@code graph} for which both nodes are contained by {@code * nodes}. * * @throws IllegalArgumentException if any element in {@code nodes} is not a node in the graph */ public static <N, V> MutableValueGraph<N, V> inducedSubgraph( ValueGraph<N, V> graph, Iterable<? extends N> nodes) { MutableValueGraph<N, V> subgraph = (nodes instanceof Collection) ? ValueGraphBuilder.from(graph).expectedNodeCount(((Collection) nodes).size()).build() : ValueGraphBuilder.from(graph).build(); for (N node : nodes) { subgraph.addNode(node); } for (N node : subgraph.nodes()) { for (N successorNode : graph.successors(node)) { if (subgraph.nodes().contains(successorNode)) { subgraph.putEdgeValue( node, successorNode, graph.edgeValueOrDefault(node, successorNode, null)); } } } return subgraph; }
@Test public void removeEdge_undirected() { graph = ValueGraphBuilder.undirected().build(); graph.putEdgeValue(1, 2, "valueA"); graph.putEdgeValue(2, 1, "valueB"); graph.putEdgeValue(2, 3, "valueC"); assertThat(graph.removeEdge(1, 2)).isEqualTo("valueB"); assertThat(graph.removeEdge(1, 2)).isNull(); assertThat(graph.removeEdge(2, 1)).isNull(); assertThat(graph.removeEdge(2, 3)).isEqualTo("valueC"); assertThat(graph.removeEdge(2, 3)).isNull(); }
@Override public boolean removeNode(N node) { return backingValueGraph.removeNode(node); }
@Test public void directedGraph() { graph = ValueGraphBuilder.directed().allowsSelfLoops(true).build(); graph.putEdgeValue(1, 2, "valueA"); graph.putEdgeValue(2, 1, "valueB"); graph.putEdgeValue(2, 3, "valueC"); graph.putEdgeValue(4, 4, "valueD"); assertThat(graph.edgeValueOrDefault(1, 2, null)).isEqualTo("valueA"); assertThat(graph.edgeValueOrDefault(2, 1, null)).isEqualTo("valueB"); assertThat(graph.edgeValueOrDefault(2, 3, null)).isEqualTo("valueC"); assertThat(graph.edgeValueOrDefault(4, 4, null)).isEqualTo("valueD"); assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo("valueA"); assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo("valueB"); assertThat(graph.edgeValueOrDefault(2, 3, DEFAULT)).isEqualTo("valueC"); assertThat(graph.edgeValueOrDefault(4, 4, DEFAULT)).isEqualTo("valueD"); String toString = graph.toString(); assertThat(toString).contains("valueA"); assertThat(toString).contains("valueB"); assertThat(toString).contains("valueC"); assertThat(toString).contains("valueD"); }
/** Creates a mutable copy of {@code graph} with the same nodes, edges, and edge values. */ public static <N, V> MutableValueGraph<N, V> copyOf(ValueGraph<N, V> graph) { MutableValueGraph<N, V> copy = ValueGraphBuilder.from(graph).expectedNodeCount(graph.nodes().size()).build(); for (N node : graph.nodes()) { copy.addNode(node); } for (EndpointPair<N> edge : graph.edges()) { copy.putEdgeValue( edge.nodeU(), edge.nodeV(), graph.edgeValueOrDefault(edge.nodeU(), edge.nodeV(), null)); } return copy; }
@Override public boolean putEdge(N nodeU, N nodeV) { return backingValueGraph.putEdgeValue(nodeU, nodeV, Presence.EDGE_EXISTS) == null; }
@After public void validateGraphState() { assertStronglyEquivalent(graph, Graphs.copyOf(graph)); assertStronglyEquivalent(graph, ImmutableValueGraph.copyOf(graph)); Graph<Integer> asGraph = graph.asGraph(); AbstractGraphTest.validateGraph(asGraph); assertThat(graph.nodes()).isEqualTo(asGraph.nodes()); assertThat(graph.edges()).isEqualTo(asGraph.edges()); assertThat(graph.nodeOrder()).isEqualTo(asGraph.nodeOrder()); assertThat(graph.isDirected()).isEqualTo(asGraph.isDirected()); assertThat(graph.allowsSelfLoops()).isEqualTo(asGraph.allowsSelfLoops()); for (Integer node : graph.nodes()) { assertThat(graph.adjacentNodes(node)).isEqualTo(asGraph.adjacentNodes(node)); assertThat(graph.predecessors(node)).isEqualTo(asGraph.predecessors(node)); assertThat(graph.successors(node)).isEqualTo(asGraph.successors(node)); assertThat(graph.degree(node)).isEqualTo(asGraph.degree(node)); assertThat(graph.inDegree(node)).isEqualTo(asGraph.inDegree(node)); assertThat(graph.outDegree(node)).isEqualTo(asGraph.outDegree(node)); for (Integer otherNode : graph.nodes()) { boolean hasEdge = graph.hasEdgeConnecting(node, otherNode); assertThat(hasEdge).isEqualTo(asGraph.hasEdgeConnecting(node, otherNode)); assertThat(graph.edgeValueOrDefault(node, otherNode, null) != null).isEqualTo(hasEdge); assertThat(!graph.edgeValueOrDefault(node, otherNode, DEFAULT).equals(DEFAULT)) .isEqualTo(hasEdge); } } }
@Override public boolean addNode(N node) { return backingValueGraph.addNode(node); }
@Test public void edgeValue_directed_mismatch() { graph = ValueGraphBuilder.directed().build(); graph.putEdgeValue(1, 2, "A"); try { Optional<String> unused = graph.edgeValue(EndpointPair.unordered(1, 2)); unused = graph.edgeValue(EndpointPair.unordered(2, 1)); fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH); } catch (IllegalArgumentException e) { assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH); } }
@Test public void edgeValue_missing() { graph = ValueGraphBuilder.directed().build(); assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo(DEFAULT); assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo(DEFAULT); assertThat(graph.edgeValue(1, 2).orElse(DEFAULT)).isEqualTo(DEFAULT); assertThat(graph.edgeValue(2, 1).orElse(DEFAULT)).isEqualTo(DEFAULT); assertThat(graph.edgeValueOrDefault(1, 2, null)).isNull(); assertThat(graph.edgeValueOrDefault(2, 1, null)).isNull(); assertThat(graph.edgeValue(1, 2).orElse(null)).isNull(); assertThat(graph.edgeValue(2, 1).orElse(null)).isNull(); graph.putEdgeValue(1, 2, "valueA"); graph.putEdgeValue(2, 1, "valueB"); assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo("valueA"); assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo("valueB"); assertThat(graph.edgeValueOrDefault(1, 2, null)).isEqualTo("valueA"); assertThat(graph.edgeValueOrDefault(2, 1, null)).isEqualTo("valueB"); assertThat(graph.edgeValue(1, 2).get()).isEqualTo("valueA"); assertThat(graph.edgeValue(2, 1).get()).isEqualTo("valueB"); graph.removeEdge(1, 2); graph.putEdgeValue(2, 1, "valueC"); assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo(DEFAULT); assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo("valueC"); assertThat(graph.edgeValue(1, 2).orElse(DEFAULT)).isEqualTo(DEFAULT); assertThat(graph.edgeValueOrDefault(1, 2, null)).isNull(); assertThat(graph.edgeValueOrDefault(2, 1, null)).isEqualTo("valueC"); assertThat(graph.edgeValue(1, 2).orElse(null)).isNull(); assertThat(graph.edgeValue(2, 1).get()).isEqualTo("valueC"); }
@Test public void transpose_directedValueGraph() { MutableValueGraph<Integer, String> directedGraph = ValueGraphBuilder.directed().allowsSelfLoops(true).build(); directedGraph.putEdgeValue(N1, N3, E13); directedGraph.putEdgeValue(N3, N1, E31); directedGraph.putEdgeValue(N1, N2, E12); directedGraph.putEdgeValue(N1, N1, E11); directedGraph.putEdgeValue(N3, N4, E34); MutableValueGraph<Integer, String> expectedTranspose = ValueGraphBuilder.directed().allowsSelfLoops(true).build(); expectedTranspose.putEdgeValue(N3, N1, E13); expectedTranspose.putEdgeValue(N1, N3, E31); expectedTranspose.putEdgeValue(N2, N1, E12); expectedTranspose.putEdgeValue(N1, N1, E11); expectedTranspose.putEdgeValue(N4, N3, E34); ValueGraph<Integer, String> transpose = transpose(directedGraph); assertThat(transpose).isEqualTo(expectedTranspose); assertThat(transpose(transpose)).isSameAs(directedGraph); AbstractGraphTest.validateGraph(transpose.asGraph()); assertThat(transpose.edgeValueOrDefault(N1, N2, null)).isNull(); for (Integer node : directedGraph.nodes()) { assertThat(directedGraph.inDegree(node)).isSameAs(transpose.outDegree(node)); assertThat(directedGraph.outDegree(node)).isSameAs(transpose.inDegree(node)); } directedGraph.putEdgeValue(N2, N1, E21); // View should be updated. assertThat(transpose.edgeValueOrDefault(N1, N2, null)).isEqualTo(E21); AbstractGraphTest.validateGraph(transpose.asGraph()); }
@Test public void hasEdgeConnecting_directed_mismatch() { graph = ValueGraphBuilder.directed().build(); graph.putEdgeValue(1, 2, "A"); assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(1, 2))).isFalse(); assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(2, 1))).isFalse(); }
@VisibleForTesting static <T> LinkedList<T> sortTopologically(ValueGraph<T, Composition> graph) { // Kahn's algorithm MutableValueGraph<T, Composition> g = Graphs.copyOf(graph); LinkedList<T> sorted = Lists.newLinkedList(); Deque<T> leaves = Lists.newLinkedList(g.nodes() .stream() .filter(n -> g.inDegree(n) == 0) .collect(toList()) ); while (!leaves.isEmpty()) { T node = leaves.pop(); sorted.push(node); Set<T> successors = ImmutableSet.copyOf(g.successors(node)); for (T successor : successors) { g.removeEdge(node, successor); if (g.inDegree(successor) == 0) { leaves.addLast(successor); } } } checkArgument(g.edges().isEmpty(), "the graph contains a circular dependency %s", g); Collections.reverse(sorted); return sorted; }
collapsed.addNode(set); int edgeCount = collapsed.edgeValueOrDefault(partitionU, partitionV, 0); collapsed.putEdgeValue(partitionU, partitionV, edgeCount + 1);
@Override public boolean removeEdge(N nodeU, N nodeV) { return backingValueGraph.removeEdge(nodeU, nodeV) != null; }
@Override public EndpointPair<V> addEdge(V sourceVertex, V targetVertex) { assertVertexExist(sourceVertex); assertVertexExist(targetVertex); if (containsEdge(sourceVertex, targetVertex)) { return null; } if (!valueGraph.allowsSelfLoops() && sourceVertex.equals(targetVertex)) { throw new IllegalArgumentException(LOOPS_NOT_ALLOWED); } valueGraph.putEdgeValue(sourceVertex, targetVertex, defaultValue); return createEdge(sourceVertex, targetVertex); }
/** Creates a mutable copy of {@code graph} with the same nodes, edges, and edge values. */ public static <N, V> MutableValueGraph<N, V> copyOf(ValueGraph<N, V> graph) { MutableValueGraph<N, V> copy = ValueGraphBuilder.from(graph).expectedNodeCount(graph.nodes().size()).build(); for (N node : graph.nodes()) { copy.addNode(node); } for (EndpointPair<N> edge : graph.edges()) { copy.putEdgeValue( edge.nodeU(), edge.nodeV(), graph.edgeValueOrDefault(edge.nodeU(), edge.nodeV(), null)); } return copy; }
@Override public boolean putEdge(N nodeU, N nodeV) { return backingValueGraph.putEdgeValue(nodeU, nodeV, Presence.EDGE_EXISTS) == null; }
@Test public void undirectedGraph() { graph = ValueGraphBuilder.undirected().allowsSelfLoops(true).build(); graph.putEdgeValue(1, 2, "valueA"); graph.putEdgeValue(2, 1, "valueB"); // overwrites valueA in undirected case graph.putEdgeValue(2, 3, "valueC"); graph.putEdgeValue(4, 4, "valueD"); assertThat(graph.edgeValueOrDefault(1, 2, null)).isEqualTo("valueB"); assertThat(graph.edgeValueOrDefault(2, 1, null)).isEqualTo("valueB"); assertThat(graph.edgeValueOrDefault(2, 3, null)).isEqualTo("valueC"); assertThat(graph.edgeValueOrDefault(4, 4, null)).isEqualTo("valueD"); assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo("valueB"); assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo("valueB"); assertThat(graph.edgeValueOrDefault(2, 3, DEFAULT)).isEqualTo("valueC"); assertThat(graph.edgeValueOrDefault(4, 4, DEFAULT)).isEqualTo("valueD"); String toString = graph.toString(); assertThat(toString).doesNotContain("valueA"); assertThat(toString).contains("valueB"); assertThat(toString).contains("valueC"); assertThat(toString).contains("valueD"); }
@After public void validateGraphState() { assertStronglyEquivalent(graph, Graphs.copyOf(graph)); assertStronglyEquivalent(graph, ImmutableValueGraph.copyOf(graph)); Graph<Integer> asGraph = graph.asGraph(); AbstractGraphTest.validateGraph(asGraph); assertThat(graph.nodes()).isEqualTo(asGraph.nodes()); assertThat(graph.edges()).isEqualTo(asGraph.edges()); assertThat(graph.nodeOrder()).isEqualTo(asGraph.nodeOrder()); assertThat(graph.isDirected()).isEqualTo(asGraph.isDirected()); assertThat(graph.allowsSelfLoops()).isEqualTo(asGraph.allowsSelfLoops()); for (Integer node : graph.nodes()) { assertThat(graph.adjacentNodes(node)).isEqualTo(asGraph.adjacentNodes(node)); assertThat(graph.predecessors(node)).isEqualTo(asGraph.predecessors(node)); assertThat(graph.successors(node)).isEqualTo(asGraph.successors(node)); assertThat(graph.degree(node)).isEqualTo(asGraph.degree(node)); assertThat(graph.inDegree(node)).isEqualTo(asGraph.inDegree(node)); assertThat(graph.outDegree(node)).isEqualTo(asGraph.outDegree(node)); for (Integer otherNode : graph.nodes()) { boolean hasEdge = graph.hasEdgeConnecting(node, otherNode); assertThat(hasEdge).isEqualTo(asGraph.hasEdgeConnecting(node, otherNode)); assertThat(graph.edgeValueOrDefault(node, otherNode, null) != null).isEqualTo(hasEdge); assertThat(!graph.edgeValueOrDefault(node, otherNode, DEFAULT).equals(DEFAULT)) .isEqualTo(hasEdge); } } }