Showing
16 changed files
with
373 additions
and
143 deletions
... | @@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
15 | * @param <V> vertex type | 15 | * @param <V> vertex type |
16 | * @param <E> edge type | 16 | * @param <E> edge type |
17 | */ | 17 | */ |
18 | -public abstract class AbstractPathSearch<V extends Vertex, E extends Edge<V>> | 18 | +public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V>> |
19 | implements GraphPathSearch<V, E> { | 19 | implements GraphPathSearch<V, E> { |
20 | 20 | ||
21 | private double samenessThreshold = 0.000000001; | 21 | private double samenessThreshold = 0.000000001; | ... | ... |
1 | +package org.onlab.graph; | ||
2 | + | ||
3 | +import java.util.HashSet; | ||
4 | +import java.util.Set; | ||
5 | + | ||
6 | +/** | ||
7 | + * Implementation of the BFS algorithm. | ||
8 | + */ | ||
9 | +public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>> | ||
10 | + extends AbstractGraphPathSearch<V, E> { | ||
11 | + | ||
12 | + @Override | ||
13 | + public Result<V, E> search(Graph<V, E> graph, V src, V dst, EdgeWeight<V, E> ew) { | ||
14 | + checkArguments(graph, src, dst); | ||
15 | + | ||
16 | + // Prepare the graph result. | ||
17 | + DefaultResult result = new DefaultResult(src, dst); | ||
18 | + | ||
19 | + // Setup the starting frontier with the source as the sole vertex. | ||
20 | + Set<V> frontier = new HashSet<>(); | ||
21 | + result.costs.put(src, 0.0); | ||
22 | + frontier.add(src); | ||
23 | + | ||
24 | + search: while (!frontier.isEmpty()) { | ||
25 | + // Prepare the next frontier. | ||
26 | + Set<V> next = new HashSet<>(); | ||
27 | + | ||
28 | + // Visit all vertexes in the current frontier. | ||
29 | + for (V vertex : frontier) { | ||
30 | + double cost = result.cost(vertex); | ||
31 | + | ||
32 | + // Visit all egress edges of the current frontier vertex. | ||
33 | + for (E edge : graph.getEdgesFrom(vertex)) { | ||
34 | + V nextVertex = edge.dst(); | ||
35 | + if (!result.hasCost(nextVertex)) { | ||
36 | + // If this vertex has not been visited yet, update it. | ||
37 | + result.updateVertex(nextVertex, edge, | ||
38 | + cost + (ew == null ? 1.0 : ew.weight(edge)), | ||
39 | + true); | ||
40 | + // If we have reached our intended destination, bail. | ||
41 | + if (nextVertex.equals(dst)) | ||
42 | + break search; | ||
43 | + next.add(nextVertex); | ||
44 | + } | ||
45 | + } | ||
46 | + } | ||
47 | + | ||
48 | + // Promote the next frontier. | ||
49 | + frontier = next; | ||
50 | + } | ||
51 | + | ||
52 | + // Finally, but the paths on the search result and return. | ||
53 | + result.buildPaths(); | ||
54 | + return result; | ||
55 | + } | ||
56 | + | ||
57 | +} |
... | @@ -14,8 +14,6 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -14,8 +14,6 @@ import static com.google.common.base.Preconditions.checkNotNull; |
14 | */ | 14 | */ |
15 | public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements MutablePath<V, E> { | 15 | public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements MutablePath<V, E> { |
16 | 16 | ||
17 | - private V src = null; | ||
18 | - private V dst = null; | ||
19 | private final List<E> edges = new ArrayList<>(); | 17 | private final List<E> edges = new ArrayList<>(); |
20 | private double cost = 0.0; | 18 | private double cost = 0.0; |
21 | 19 | ||
... | @@ -32,20 +30,18 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements | ... | @@ -32,20 +30,18 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements |
32 | */ | 30 | */ |
33 | public DefaultMutablePath(Path<V, E> path) { | 31 | public DefaultMutablePath(Path<V, E> path) { |
34 | checkNotNull(path, "Path cannot be null"); | 32 | checkNotNull(path, "Path cannot be null"); |
35 | - this.src = path.src(); | ||
36 | - this.dst = path.dst(); | ||
37 | this.cost = path.cost(); | 33 | this.cost = path.cost(); |
38 | edges.addAll(path.edges()); | 34 | edges.addAll(path.edges()); |
39 | } | 35 | } |
40 | 36 | ||
41 | @Override | 37 | @Override |
42 | public V src() { | 38 | public V src() { |
43 | - return src; | 39 | + return edges.isEmpty() ? null : edges.get(0).src(); |
44 | } | 40 | } |
45 | 41 | ||
46 | @Override | 42 | @Override |
47 | public V dst() { | 43 | public V dst() { |
48 | - return dst; | 44 | + return edges.isEmpty() ? null : edges.get(edges.size() - 1).dst(); |
49 | } | 45 | } |
50 | 46 | ||
51 | @Override | 47 | @Override |
... | @@ -69,28 +65,35 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements | ... | @@ -69,28 +65,35 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements |
69 | } | 65 | } |
70 | 66 | ||
71 | @Override | 67 | @Override |
68 | + public void insertEdge(E edge) { | ||
69 | + checkNotNull(edge, "Edge cannot be null"); | ||
70 | + checkArgument(edges.isEmpty() || src().equals(edge.dst()), | ||
71 | + "Edge destination must be the same as the current path source"); | ||
72 | + edges.add(0, edge); | ||
73 | + } | ||
74 | + | ||
75 | + @Override | ||
72 | public void appendEdge(E edge) { | 76 | public void appendEdge(E edge) { |
73 | checkNotNull(edge, "Edge cannot be null"); | 77 | checkNotNull(edge, "Edge cannot be null"); |
74 | - checkArgument(edges.isEmpty() || dst.equals(edge.src()), | 78 | + checkArgument(edges.isEmpty() || dst().equals(edge.src()), |
75 | "Edge source must be the same as the current path destination"); | 79 | "Edge source must be the same as the current path destination"); |
76 | - dst = edge.dst(); | ||
77 | edges.add(edge); | 80 | edges.add(edge); |
78 | } | 81 | } |
79 | 82 | ||
80 | @Override | 83 | @Override |
81 | - public void insertEdge(E edge) { | 84 | + public void removeEdge(E edge) { |
82 | - checkNotNull(edge, "Edge cannot be null"); | 85 | + checkArgument(edge.src().equals(edge.dst()) || |
83 | - checkArgument(edges.isEmpty() || src.equals(edge.dst()), | 86 | + edges.indexOf(edge) == 0 || |
84 | - "Edge destination must be the same as the current path source"); | 87 | + edges.lastIndexOf(edge) == edges.size() - 1, |
85 | - src = edge.src(); | 88 | + "Edge must be at start or end of path, or it must be a cyclic edge"); |
86 | - edges.add(0, edge); | 89 | + edges.remove(edge); |
87 | } | 90 | } |
88 | 91 | ||
89 | @Override | 92 | @Override |
90 | public String toString() { | 93 | public String toString() { |
91 | return com.google.common.base.Objects.toStringHelper(this) | 94 | return com.google.common.base.Objects.toStringHelper(this) |
92 | - .add("src", src) | 95 | + .add("src", src()) |
93 | - .add("dst", dst) | 96 | + .add("dst", dst()) |
94 | .add("cost", cost) | 97 | .add("cost", cost) |
95 | .add("edges", edges) | 98 | .add("edges", edges) |
96 | .toString(); | 99 | .toString(); |
... | @@ -98,19 +101,17 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements | ... | @@ -98,19 +101,17 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements |
98 | 101 | ||
99 | @Override | 102 | @Override |
100 | public int hashCode() { | 103 | public int hashCode() { |
101 | - return Objects.hash(src, dst, edges, cost); | 104 | + return Objects.hash(edges, cost); |
102 | } | 105 | } |
103 | 106 | ||
104 | @Override | 107 | @Override |
105 | public boolean equals(Object obj) { | 108 | public boolean equals(Object obj) { |
106 | if (obj instanceof DefaultMutablePath) { | 109 | if (obj instanceof DefaultMutablePath) { |
107 | final DefaultMutablePath other = (DefaultMutablePath) obj; | 110 | final DefaultMutablePath other = (DefaultMutablePath) obj; |
108 | - return super.equals(obj) && | 111 | + return Objects.equals(this.cost, other.cost) && |
109 | - Objects.equals(this.src, other.src) && | ||
110 | - Objects.equals(this.dst, other.dst) && | ||
111 | - Objects.equals(this.cost, other.cost) && | ||
112 | Objects.equals(this.edges, other.edges); | 112 | Objects.equals(this.edges, other.edges); |
113 | } | 113 | } |
114 | return false; | 114 | return false; |
115 | } | 115 | } |
116 | + | ||
116 | } | 117 | } | ... | ... |
... | @@ -73,8 +73,7 @@ public class DefaultPath<V extends Vertex, E extends Edge<V>> implements Path<V, | ... | @@ -73,8 +73,7 @@ public class DefaultPath<V extends Vertex, E extends Edge<V>> implements Path<V, |
73 | public boolean equals(Object obj) { | 73 | public boolean equals(Object obj) { |
74 | if (obj instanceof DefaultPath) { | 74 | if (obj instanceof DefaultPath) { |
75 | final DefaultPath other = (DefaultPath) obj; | 75 | final DefaultPath other = (DefaultPath) obj; |
76 | - return super.equals(obj) && | 76 | + return Objects.equals(this.src, other.src) && |
77 | - Objects.equals(this.src, other.src) && | ||
78 | Objects.equals(this.dst, other.dst) && | 77 | Objects.equals(this.dst, other.dst) && |
79 | Objects.equals(this.cost, other.cost) && | 78 | Objects.equals(this.cost, other.cost) && |
80 | Objects.equals(this.edges, other.edges); | 79 | Objects.equals(this.edges, other.edges); | ... | ... |
... | @@ -9,7 +9,7 @@ import java.util.Set; | ... | @@ -9,7 +9,7 @@ import java.util.Set; |
9 | * one, but all shortest paths between the source and destinations. | 9 | * one, but all shortest paths between the source and destinations. |
10 | */ | 10 | */ |
11 | public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>> | 11 | public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>> |
12 | - extends AbstractPathSearch<V, E> { | 12 | + extends AbstractGraphPathSearch<V, E> { |
13 | 13 | ||
14 | @Override | 14 | @Override |
15 | public Result<V, E> search(Graph<V, E> g, V src, V dst, EdgeWeight<V, E> ew) { | 15 | public Result<V, E> search(Graph<V, E> g, V src, V dst, EdgeWeight<V, E> ew) { | ... | ... |
... | @@ -22,6 +22,15 @@ public interface MutablePath<V extends Vertex, E extends Edge<V>> extends Path<V | ... | @@ -22,6 +22,15 @@ public interface MutablePath<V extends Vertex, E extends Edge<V>> extends Path<V |
22 | void appendEdge(E edge); | 22 | void appendEdge(E edge); |
23 | 23 | ||
24 | /** | 24 | /** |
25 | + * Removes the specified edge. This edge must be either at the start or | ||
26 | + * at the end of the path, or it must be a cyclic edge in order not to | ||
27 | + * violate the contiguous path property. | ||
28 | + * | ||
29 | + * @param edge edge to be removed | ||
30 | + */ | ||
31 | + void removeEdge(E edge); | ||
32 | + | ||
33 | + /** | ||
25 | * Sets the total path cost as a unit-less double. | 34 | * Sets the total path cost as a unit-less double. |
26 | * | 35 | * |
27 | * @param cost new path cost | 36 | * @param cost new path cost | ... | ... |
1 | package org.onlab.graph; | 1 | package org.onlab.graph; |
2 | 2 | ||
3 | -import com.google.common.collect.ImmutableSet; | ||
4 | import org.junit.Test; | 3 | import org.junit.Test; |
5 | 4 | ||
5 | +import static com.google.common.collect.ImmutableSet.of; | ||
6 | +import static org.junit.Assert.assertEquals; | ||
7 | + | ||
6 | /** | 8 | /** |
7 | * Base for all graph search tests. | 9 | * Base for all graph search tests. |
8 | */ | 10 | */ |
9 | -public abstract class AbstractGraphSearchTest extends GraphTest { | 11 | +public abstract class AbstractGraphPathSearchTest extends GraphTest { |
10 | 12 | ||
11 | /** | 13 | /** |
12 | - * Creates a graph search to be tested. | 14 | + * Creates a test-specific graph search to exercise. |
13 | * | 15 | * |
14 | * @return graph search | 16 | * @return graph search |
15 | */ | 17 | */ |
16 | - protected abstract GraphPathSearch<TestVertex, TestEdge> graphSearch(); | 18 | + protected abstract AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch(); |
17 | 19 | ||
18 | @Test(expected = IllegalArgumentException.class) | 20 | @Test(expected = IllegalArgumentException.class) |
19 | - public void badSource() { | 21 | + public void noSuchSourceArgument() { |
20 | - graphSearch().search(new AdjacencyListsGraph<>(ImmutableSet.of(B, C), | 22 | + graphSearch().search(new AdjacencyListsGraph<>(of(B, C), |
21 | - ImmutableSet.of(new TestEdge(B, C, 1))), | 23 | + of(new TestEdge(B, C, 1))), |
22 | A, H, weight); | 24 | A, H, weight); |
23 | } | 25 | } |
24 | 26 | ||
25 | @Test(expected = NullPointerException.class) | 27 | @Test(expected = NullPointerException.class) |
26 | - public void nullSource() { | 28 | + public void nullGraphArgument() { |
27 | - graphSearch().search(new AdjacencyListsGraph<>(ImmutableSet.of(B, C), | 29 | + graphSearch().search(null, A, H, weight); |
28 | - ImmutableSet.of(new TestEdge(B, C, 1))), | ||
29 | - null, H, weight); | ||
30 | } | 30 | } |
31 | 31 | ||
32 | @Test(expected = NullPointerException.class) | 32 | @Test(expected = NullPointerException.class) |
33 | - public void nullGraph() { | 33 | + public void nullSourceArgument() { |
34 | - graphSearch().search(null, A, H, weight); | 34 | + graphSearch().search(new AdjacencyListsGraph<>(of(B, C), |
35 | + of(new TestEdge(B, C, 1))), | ||
36 | + null, H, weight); | ||
37 | + } | ||
38 | + | ||
39 | + @Test | ||
40 | + public void samenessThreshold() { | ||
41 | + AbstractGraphPathSearch<TestVertex, TestEdge> search = graphSearch(); | ||
42 | + search.setSamenessThreshold(0.3); | ||
43 | + assertEquals("incorrect threshold", 0.3, search.samenessThreshold(), 0.01); | ||
35 | } | 44 | } |
36 | 45 | ||
37 | } | 46 | } | ... | ... |
... | @@ -22,22 +22,9 @@ public class AdjacencyListsGraphTest { | ... | @@ -22,22 +22,9 @@ public class AdjacencyListsGraphTest { |
22 | private static final TestVertex G = new TestVertex("G"); | 22 | private static final TestVertex G = new TestVertex("G"); |
23 | 23 | ||
24 | private final Set<TestEdge> edges = | 24 | private final Set<TestEdge> edges = |
25 | - ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(A, C, 1), | 25 | + ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(B, C, 1), |
26 | - new TestEdge(B, C, 1), new TestEdge(C, D, 1), | 26 | + new TestEdge(C, D, 1), new TestEdge(D, A, 1), |
27 | - new TestEdge(D, A, 1)); | 27 | + new TestEdge(B, D, 1)); |
28 | - | ||
29 | - @Test | ||
30 | - public void basics() { | ||
31 | - Set<TestVertex> vertexes = ImmutableSet.of(A, B, C, D, E, F); | ||
32 | - AdjacencyListsGraph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(vertexes, edges); | ||
33 | - assertEquals("incorrect vertex count", 6, graph.getVertexes().size()); | ||
34 | - assertEquals("incorrect edge count", 5, graph.getEdges().size()); | ||
35 | - | ||
36 | - assertEquals("incorrect egress edge count", 2, graph.getEdgesFrom(A).size()); | ||
37 | - assertEquals("incorrect ingress edge count", 1, graph.getEdgesTo(A).size()); | ||
38 | - assertEquals("incorrect ingress edge count", 2, graph.getEdgesTo(C).size()); | ||
39 | - assertEquals("incorrect egress edge count", 1, graph.getEdgesFrom(C).size()); | ||
40 | - } | ||
41 | 28 | ||
42 | @Test | 29 | @Test |
43 | public void equality() { | 30 | public void equality() { |
... | @@ -53,4 +40,18 @@ public class AdjacencyListsGraphTest { | ... | @@ -53,4 +40,18 @@ public class AdjacencyListsGraphTest { |
53 | .addEqualityGroup(different) | 40 | .addEqualityGroup(different) |
54 | .testEquals(); | 41 | .testEquals(); |
55 | } | 42 | } |
43 | + | ||
44 | + @Test | ||
45 | + public void basics() { | ||
46 | + Set<TestVertex> vertexes = ImmutableSet.of(A, B, C, D, E, F); | ||
47 | + AdjacencyListsGraph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(vertexes, edges); | ||
48 | + assertEquals("incorrect vertex count", 6, graph.getVertexes().size()); | ||
49 | + assertEquals("incorrect edge count", 5, graph.getEdges().size()); | ||
50 | + | ||
51 | + assertEquals("incorrect egress edge count", 1, graph.getEdgesFrom(A).size()); | ||
52 | + assertEquals("incorrect ingress edge count", 1, graph.getEdgesTo(A).size()); | ||
53 | + assertEquals("incorrect ingress edge count", 1, graph.getEdgesTo(C).size()); | ||
54 | + assertEquals("incorrect egress edge count", 2, graph.getEdgesFrom(B).size()); | ||
55 | + assertEquals("incorrect ingress edge count", 2, graph.getEdgesTo(D).size()); | ||
56 | + } | ||
56 | } | 57 | } | ... | ... |
... | @@ -7,27 +7,28 @@ import java.util.Set; | ... | @@ -7,27 +7,28 @@ import java.util.Set; |
7 | import static org.junit.Assert.assertEquals; | 7 | import static org.junit.Assert.assertEquals; |
8 | 8 | ||
9 | /** | 9 | /** |
10 | - * Test of the BFS algorithm. | 10 | + * Test of the BFS and similar path search algorithms. |
11 | */ | 11 | */ |
12 | -public abstract class BreadthFirstSearchTest extends AbstractGraphSearchTest { | 12 | +public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest { |
13 | 13 | ||
14 | @Override | 14 | @Override |
15 | - protected GraphPathSearch<TestVertex, TestEdge> graphSearch() { | 15 | + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { |
16 | - return null; // new BreadthFirstSearch(); | 16 | + return new BreadthFirstSearch<>(); |
17 | } | 17 | } |
18 | 18 | ||
19 | @Test | 19 | @Test |
20 | - public void basics() { | 20 | + public void defaultGraphTest() { |
21 | - runBasics(3, 8.0, 7); | 21 | + executeDefaultTest(7, 3, 8.0); |
22 | } | 22 | } |
23 | 23 | ||
24 | @Test | 24 | @Test |
25 | - public void defaultWeight() { | 25 | + public void defaultHopCountWeight() { |
26 | weight = null; | 26 | weight = null; |
27 | - runBasics(3, 3.0, 7); | 27 | + executeDefaultTest(7, 3, 3.0); |
28 | } | 28 | } |
29 | 29 | ||
30 | - protected void runBasics(int expectedLength, double expectedCost, int expectedPaths) { | 30 | + // Executes the default test |
31 | + protected void executeDefaultTest(int pathCount, int pathLength, double pathCost) { | ||
31 | g = new AdjacencyListsGraph<>(vertices(), edges()); | 32 | g = new AdjacencyListsGraph<>(vertices(), edges()); |
32 | 33 | ||
33 | GraphPathSearch<TestVertex, TestEdge> search = graphSearch(); | 34 | GraphPathSearch<TestVertex, TestEdge> search = graphSearch(); |
... | @@ -37,12 +38,29 @@ public abstract class BreadthFirstSearchTest extends AbstractGraphSearchTest { | ... | @@ -37,12 +38,29 @@ public abstract class BreadthFirstSearchTest extends AbstractGraphSearchTest { |
37 | Path p = paths.iterator().next(); | 38 | Path p = paths.iterator().next(); |
38 | assertEquals("incorrect src", A, p.src()); | 39 | assertEquals("incorrect src", A, p.src()); |
39 | assertEquals("incorrect dst", H, p.dst()); | 40 | assertEquals("incorrect dst", H, p.dst()); |
40 | - assertEquals("incorrect path length", expectedLength, p.edges().size()); | 41 | + assertEquals("incorrect path length", pathLength, p.edges().size()); |
41 | - assertEquals("incorrect path cost", expectedCost, p.cost(), 0.1); | 42 | + assertEquals("incorrect path cost", pathCost, p.cost(), 0.1); |
42 | 43 | ||
43 | paths = search.search(g, A, null, weight).paths(); | 44 | paths = search.search(g, A, null, weight).paths(); |
44 | printPaths(paths); | 45 | printPaths(paths); |
45 | - assertEquals("incorrect paths count", expectedPaths, paths.size()); | 46 | + assertEquals("incorrect paths count", pathCount, paths.size()); |
47 | + } | ||
48 | + | ||
49 | + // Executes the search and validates its results. | ||
50 | + protected void executeSearch(GraphPathSearch<TestVertex, TestEdge> search, | ||
51 | + Graph<TestVertex, TestEdge> graph, | ||
52 | + TestVertex src, TestVertex dst, | ||
53 | + EdgeWeight<TestVertex, TestEdge> weight, | ||
54 | + int pathCount, double pathCost) { | ||
55 | + GraphPathSearch.Result<TestVertex, TestEdge> result = | ||
56 | + search.search(graph, src, dst, weight); | ||
57 | + Set<Path<TestVertex, TestEdge>> paths = result.paths(); | ||
58 | + printPaths(paths); | ||
59 | + assertEquals("incorrect paths count", pathCount, paths.size()); | ||
60 | + if (pathCount > 0) { | ||
61 | + Path<TestVertex, TestEdge> path = paths.iterator().next(); | ||
62 | + assertEquals("incorrect path cost", pathCost, path.cost(), 0.1); | ||
63 | + } | ||
46 | } | 64 | } |
47 | 65 | ||
48 | } | 66 | } | ... | ... |
1 | +package org.onlab.graph; | ||
2 | + | ||
3 | +import com.google.common.collect.ImmutableList; | ||
4 | +import com.google.common.testing.EqualsTester; | ||
5 | +import org.junit.Test; | ||
6 | + | ||
7 | +import java.util.Iterator; | ||
8 | +import java.util.List; | ||
9 | + | ||
10 | +import static com.google.common.collect.ImmutableList.of; | ||
11 | +import static org.junit.Assert.assertEquals; | ||
12 | +import static org.junit.Assert.assertNull; | ||
13 | + | ||
14 | +/** | ||
15 | + * Test of the default mutable path. | ||
16 | + */ | ||
17 | +public class DefaultMutablePathTest extends DefaultPathTest { | ||
18 | + | ||
19 | + @Test | ||
20 | + public void equality() { | ||
21 | + DefaultPath<TestVertex, TestEdge> p1 = | ||
22 | + new DefaultPath<>(of(new TestEdge(A, B, 1), | ||
23 | + new TestEdge(B, C, 1)), 2.0); | ||
24 | + DefaultPath<TestVertex, TestEdge> p2 = | ||
25 | + new DefaultPath<>(of(new TestEdge(A, B, 1), | ||
26 | + new TestEdge(B, D, 1)), 2.0); | ||
27 | + new EqualsTester().addEqualityGroup(new DefaultMutablePath<>(p1), | ||
28 | + new DefaultMutablePath<>(p1)) | ||
29 | + .addEqualityGroup(new DefaultMutablePath<>(p2)) | ||
30 | + .testEquals(); | ||
31 | + } | ||
32 | + | ||
33 | + @Test | ||
34 | + public void empty() { | ||
35 | + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); | ||
36 | + assertNull("src should be null", p.src()); | ||
37 | + assertNull("dst should be null", p.dst()); | ||
38 | + assertEquals("incorrect edge count", 0, p.edges().size()); | ||
39 | + assertEquals("incorrect path cost", 0.0, p.cost(), 0.1); | ||
40 | + } | ||
41 | + | ||
42 | + @Test | ||
43 | + public void pathCost() { | ||
44 | + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); | ||
45 | + p.setCost(4); | ||
46 | + assertEquals("incorrect path cost", 4.0, p.cost(), 0.1); | ||
47 | + } | ||
48 | + | ||
49 | + private void validatePath(Path<TestVertex, TestEdge> p, | ||
50 | + TestVertex src, TestVertex dst, int length) { | ||
51 | + validatePath(p, src, dst, length, 0.0); | ||
52 | + } | ||
53 | + | ||
54 | + @Test | ||
55 | + public void insertEdge() { | ||
56 | + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); | ||
57 | + p.insertEdge(new TestEdge(B, C, 1)); | ||
58 | + p.insertEdge(new TestEdge(A, B, 1)); | ||
59 | + validatePath(p, A, C, 2); | ||
60 | + } | ||
61 | + | ||
62 | + @Test | ||
63 | + public void appendEdge() { | ||
64 | + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); | ||
65 | + p.appendEdge(new TestEdge(A, B, 1)); | ||
66 | + p.appendEdge(new TestEdge(B, C, 1)); | ||
67 | + validatePath(p, A, C, 2); | ||
68 | + } | ||
69 | + | ||
70 | + @Test | ||
71 | + public void removeEdge() { | ||
72 | + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); | ||
73 | + p.appendEdge(new TestEdge(A, B, 1)); | ||
74 | + p.appendEdge(new TestEdge(B, C, 1)); | ||
75 | + p.appendEdge(new TestEdge(C, C, 2)); | ||
76 | + p.appendEdge(new TestEdge(C, D, 1)); | ||
77 | + validatePath(p, A, D, 4); | ||
78 | + | ||
79 | + p.removeEdge(new TestEdge(A, B, 1)); | ||
80 | + validatePath(p, B, D, 3); | ||
81 | + | ||
82 | + p.removeEdge(new TestEdge(C, C, 2)); | ||
83 | + validatePath(p, B, D, 2); | ||
84 | + | ||
85 | + p.removeEdge(new TestEdge(C, D, 1)); | ||
86 | + validatePath(p, B, C, 1); | ||
87 | + } | ||
88 | + | ||
89 | + @Test | ||
90 | + public void toImmutable() { | ||
91 | + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>(); | ||
92 | + p.appendEdge(new TestEdge(A, B, 1)); | ||
93 | + p.appendEdge(new TestEdge(B, C, 1)); | ||
94 | + validatePath(p, A, C, 2); | ||
95 | + | ||
96 | + assertEquals("immutables should equal", p.toImmutable(), p.toImmutable()); | ||
97 | + validatePath(p.toImmutable(), A, C, 2); | ||
98 | + } | ||
99 | +} |
1 | +package org.onlab.graph; | ||
2 | + | ||
3 | +import com.google.common.collect.ImmutableList; | ||
4 | +import com.google.common.testing.EqualsTester; | ||
5 | +import org.junit.Test; | ||
6 | + | ||
7 | +import java.util.List; | ||
8 | + | ||
9 | +import static com.google.common.collect.ImmutableList.of; | ||
10 | +import static org.junit.Assert.assertEquals; | ||
11 | +import static org.junit.Assert.assertNull; | ||
12 | + | ||
13 | +/** | ||
14 | + * Test of the default path. | ||
15 | + */ | ||
16 | +public class DefaultPathTest extends GraphTest { | ||
17 | + | ||
18 | + @Test | ||
19 | + public void equality() { | ||
20 | + List<TestEdge> edges = of(new TestEdge(A, B, 1), new TestEdge(B, C, 1)); | ||
21 | + new EqualsTester().addEqualityGroup(new DefaultPath<>(edges, 2.0), | ||
22 | + new DefaultPath<>(edges, 2.0)) | ||
23 | + .addEqualityGroup(new DefaultPath<>(edges, 3.0)) | ||
24 | + .testEquals(); | ||
25 | + } | ||
26 | + | ||
27 | + @Test | ||
28 | + public void basics() { | ||
29 | + Path<TestVertex, TestEdge> p = new DefaultPath<>(of(new TestEdge(A, B, 1), | ||
30 | + new TestEdge(B, C, 1)), 2.0); | ||
31 | + validatePath(p, A, C, 2, 2.0); | ||
32 | + } | ||
33 | + | ||
34 | + // Validates the path against expected attributes | ||
35 | + protected void validatePath(Path<TestVertex, TestEdge> p, | ||
36 | + TestVertex src, TestVertex dst, | ||
37 | + int length, double cost) { | ||
38 | + assertEquals("incorrect path length", length, p.edges().size()); | ||
39 | + assertEquals("incorrect source", src, p.src()); | ||
40 | + assertEquals("incorrect destination", dst, p.dst()); | ||
41 | + assertEquals("incorrect path cost", cost, p.cost(), 0.1); | ||
42 | + } | ||
43 | + | ||
44 | +} |
1 | package org.onlab.graph; | 1 | package org.onlab.graph; |
2 | 2 | ||
3 | -import com.google.common.collect.ImmutableSet; | ||
4 | import org.junit.Test; | 3 | import org.junit.Test; |
5 | 4 | ||
6 | import java.util.Set; | 5 | import java.util.Set; |
7 | 6 | ||
7 | +import static com.google.common.collect.ImmutableSet.of; | ||
8 | import static org.junit.Assert.assertEquals; | 8 | import static org.junit.Assert.assertEquals; |
9 | 9 | ||
10 | /** | 10 | /** |
... | @@ -13,30 +13,30 @@ import static org.junit.Assert.assertEquals; | ... | @@ -13,30 +13,30 @@ import static org.junit.Assert.assertEquals; |
13 | public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { | 13 | public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { |
14 | 14 | ||
15 | @Override | 15 | @Override |
16 | - protected GraphPathSearch<TestVertex, TestEdge> graphSearch() { | 16 | + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() { |
17 | return new DijkstraGraphSearch<>(); | 17 | return new DijkstraGraphSearch<>(); |
18 | } | 18 | } |
19 | 19 | ||
20 | @Test | 20 | @Test |
21 | @Override | 21 | @Override |
22 | - public void basics() { | 22 | + public void defaultGraphTest() { |
23 | - runBasics(5, 5.0, 7); | 23 | + executeDefaultTest(7, 5, 5.0); |
24 | } | 24 | } |
25 | 25 | ||
26 | @Test | 26 | @Test |
27 | - public void defaultWeight() { | 27 | + @Override |
28 | + public void defaultHopCountWeight() { | ||
28 | weight = null; | 29 | weight = null; |
29 | - runBasics(3, 3.0, 10); | 30 | + executeDefaultTest(10, 3, 3.0); |
30 | } | 31 | } |
31 | 32 | ||
32 | @Test | 33 | @Test |
33 | public void noPath() { | 34 | public void noPath() { |
34 | - g = new AdjacencyListsGraph<>(ImmutableSet.of(A, B, C, D), | 35 | + g = new AdjacencyListsGraph<>(of(A, B, C, D), |
35 | - ImmutableSet.of(new TestEdge(A, B, 1), | 36 | + of(new TestEdge(A, B, 1), |
36 | new TestEdge(B, A, 1), | 37 | new TestEdge(B, A, 1), |
37 | new TestEdge(C, D, 1), | 38 | new TestEdge(C, D, 1), |
38 | new TestEdge(D, C, 1))); | 39 | new TestEdge(D, C, 1))); |
39 | - | ||
40 | GraphPathSearch<TestVertex, TestEdge> gs = graphSearch(); | 40 | GraphPathSearch<TestVertex, TestEdge> gs = graphSearch(); |
41 | Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, B, weight).paths(); | 41 | Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, B, weight).paths(); |
42 | printPaths(paths); | 42 | printPaths(paths); |
... | @@ -54,24 +54,19 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { | ... | @@ -54,24 +54,19 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { |
54 | } | 54 | } |
55 | 55 | ||
56 | @Test | 56 | @Test |
57 | - public void multiPath1() { | 57 | + public void simpleMultiplePath() { |
58 | - g = new AdjacencyListsGraph<>(ImmutableSet.of(A, B, C, D), | 58 | + g = new AdjacencyListsGraph<>(of(A, B, C, D), |
59 | - ImmutableSet.of(new TestEdge(A, B, 1), | 59 | + of(new TestEdge(A, B, 1), |
60 | new TestEdge(A, C, 1), | 60 | new TestEdge(A, C, 1), |
61 | new TestEdge(B, D, 1), | 61 | new TestEdge(B, D, 1), |
62 | new TestEdge(C, D, 1))); | 62 | new TestEdge(C, D, 1))); |
63 | - | 63 | + executeSearch(graphSearch(), g, A, D, weight, 2, 2.0); |
64 | - GraphPathSearch<TestVertex, TestEdge> gs = graphSearch(); | ||
65 | - Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, D, weight).paths(); | ||
66 | - printPaths(paths); | ||
67 | - assertEquals("incorrect paths count", 2, paths.size()); | ||
68 | - assertEquals("incorrect path cost", 2.0, paths.iterator().next().cost(), 0.1); | ||
69 | } | 64 | } |
70 | 65 | ||
71 | @Test | 66 | @Test |
72 | - public void multiPath2() { | 67 | + public void denseMultiplePath() { |
73 | - g = new AdjacencyListsGraph<>(ImmutableSet.of(A, B, C, D, E, F, G), | 68 | + g = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G), |
74 | - ImmutableSet.of(new TestEdge(A, B, 1), | 69 | + of(new TestEdge(A, B, 1), |
75 | new TestEdge(A, C, 1), | 70 | new TestEdge(A, C, 1), |
76 | new TestEdge(B, D, 1), | 71 | new TestEdge(B, D, 1), |
77 | new TestEdge(C, D, 1), | 72 | new TestEdge(C, D, 1), |
... | @@ -80,31 +75,20 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { | ... | @@ -80,31 +75,20 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { |
80 | new TestEdge(E, G, 1), | 75 | new TestEdge(E, G, 1), |
81 | new TestEdge(F, G, 1), | 76 | new TestEdge(F, G, 1), |
82 | new TestEdge(A, G, 4))); | 77 | new TestEdge(A, G, 4))); |
83 | - | 78 | + executeSearch(graphSearch(), g, A, G, weight, 5, 4.0); |
84 | - GraphPathSearch<TestVertex, TestEdge> gs = graphSearch(); | ||
85 | - GraphPathSearch.Result<TestVertex, TestEdge> gsr = gs.search(g, A, G, weight); | ||
86 | - Set<Path<TestVertex, TestEdge>> paths = gsr.paths(); | ||
87 | - printPaths(paths); | ||
88 | - assertEquals("incorrect paths count", 5, paths.size()); | ||
89 | - assertEquals("incorrect path cost", 4.0, paths.iterator().next().cost(), 0.1); | ||
90 | } | 79 | } |
91 | 80 | ||
92 | @Test | 81 | @Test |
93 | - public void multiPath3() { | 82 | + public void dualEdgeMultiplePath() { |
94 | - g = new AdjacencyListsGraph<>(ImmutableSet.of(A, B, C, D, E, F, G, H), | 83 | + g = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G, H), |
95 | - ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), | 84 | + of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), |
96 | new TestEdge(B, D, 2), new TestEdge(B, C, 1), | 85 | new TestEdge(B, D, 2), new TestEdge(B, C, 1), |
97 | new TestEdge(B, E, 4), new TestEdge(C, E, 1), | 86 | new TestEdge(B, E, 4), new TestEdge(C, E, 1), |
98 | new TestEdge(D, H, 5), new TestEdge(D, E, 1), | 87 | new TestEdge(D, H, 5), new TestEdge(D, E, 1), |
99 | new TestEdge(E, F, 1), new TestEdge(F, D, 1), | 88 | new TestEdge(E, F, 1), new TestEdge(F, D, 1), |
100 | new TestEdge(F, G, 1), new TestEdge(F, H, 1), | 89 | new TestEdge(F, G, 1), new TestEdge(F, H, 1), |
101 | new TestEdge(A, E, 3), new TestEdge(B, D, 1))); | 90 | new TestEdge(A, E, 3), new TestEdge(B, D, 1))); |
102 | - | 91 | + executeSearch(graphSearch(), g, A, E, weight, 3, 3.0); |
103 | - GraphPathSearch<TestVertex, TestEdge> gs = graphSearch(); | ||
104 | - Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, E, weight).paths(); | ||
105 | - printPaths(paths); | ||
106 | - assertEquals("incorrect paths count", 3, paths.size()); | ||
107 | - assertEquals("incorrect path cost", 3.0, paths.iterator().next().cost(), 0.1); | ||
108 | } | 92 | } |
109 | 93 | ||
110 | } | 94 | } | ... | ... |
... | @@ -4,6 +4,8 @@ import com.google.common.collect.ImmutableSet; | ... | @@ -4,6 +4,8 @@ import com.google.common.collect.ImmutableSet; |
4 | 4 | ||
5 | import java.util.Set; | 5 | import java.util.Set; |
6 | 6 | ||
7 | +import static com.google.common.collect.ImmutableSet.of; | ||
8 | + | ||
7 | /** | 9 | /** |
8 | * Base class for various graph-related tests. | 10 | * Base class for various graph-related tests. |
9 | */ | 11 | */ |
... | @@ -35,11 +37,11 @@ public class GraphTest { | ... | @@ -35,11 +37,11 @@ public class GraphTest { |
35 | } | 37 | } |
36 | 38 | ||
37 | protected Set<TestVertex> vertices() { | 39 | protected Set<TestVertex> vertices() { |
38 | - return ImmutableSet.of(A, B, C, D, E, F, G, H); | 40 | + return of(A, B, C, D, E, F, G, H); |
39 | } | 41 | } |
40 | 42 | ||
41 | protected Set<TestEdge> edges() { | 43 | protected Set<TestEdge> edges() { |
42 | - return ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), | 44 | + return of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), |
43 | new TestEdge(B, D, 2), new TestEdge(B, C, 1), | 45 | new TestEdge(B, D, 2), new TestEdge(B, C, 1), |
44 | new TestEdge(B, E, 4), new TestEdge(C, E, 1), | 46 | new TestEdge(B, E, 4), new TestEdge(C, E, 1), |
45 | new TestEdge(D, H, 5), new TestEdge(D, E, 1), | 47 | new TestEdge(D, H, 5), new TestEdge(D, E, 1), | ... | ... |
... | @@ -9,6 +9,7 @@ import java.util.ArrayList; | ... | @@ -9,6 +9,7 @@ import java.util.ArrayList; |
9 | import java.util.Comparator; | 9 | import java.util.Comparator; |
10 | import java.util.Iterator; | 10 | import java.util.Iterator; |
11 | 11 | ||
12 | +import static com.google.common.collect.ImmutableList.of; | ||
12 | import static org.junit.Assert.*; | 13 | import static org.junit.Assert.*; |
13 | 14 | ||
14 | /** | 15 | /** |
... | @@ -17,25 +18,42 @@ import static org.junit.Assert.*; | ... | @@ -17,25 +18,42 @@ import static org.junit.Assert.*; |
17 | public class HeapTest { | 18 | public class HeapTest { |
18 | 19 | ||
19 | private ArrayList<Integer> data = | 20 | private ArrayList<Integer> data = |
20 | - new ArrayList<>(ImmutableList.of(6, 4, 5, 9, 8, 3, 2, 1, 7, 0)); | 21 | + new ArrayList<>(of(6, 4, 5, 9, 8, 3, 2, 1, 7, 0)); |
21 | 22 | ||
22 | - private static final Comparator<Integer> ASCENDING = Ordering.natural().reverse(); | 23 | + private static final Comparator<Integer> MIN = Ordering.natural().reverse(); |
23 | - private static final Comparator<Integer> DESCENDING = Ordering.natural(); | 24 | + private static final Comparator<Integer> MAX = Ordering.natural(); |
24 | 25 | ||
25 | @Test | 26 | @Test |
26 | public void equality() { | 27 | public void equality() { |
27 | new EqualsTester() | 28 | new EqualsTester() |
28 | - .addEqualityGroup(new Heap<>(data, ASCENDING), | 29 | + .addEqualityGroup(new Heap<>(data, MIN), |
29 | - new Heap<>(data, ASCENDING)) | 30 | + new Heap<>(data, MIN)) |
30 | - .addEqualityGroup(new Heap<>(data, DESCENDING)) | 31 | + .addEqualityGroup(new Heap<>(data, MAX)) |
31 | .testEquals(); | 32 | .testEquals(); |
32 | } | 33 | } |
33 | 34 | ||
34 | @Test | 35 | @Test |
35 | - public void ascending() { | 36 | + public void empty() { |
36 | - Heap<Integer> h = new Heap<>(data, ASCENDING); | 37 | + Heap<Integer> h = new Heap<>(new ArrayList<Integer>(), MIN); |
38 | + assertTrue("should be empty", h.isEmpty()); | ||
39 | + assertEquals("incorrect size", 0, h.size()); | ||
40 | + assertNull("no item expected", h.extreme()); | ||
41 | + assertNull("no item expected", h.extractExtreme()); | ||
42 | + } | ||
43 | + | ||
44 | + @Test | ||
45 | + public void insert() { | ||
46 | + Heap<Integer> h = new Heap<>(data, MIN); | ||
37 | assertEquals("incorrect size", 10, h.size()); | 47 | assertEquals("incorrect size", 10, h.size()); |
48 | + h.insert(3); | ||
49 | + assertEquals("incorrect size", 11, h.size()); | ||
50 | + } | ||
51 | + | ||
52 | + @Test | ||
53 | + public void minQueue() { | ||
54 | + Heap<Integer> h = new Heap<>(data, MIN); | ||
38 | assertFalse("should not be empty", h.isEmpty()); | 55 | assertFalse("should not be empty", h.isEmpty()); |
56 | + assertEquals("incorrect size", 10, h.size()); | ||
39 | assertEquals("incorrect extreme", (Integer) 0, h.extreme()); | 57 | assertEquals("incorrect extreme", (Integer) 0, h.extreme()); |
40 | 58 | ||
41 | for (int i = 0, n = h.size(); i < n; i++) { | 59 | for (int i = 0, n = h.size(); i < n; i++) { |
... | @@ -45,10 +63,10 @@ public class HeapTest { | ... | @@ -45,10 +63,10 @@ public class HeapTest { |
45 | } | 63 | } |
46 | 64 | ||
47 | @Test | 65 | @Test |
48 | - public void descending() { | 66 | + public void maxQueue() { |
49 | - Heap<Integer> h = new Heap<>(data, DESCENDING); | 67 | + Heap<Integer> h = new Heap<>(data, MAX); |
50 | - assertEquals("incorrect size", 10, h.size()); | ||
51 | assertFalse("should not be empty", h.isEmpty()); | 68 | assertFalse("should not be empty", h.isEmpty()); |
69 | + assertEquals("incorrect size", 10, h.size()); | ||
52 | assertEquals("incorrect extreme", (Integer) 9, h.extreme()); | 70 | assertEquals("incorrect extreme", (Integer) 9, h.extreme()); |
53 | 71 | ||
54 | for (int i = h.size(); i > 0; i--) { | 72 | for (int i = h.size(); i > 0; i--) { |
... | @@ -58,29 +76,9 @@ public class HeapTest { | ... | @@ -58,29 +76,9 @@ public class HeapTest { |
58 | } | 76 | } |
59 | 77 | ||
60 | @Test | 78 | @Test |
61 | - public void empty() { | ||
62 | - Heap<Integer> h = new Heap<>(new ArrayList<Integer>(), ASCENDING); | ||
63 | - assertEquals("incorrect size", 0, h.size()); | ||
64 | - assertTrue("should be empty", h.isEmpty()); | ||
65 | - assertNull("no item expected", h.extreme()); | ||
66 | - assertNull("no item expected", h.extractExtreme()); | ||
67 | - } | ||
68 | - | ||
69 | - @Test | ||
70 | - public void insert() { | ||
71 | - Heap<Integer> h = new Heap<>(data, ASCENDING); | ||
72 | - assertEquals("incorrect size", 10, h.size()); | ||
73 | - h.insert(3); | ||
74 | - assertEquals("incorrect size", 11, h.size()); | ||
75 | - } | ||
76 | - | ||
77 | - @Test | ||
78 | public void iterator() { | 79 | public void iterator() { |
79 | - Heap<Integer> h = new Heap<>(data, ASCENDING); | 80 | + Heap<Integer> h = new Heap<>(data, MIN); |
80 | - Iterator<Integer> it = h.iterator(); | 81 | + assertTrue("should have next element", h.iterator().hasNext()); |
81 | - while (it.hasNext()) { | ||
82 | - int item = it.next(); | ||
83 | - } | ||
84 | } | 82 | } |
85 | 83 | ||
86 | } | 84 | } | ... | ... |
... | @@ -2,6 +2,8 @@ package org.onlab.graph; | ... | @@ -2,6 +2,8 @@ package org.onlab.graph; |
2 | 2 | ||
3 | import java.util.Objects; | 3 | import java.util.Objects; |
4 | 4 | ||
5 | +import static com.google.common.base.Objects.toStringHelper; | ||
6 | + | ||
5 | /** | 7 | /** |
6 | * Test edge. | 8 | * Test edge. |
7 | */ | 9 | */ |
... | @@ -43,4 +45,11 @@ public class TestEdge extends AbstractEdge<TestVertex> { | ... | @@ -43,4 +45,11 @@ public class TestEdge extends AbstractEdge<TestVertex> { |
43 | } | 45 | } |
44 | return false; | 46 | return false; |
45 | } | 47 | } |
48 | + | ||
49 | + @Override | ||
50 | + public String toString() { | ||
51 | + return toStringHelper(this).add("src", src()).add("dst", dst()). | ||
52 | + add("weight", weight).toString(); | ||
53 | + } | ||
54 | + | ||
46 | } | 55 | } | ... | ... |
... | @@ -16,11 +16,6 @@ public class TestVertex implements Vertex { | ... | @@ -16,11 +16,6 @@ public class TestVertex implements Vertex { |
16 | } | 16 | } |
17 | 17 | ||
18 | @Override | 18 | @Override |
19 | - public String toString() { | ||
20 | - return toStringHelper(this).add("name", name).toString(); | ||
21 | - } | ||
22 | - | ||
23 | - @Override | ||
24 | public int hashCode() { | 19 | public int hashCode() { |
25 | return Objects.hash(name); | 20 | return Objects.hash(name); |
26 | } | 21 | } |
... | @@ -34,4 +29,9 @@ public class TestVertex implements Vertex { | ... | @@ -34,4 +29,9 @@ public class TestVertex implements Vertex { |
34 | return false; | 29 | return false; |
35 | } | 30 | } |
36 | 31 | ||
32 | + @Override | ||
33 | + public String toString() { | ||
34 | + return name; | ||
35 | + } | ||
36 | + | ||
37 | } | 37 | } | ... | ... |
-
Please register or login to post a comment