Skip to content

Commit

Permalink
Add ValueGraph.edgeValues(). Remove ValueGraph.edgeValueOrDefault(nod…
Browse files Browse the repository at this point in the history
…e, node).

There's a few nice things we get out of this. An easy way to address all the values in a ValueGraph as a single collection (edgeValues().values()). An easy way to get an edge value if you're dealing with "EndpointPair"s. And if you're on Java 8+, Map has getOrDefault() plus some other nifty methods.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=131959724
  • Loading branch information
Bezier89 authored and cpovirk committed Sep 1, 2016
1 parent 5e8b9f6 commit 58f4014
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 91 deletions.
5 changes: 3 additions & 2 deletions guava-tests/test/com/google/common/graph/GraphsTest.java
Expand Up @@ -278,10 +278,11 @@ public void transpose_directedValueGraph() {
assertThat(transpose(transpose)).isSameAs(directedGraph); assertThat(transpose(transpose)).isSameAs(directedGraph);
AbstractGraphTest.validateGraph(transpose); AbstractGraphTest.validateGraph(transpose);


assertThat(transpose.edgeValueOrDefault(N1, N2, null)).isNull(); EndpointPair<Integer> pair12 = EndpointPair.ordered(N1, N2);
assertThat(transpose.edgeValues().get(pair12)).isNull();
directedGraph.putEdgeValue(N2, N1, E21); directedGraph.putEdgeValue(N2, N1, E21);
// View should be updated. // View should be updated.
assertThat(transpose.edgeValueOrDefault(N1, N2, null)).isEqualTo(E21); assertThat(transpose.edgeValues().get(pair12)).isEqualTo(E21);
AbstractGraphTest.validateGraph(transpose); AbstractGraphTest.validateGraph(transpose);
} }


Expand Down
33 changes: 24 additions & 9 deletions guava-tests/test/com/google/common/graph/ValueGraphTest.java
Expand Up @@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;


import java.util.Map;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
Expand All @@ -37,12 +38,17 @@ public void validateGraphState() {
assertThat(Graphs.equivalent(graph, Graphs.copyOf(graph))).isTrue(); assertThat(Graphs.equivalent(graph, Graphs.copyOf(graph))).isTrue();
assertThat(Graphs.equivalent(graph, ImmutableValueGraph.copyOf(graph))).isTrue(); assertThat(Graphs.equivalent(graph, ImmutableValueGraph.copyOf(graph))).isTrue();


assertThat(graph.edgeValues().keySet()).isEqualTo(graph.edges());

for (Integer node : graph.nodes()) { for (Integer node : graph.nodes()) {
for (Integer otherNode : graph.nodes()) { for (Integer otherNode : graph.nodes()) {
EndpointPair<Integer> endpointPair = EndpointPair.of(graph, node, otherNode);
if (graph.successors(node).contains(otherNode)) { if (graph.successors(node).contains(otherNode)) {
assertThat(graph.edgeValue(node, otherNode)).isNotNull(); String value = graph.edgeValue(node, otherNode);
assertThat(value).isNotNull();
assertThat(value).isEqualTo(graph.edgeValues().get(endpointPair));
} else { } else {
assertThat(graph.edgeValueOrDefault(node, otherNode, null)).isNull(); assertThat(graph.edgeValues()).doesNotContainKey(endpointPair);
} }
} }
} }
Expand Down Expand Up @@ -167,23 +173,32 @@ public void edgeValue_nodeNotPresent() {
} }


@Test @Test
public void edgeValueOrDefault() { public void edgeValues() {
graph = ValueGraphBuilder.directed().build(); graph = ValueGraphBuilder.directed().build();
Map<EndpointPair<Integer>, String> edgeValues = graph.edgeValues();
EndpointPair<Integer> pair12 = EndpointPair.ordered(1, 2);
EndpointPair<Integer> pair21 = EndpointPair.ordered(2, 1);


graph.addNode(1); graph.addNode(1);
graph.addNode(2); graph.addNode(2);
assertThat(graph.edgeValueOrDefault(1, 2, "default")).isEqualTo("default"); assertThat(edgeValues).doesNotContainKey(pair12);
assertThat(graph.edgeValueOrDefault(2, 1, "default")).isEqualTo("default"); assertThat(edgeValues).doesNotContainKey(pair21);


graph.putEdgeValue(1, 2, "valueA"); graph.putEdgeValue(1, 2, "valueA");
graph.putEdgeValue(2, 1, "valueB"); graph.putEdgeValue(2, 1, "valueB");
assertThat(graph.edgeValueOrDefault(1, 2, "default")).isEqualTo("valueA"); assertThat(edgeValues.get(pair12)).isEqualTo("valueA");
assertThat(graph.edgeValueOrDefault(2, 1, "default")).isEqualTo("valueB"); assertThat(edgeValues.get(pair21)).isEqualTo("valueB");


graph.removeEdge(1, 2); graph.removeEdge(1, 2);
graph.putEdgeValue(2, 1, "valueC"); graph.putEdgeValue(2, 1, "valueC");
assertThat(graph.edgeValueOrDefault(1, 2, "default")).isEqualTo("default"); assertThat(edgeValues).doesNotContainKey(pair12);
assertThat(graph.edgeValueOrDefault(2, 1, "default")).isEqualTo("valueC"); assertThat(edgeValues.get(pair21)).isEqualTo("valueC");

try {
edgeValues.put(pair12, "valueA");
fail("Map returned by edgeValues() should be unmodifiable");
} catch (UnsupportedOperationException expected) {
}
} }


@Test @Test
Expand Down
27 changes: 16 additions & 11 deletions guava/src/com/google/common/graph/AbstractValueGraph.java
Expand Up @@ -36,6 +36,21 @@
public abstract class AbstractValueGraph<N, V> public abstract class AbstractValueGraph<N, V>
extends AbstractGraph<N> implements ValueGraph<N, V> { extends AbstractGraph<N> implements ValueGraph<N, V> {


@Override
public Map<EndpointPair<N>, V> edgeValues() {
return edgeValues(this);
}

static <N, V> Map<EndpointPair<N>, V> edgeValues(final ValueGraph<N, V> graph) {
Function<EndpointPair<N>, V> edgeToValueFn = new Function<EndpointPair<N>, V>() {
@Override
public V apply(EndpointPair<N> edge) {
return graph.edgeValue(edge.nodeU(), edge.nodeV());
}
};
return Maps.asMap(graph.edges(), edgeToValueFn);
}

/** /**
* Returns a string representation of this graph. * Returns a string representation of this graph.
*/ */
Expand All @@ -50,16 +65,6 @@ static String toString(ValueGraph<?, ?> graph) {
return String.format(GRAPH_STRING_FORMAT, return String.format(GRAPH_STRING_FORMAT,
propertiesString, propertiesString,
graph.nodes(), graph.nodes(),
edgeValueMap(graph)); graph.edgeValues());
}

private static <N, V> Map<EndpointPair<N>, V> edgeValueMap(final ValueGraph<N, V> graph) {
Function<EndpointPair<N>, V> edgeToValueFn = new Function<EndpointPair<N>, V>() {
@Override
public V apply(EndpointPair<N> edge) {
return graph.edgeValue(edge.nodeU(), edge.nodeV());
}
};
return Maps.asMap(graph.edges(), edgeToValueFn);
} }
} }
Expand Up @@ -126,17 +126,10 @@ public Set<N> successors(Object node) {


@Override @Override
public V edgeValue(Object nodeU, Object nodeV) { public V edgeValue(Object nodeU, Object nodeV) {
V value = edgeValueOrDefault(nodeU, nodeV, null);
checkArgument(value != null, EDGE_CONNECTING_NOT_IN_GRAPH, nodeU, nodeV);
return value;
}

@Override
public V edgeValueOrDefault(Object nodeU, Object nodeV, @Nullable V defaultValue) {
V value = checkedConnections(nodeU).value(nodeV); V value = checkedConnections(nodeU).value(nodeV);
if (value == null) { if (value == null) {
checkArgument(containsNode(nodeV), NODE_NOT_IN_GRAPH, nodeV); checkArgument(containsNode(nodeV), NODE_NOT_IN_GRAPH, nodeV);
return defaultValue; throw new IllegalArgumentException(String.format(EDGE_CONNECTING_NOT_IN_GRAPH, nodeU, nodeV));
} }
return value; return value;
} }
Expand Down
10 changes: 5 additions & 5 deletions guava/src/com/google/common/graph/Graph.java
Expand Up @@ -74,12 +74,12 @@
* should prefer the non-mutating {@link Graph} interface. * should prefer the non-mutating {@link Graph} interface.
* *
* <p>We provide an efficient implementation of this interface via {@link GraphBuilder}. When using * <p>We provide an efficient implementation of this interface via {@link GraphBuilder}. When using
* the implementation provided, all {@link Set}-returning methods provide live, unmodifiable views * the implementation provided, all collection-returning methods provide live, unmodifiable views of
* of the graph. In other words, you cannot add an element to the {@link Set}, but if an element is * the graph. In other words, you cannot add an element to the collection, but if an element is
* added to the {@link Graph} that would affect the result of that set, it will be updated * added to the {@link Graph} that would affect the result of that collection, it will be updated
* automatically. This also means that you cannot modify a {@link Graph} in a way that would affect * automatically. This also means that you cannot modify a {@link Graph} in a way that would affect
* a {#link Set} while iterating over that set. For example, you cannot remove the nodes from a * a collection while iterating over that collection. For example, you cannot remove the nodes from
* {@link Graph} while iterating over {@link #nodes} (unless you first make a copy of the nodes), * a {@link Graph} while iterating over {@link #nodes} (unless you first make a copy of the nodes),
* just as you could not remove the keys from a {@link Map} while iterating over its {@link * just as you could not remove the keys from a {@link Map} while iterating over its {@link
* Map#keySet()}. This will either throw a {@link ConcurrentModificationException} or risk undefined * Map#keySet()}. This will either throw a {@link ConcurrentModificationException} or risk undefined
* behavior. * behavior.
Expand Down
23 changes: 4 additions & 19 deletions guava/src/com/google/common/graph/Graphs.java
Expand Up @@ -267,21 +267,9 @@ public static boolean equivalent(
return false; return false;
} }


// TODO(b/31166974): If we add a Map of edgeValues, we can check against that for equality. return graphA.isDirected() == graphB.isDirected()
if (graphA.isDirected() != graphB.isDirected() && graphA.nodes().equals(graphB.nodes())
|| !graphA.nodes().equals(graphB.nodes()) && graphA.edgeValues().equals(graphB.edgeValues());
|| !graphA.edges().equals(graphB.edges())) {
return false;
}

for (EndpointPair<?> edge : graphA.edges()) {
if (!graphA.edgeValue(edge.nodeU(), edge.nodeV()).equals(
graphB.edgeValue(edge.nodeU(), edge.nodeV()))) {
return false;
}
}

return true;
} }


/** /**
Expand Down Expand Up @@ -471,10 +459,7 @@ public V edgeValue(Object nodeU, Object nodeV) {
return graph.edgeValue(nodeV, nodeU); // transpose return graph.edgeValue(nodeV, nodeU); // transpose
} }


@Override // Defer to AbstractValueGraph for edgeValues() implementation based on edgeValue().
public V edgeValueOrDefault(Object nodeU, Object nodeV, V defaultValue) {
return graph.edgeValueOrDefault(nodeV, nodeU, defaultValue); // transpose
}
} }


/** /**
Expand Down
16 changes: 7 additions & 9 deletions guava/src/com/google/common/graph/ImmutableValueGraph.java
Expand Up @@ -26,7 +26,7 @@
import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import javax.annotation.Nullable; import java.util.Map;


/** /**
* A {@link ValueGraph} whose elements and structural relationships will never change. Instances of * A {@link ValueGraph} whose elements and structural relationships will never change. Instances of
Expand Down Expand Up @@ -97,21 +97,19 @@ public V apply(N successorNode) {


@Override @Override
public V edgeValue(Object nodeU, Object nodeV) { public V edgeValue(Object nodeU, Object nodeV) {
V value = edgeValueOrDefault(nodeU, nodeV, null);
checkArgument(value != null, EDGE_CONNECTING_NOT_IN_GRAPH, nodeU, nodeV);
return value;
}

@Override
public V edgeValueOrDefault(Object nodeU, Object nodeV, @Nullable V defaultValue) {
V value = backingGraph.checkedConnections(nodeU).value(nodeV); V value = backingGraph.checkedConnections(nodeU).value(nodeV);
if (value == null) { if (value == null) {
checkArgument(backingGraph.containsNode(nodeV), NODE_NOT_IN_GRAPH, nodeV); checkArgument(backingGraph.containsNode(nodeV), NODE_NOT_IN_GRAPH, nodeV);
return defaultValue; throw new IllegalArgumentException(String.format(EDGE_CONNECTING_NOT_IN_GRAPH, nodeU, nodeV));
} }
return value; return value;
} }


@Override
public Map<EndpointPair<N>, V> edgeValues() {
return AbstractValueGraph.edgeValues(this);
}

@Override @Override
public String toString() { public String toString() {
return AbstractValueGraph.toString(this); return AbstractValueGraph.toString(this);
Expand Down
18 changes: 9 additions & 9 deletions guava/src/com/google/common/graph/Network.java
Expand Up @@ -66,15 +66,15 @@
* should prefer the non-mutating {@link Network} interface. * should prefer the non-mutating {@link Network} interface.
* *
* <p>We provide an efficient implementation of this interface via {@link NetworkBuilder}. When * <p>We provide an efficient implementation of this interface via {@link NetworkBuilder}. When
* using the implementation provided, all {@link Set}-returning methods provide live, unmodifiable * using the implementation provided, all collection-returning methods provide live, unmodifiable
* views of the network. In other words, you cannot add an element to the {@link Set}, but if an * views of the network. In other words, you cannot add an element to the collection, but if an
* element is added to the {@link Network} that would affect the result of that set, it will be * element is added to the {@link Network} that would affect the result of that collection, it will
* updated automatically. This also means that you cannot modify a {@link Network} in a way that * be updated automatically. This also means that you cannot modify a {@link Network} in a way that
* would affect a {#link Set} while iterating over that set. For example, you cannot remove the * would affect a collection while iterating over that collection. For example, you cannot remove
* nodes from a {@link Network} while iterating over {@link #nodes} (unless you first make a copy of * the nodes from a {@link Network} while iterating over {@link #nodes} (unless you first make a
* the nodes), just as you could not remove the keys from a {@link Map} while iterating over its * copy of the nodes), just as you could not remove the keys from a {@link Map} while iterating over
* {@link Map#keySet()}. This will either throw a {@link ConcurrentModificationException} or risk * its {@link Map#keySet()}. This will either throw a {@link ConcurrentModificationException} or
* undefined behavior. * risk undefined behavior.
* *
* <p>Example of use: * <p>Example of use:
* *
Expand Down
31 changes: 12 additions & 19 deletions guava/src/com/google/common/graph/ValueGraph.java
Expand Up @@ -19,7 +19,6 @@
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import java.util.ConcurrentModificationException; import java.util.ConcurrentModificationException;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;


/** /**
Expand Down Expand Up @@ -74,15 +73,15 @@
* should prefer the non-mutating {@link ValueGraph} interface. * should prefer the non-mutating {@link ValueGraph} interface.
* *
* <p>We provide an efficient implementation of this interface via {@link ValueGraphBuilder}. When * <p>We provide an efficient implementation of this interface via {@link ValueGraphBuilder}. When
* using the implementation provided, all {@link Set}-returning methods provide live, unmodifiable * using the implementation provided, all collection-returning methods provide live, unmodifiable
* views of the graph. In other words, you cannot add an element to the {@link Set}, but if an * views of the graph. In other words, you cannot add an element to the collection, but if an
* element is added to the {@link ValueGraph} that would affect the result of that set, it will be * element is added to the {@link ValueGraph} that would affect the result of that collection, it
* updated automatically. This also means that you cannot modify a {@link ValueGraph} in a way that * will be updated automatically. This also means that you cannot modify a {@link ValueGraph} in a
* would affect a {#link Set} while iterating over that set. For example, you cannot remove the * way that would affect a collection while iterating over that collection. For example, you cannot
* nodes from a {@link ValueGraph} while iterating over {@link #nodes} (unless you first make a copy * remove the nodes from a {@link ValueGraph} while iterating over {@link #nodes} (unless you first
* of the nodes), just as you could not remove the keys from a {@link Map} while iterating over its * make a copy of the nodes), just as you could not remove the keys from a {@link Map} while
* {@link Map#keySet()}. This will either throw a {@link ConcurrentModificationException} or risk * iterating over its {@link Map#keySet()}. This will either throw a
* undefined behavior. * {@link ConcurrentModificationException} or risk undefined behavior.
* *
* <p>Example of use: * <p>Example of use:
* *
Expand Down Expand Up @@ -120,16 +119,10 @@ public interface ValueGraph<N, V> extends Graph<N> {
V edgeValue(Object nodeU, Object nodeV); V edgeValue(Object nodeU, Object nodeV);


/** /**
* If there is an edge connecting {@code nodeU} to {@code nodeV}, returns the non-null value * Returns a {@link Map} of all {@link #edges() edges} mapped to their associated {@link
* associated with that edge; otherwise, returns {@code defaultValue}. * #edgeValue(Object, Object) value}.
*
* <p>In an undirected graph, this is equal to {@code edgeValueOrDefault(nodeV, nodeU,
* defaultValue)}.
*
* @throws IllegalArgumentException if {@code nodeU} or {@code nodeV} is not an element of this
* graph
*/ */
V edgeValueOrDefault(Object nodeU, Object nodeV, @Nullable V defaultValue); Map<EndpointPair<N>, V> edgeValues();


// //
// ValueGraph identity // ValueGraph identity
Expand Down

0 comments on commit 58f4014

Please sign in to comment.