alshabib

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 39 changed files with 2286 additions and 4 deletions
...@@ -45,7 +45,7 @@ public class AbstractListenerRegistry<E extends Event, L extends EventListener<E ...@@ -45,7 +45,7 @@ public class AbstractListenerRegistry<E extends Event, L extends EventListener<E
45 for (L listener : listeners) { 45 for (L listener : listeners) {
46 try { 46 try {
47 listener.event(event); 47 listener.event(event);
48 - } catch (Throwable error) { 48 + } catch (Exception error) {
49 reportProblem(event, error); 49 reportProblem(event, error);
50 } 50 }
51 } 51 }
......
...@@ -82,7 +82,7 @@ public class SimpleEventDispatcher extends DefaultEventSinkRegistry ...@@ -82,7 +82,7 @@ public class SimpleEventDispatcher extends DefaultEventSinkRegistry
82 log.warn("No sink registered for event class {}", 82 log.warn("No sink registered for event class {}",
83 event.getClass()); 83 event.getClass());
84 } 84 }
85 - } catch (Throwable e) { 85 + } catch (Exception e) {
86 log.warn("Error encountered while dispatching event:", e); 86 log.warn("Error encountered while dispatching event:", e);
87 } 87 }
88 } 88 }
......
...@@ -141,7 +141,6 @@ public class SimpleDeviceManager ...@@ -141,7 +141,6 @@ public class SimpleDeviceManager
141 public void updatePorts(DeviceId deviceId, List<PortDescription> portDescriptions) { 141 public void updatePorts(DeviceId deviceId, List<PortDescription> portDescriptions) {
142 checkNotNull(deviceId, DEVICE_ID_NULL); 142 checkNotNull(deviceId, DEVICE_ID_NULL);
143 checkNotNull(portDescriptions, "Port descriptions list cannot be null"); 143 checkNotNull(portDescriptions, "Port descriptions list cannot be null");
144 - // FIXME: fix the interface to accept DeviceId separately
145 log.info("Device {} ports updated: {}", portDescriptions); 144 log.info("Device {} ports updated: {}", portDescriptions);
146 List<DeviceEvent> events = store.updatePorts(deviceId, portDescriptions); 145 List<DeviceEvent> events = store.updatePorts(deviceId, portDescriptions);
147 for (DeviceEvent event : events) { 146 for (DeviceEvent event : events) {
......
...@@ -306,7 +306,7 @@ ...@@ -306,7 +306,7 @@
306 <group> 306 <group>
307 <title>Utilities</title> 307 <title>Utilities</title>
308 <packages> 308 <packages>
309 - org.onlab.util:org.onlab.util.* 309 + org.onlab.*
310 </packages> 310 </packages>
311 </group> 311 </group>
312 <group> 312 <group>
......
...@@ -17,6 +17,12 @@ ...@@ -17,6 +17,12 @@
17 <description>Miscellaneous ON.Lab utilities</description> 17 <description>Miscellaneous ON.Lab utilities</description>
18 18
19 <dependencies> 19 <dependencies>
20 + <dependency>
21 + <groupId>com.google.guava</groupId>
22 + <artifactId>guava-testlib</artifactId>
23 + <version>17.0</version>
24 + <scope>test</scope>
25 + </dependency>
20 </dependencies> 26 </dependencies>
21 27
22 </project> 28 </project>
......
1 +package org.onlab.graph;
2 +
3 +import java.util.Objects;
4 +
5 +import static com.google.common.base.Preconditions.checkNotNull;
6 +
7 +/**
8 + * Abstract graph edge implementation.
9 + */
10 +public abstract class AbstractEdge<V extends Vertex> implements Edge<V> {
11 +
12 + private final V src;
13 + private final V dst;
14 +
15 + /**
16 + * Creates a new edge between the specified source and destination vertexes.
17 + *
18 + * @param src source vertex
19 + * @param dst destination vertex
20 + */
21 + public AbstractEdge(V src, V dst) {
22 + this.src = checkNotNull(src, "Source vertex cannot be null");
23 + this.dst = checkNotNull(dst, "Destination vertex cannot be null");
24 + }
25 +
26 + @Override
27 + public V src() {
28 + return src;
29 + }
30 +
31 + @Override
32 + public V dst() {
33 + return dst;
34 + }
35 +
36 + @Override
37 + public int hashCode() {
38 + return Objects.hash(src, dst);
39 + }
40 +
41 + @Override
42 + public boolean equals(Object obj) {
43 + if (obj instanceof AbstractEdge) {
44 + final AbstractEdge other = (AbstractEdge) obj;
45 + return Objects.equals(this.src, other.src) && Objects.equals(this.dst, other.dst);
46 + }
47 + return false;
48 + }
49 +
50 + @Override
51 + public String toString() {
52 + return com.google.common.base.Objects.toStringHelper(this)
53 + .add("src", src)
54 + .add("dst", dst)
55 + .toString();
56 + }
57 +}
1 +package org.onlab.graph;
2 +
3 +import java.util.HashMap;
4 +import java.util.HashSet;
5 +import java.util.Iterator;
6 +import java.util.Map;
7 +import java.util.Set;
8 +
9 +import static com.google.common.base.Preconditions.checkArgument;
10 +import static com.google.common.base.Preconditions.checkNotNull;
11 +
12 +/**
13 + * Basis for various graph path search algorithm implementations.
14 + *
15 + * @param <V> vertex type
16 + * @param <E> edge type
17 + */
18 +public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V>>
19 + implements GraphPathSearch<V, E> {
20 +
21 + private double samenessThreshold = 0.000000001;
22 +
23 + /**
24 + * Sets a new sameness threshold for comparing cost values; default is
25 + * is {@code 0.000000001}.
26 + *
27 + * @param threshold fractional double value
28 + */
29 + public void setSamenessThreshold(double threshold) {
30 + samenessThreshold = threshold;
31 + }
32 +
33 + /**
34 + * Returns the current sameness threshold for comparing cost values.
35 + *
36 + * @return current threshold
37 + */
38 + public double samenessThreshold() {
39 + return samenessThreshold;
40 + }
41 +
42 + /**
43 + * Default path search result that uses the DefaultPath to convey paths
44 + * in a graph.
45 + */
46 + protected class DefaultResult implements Result<V, E> {
47 +
48 + private final V src;
49 + private final V dst;
50 + protected final Set<Path<V, E>> paths = new HashSet<>();
51 + protected final Map<V, Double> costs = new HashMap<>();
52 + protected final Map<V, Set<E>> parents = new HashMap<>();
53 +
54 + /**
55 + * Creates the result of path search.
56 + *
57 + * @param src path source
58 + * @param dst optional path destination
59 + */
60 + public DefaultResult(V src, V dst) {
61 + checkNotNull(src, "Source cannot be null");
62 + this.src = src;
63 + this.dst = dst;
64 + }
65 +
66 + @Override
67 + public V src() {
68 + return src;
69 + }
70 +
71 + @Override
72 + public V dst() {
73 + return dst;
74 + }
75 +
76 + @Override
77 + public Set<Path<V, E>> paths() {
78 + return paths;
79 + }
80 +
81 + @Override
82 + public Map<V, Double> costs() {
83 + return costs;
84 + }
85 +
86 + @Override
87 + public Map<V, Set<E>> parents() {
88 + return parents;
89 + }
90 +
91 + /**
92 + * Indicates whether or not the given vertex has a cost yet.
93 + *
94 + * @param v vertex to test
95 + * @return true if the vertex has cost already
96 + */
97 + boolean hasCost(V v) {
98 + return costs.get(v) != null;
99 + }
100 +
101 + /**
102 + * Returns the current cost to reach the specified vertex.
103 + *
104 + * @return cost to reach the vertex
105 + */
106 + double cost(V v) {
107 + Double c = costs.get(v);
108 + return c == null ? Double.MAX_VALUE : c;
109 + }
110 +
111 + /**
112 + * Updates the cost of the vertex using its existing cost plus the
113 + * cost to traverse the specified edge.
114 + *
115 + * @param v vertex
116 + * @param edge edge through which vertex is reached
117 + * @param cost current cost to reach the vertex from the source
118 + * @param replace true to indicate that any accrued edges are to be
119 + * cleared; false to indicate that the edge should be
120 + * added to the previously accrued edges as they yield
121 + * the same cost
122 + */
123 + void updateVertex(V v, E edge, double cost, boolean replace) {
124 + costs.put(v, cost);
125 + if (edge != null) {
126 + Set<E> edges = parents.get(v);
127 + if (edges == null) {
128 + edges = new HashSet<>();
129 + parents.put(v, edges);
130 + }
131 + if (replace) {
132 + edges.clear();
133 + }
134 + edges.add(edge);
135 + }
136 + }
137 +
138 + /**
139 + * Removes the set of parent edges for the specified vertex.
140 + *
141 + * @param v vertex
142 + */
143 + void removeVertex(V v) {
144 + parents.remove(v);
145 + }
146 +
147 + /**
148 + * If possible, relax the specified edge using the supplied base cost
149 + * and edge-weight function.
150 + *
151 + * @param e edge to be relaxed
152 + * @param cost base cost to reach the edge destination vertex
153 + * @param ew optional edge weight function
154 + * @return true if the edge was relaxed; false otherwise
155 + */
156 + boolean relaxEdge(E e, double cost, EdgeWeight<V, E> ew) {
157 + V v = e.dst();
158 + double oldCost = cost(v);
159 + double newCost = cost + (ew == null ? 1.0 : ew.weight(e));
160 + boolean relaxed = newCost < oldCost;
161 + boolean same = Math.abs(newCost - oldCost) < samenessThreshold;
162 + if (same || relaxed) {
163 + updateVertex(v, e, newCost, !same);
164 + }
165 + return relaxed;
166 + }
167 +
168 + /**
169 + * Builds a set of paths for the specified src/dst vertex pair.
170 + */
171 + protected void buildPaths() {
172 + Set<V> destinations = new HashSet<>();
173 + if (dst == null) {
174 + destinations.addAll(costs.keySet());
175 + } else {
176 + destinations.add(dst);
177 + }
178 +
179 + // Build all paths between the source and all requested destinations.
180 + for (V v : destinations) {
181 + // Ignore the source, if it is among the destinations.
182 + if (!v.equals(src)) {
183 + buildAllPaths(this, src, v);
184 + }
185 + }
186 + }
187 +
188 + }
189 +
190 + /**
191 + * Builds a set of all paths between the source and destination using the
192 + * graph search result by applying breadth-first search through the parent
193 + * edges and vertex costs.
194 + *
195 + * @param result graph search result
196 + * @param src source vertex
197 + * @param dst destination vertex
198 + */
199 + private void buildAllPaths(DefaultResult result, V src, V dst) {
200 + DefaultMutablePath<V, E> basePath = new DefaultMutablePath<>();
201 + basePath.setCost(result.cost(dst));
202 +
203 + Set<DefaultMutablePath<V, E>> pendingPaths = new HashSet<>();
204 + pendingPaths.add(basePath);
205 +
206 + while (!pendingPaths.isEmpty()) {
207 + Set<DefaultMutablePath<V, E>> frontier = new HashSet<>();
208 +
209 + for (DefaultMutablePath<V, E> path : pendingPaths) {
210 + // For each pending path, locate its first vertex since we
211 + // will be moving backwards from it.
212 + V firstVertex = firstVertex(path, dst);
213 +
214 + // If the first vertex is our expected source, we have reached
215 + // the beginning, so add the this path to the result paths.
216 + if (firstVertex.equals(src)) {
217 + path.setCost(result.cost(dst));
218 + result.paths.add(new DefaultPath<>(path.edges(), path.cost()));
219 +
220 + } else {
221 + // If we have not reached the beginning, i.e. the source,
222 + // fetch the set of edges leading to the first vertex of
223 + // this pending path; if there are none, abandon processing
224 + // this path for good.
225 + Set<E> firstVertexParents = result.parents.get(firstVertex);
226 + if (firstVertexParents == null || firstVertexParents.isEmpty()) {
227 + break;
228 + }
229 +
230 + // Now iterate over all the edges and for each of them
231 + // cloning the current path and then insert that edge to
232 + // the path and then add that path to the pending ones.
233 + // When processing the last edge, modify the current
234 + // pending path rather than cloning a new one.
235 + Iterator<E> edges = firstVertexParents.iterator();
236 + while (edges.hasNext()) {
237 + E edge = edges.next();
238 + boolean isLast = !edges.hasNext();
239 + DefaultMutablePath<V, E> pendingPath = isLast ? path : new DefaultMutablePath<>(path);
240 + pendingPath.insertEdge(edge);
241 + frontier.add(pendingPath);
242 + }
243 + }
244 + }
245 +
246 + // All pending paths have been scanned so promote the next frontier
247 + pendingPaths = frontier;
248 + }
249 + }
250 +
251 + // Returns the first vertex of the specified path. This is either the source
252 + // of the first edge or, if there are no edges yet, the given destination.
253 + private V firstVertex(Path<V, E> path, V dst) {
254 + return path.edges().isEmpty() ? dst : path.edges().get(0).src();
255 + }
256 +
257 + /**
258 + * Checks the specified path search arguments for validity.
259 + *
260 + * @param graph graph; must not be null
261 + * @param src source vertex; must not be null and belong to graph
262 + * @param dst optional target vertex; must belong to graph
263 + */
264 + protected void checkArguments(Graph<V, E> graph, V src, V dst) {
265 + checkNotNull(graph, "Graph cannot be null");
266 + checkNotNull(src, "Source cannot be null");
267 + Set<V> vertices = graph.getVertexes();
268 + checkArgument(vertices.contains(src), "Source not in the graph");
269 + checkArgument(dst == null || vertices.contains(dst),
270 + "Destination not in graph");
271 + }
272 +
273 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.collect.ImmutableSet;
4 +import com.google.common.collect.ImmutableSetMultimap;
5 +
6 +import java.util.Objects;
7 +import java.util.Set;
8 +
9 +import static com.google.common.base.Preconditions.checkNotNull;
10 +
11 +/**
12 + * Immutable graph implemented using adjacency lists.
13 + *
14 + * @param <V> vertex type
15 + * @param <E> edge type
16 + */
17 +public class AdjacencyListsGraph<V extends Vertex, E extends Edge<V>> implements Graph<V, E> {
18 +
19 + private final Set<V> vertexes;
20 + private final Set<E> edges;
21 +
22 + private final ImmutableSetMultimap<V, E> sources;
23 + private final ImmutableSetMultimap<V, E> destinations;
24 +
25 + /**
26 + * Creates a graph comprising of the specified vertexes and edges.
27 + *
28 + * @param vertexes set of graph vertexes
29 + * @param edges set of graph edges
30 + */
31 + public AdjacencyListsGraph(Set<V> vertexes, Set<E> edges) {
32 + checkNotNull(vertexes, "Vertex set cannot be null");
33 + checkNotNull(edges, "Edge set cannot be null");
34 +
35 + // Record ingress/egress edges for each vertex.
36 + ImmutableSetMultimap.Builder<V, E> srcMap = ImmutableSetMultimap.builder();
37 + ImmutableSetMultimap.Builder<V, E> dstMap = ImmutableSetMultimap.builder();
38 +
39 + // Also make sure that all edge end-points are added as vertexes
40 + ImmutableSet.Builder<V> actualVertexes = ImmutableSet.builder();
41 + actualVertexes.addAll(vertexes);
42 +
43 + for (E edge : edges) {
44 + srcMap.put(edge.src(), edge);
45 + actualVertexes.add(edge.src());
46 + dstMap.put(edge.dst(), edge);
47 + actualVertexes.add(edge.dst());
48 + }
49 +
50 + // Make an immutable copy of the edge and vertex sets
51 + this.edges = ImmutableSet.copyOf(edges);
52 + this.vertexes = actualVertexes.build();
53 +
54 + // Build immutable copies of sources and destinations edge maps
55 + sources = srcMap.build();
56 + destinations = dstMap.build();
57 + }
58 +
59 + @Override
60 + public Set<V> getVertexes() {
61 + return vertexes;
62 + }
63 +
64 + @Override
65 + public Set<E> getEdges() {
66 + return edges;
67 + }
68 +
69 + @Override
70 + public Set<E> getEdgesFrom(V src) {
71 + return sources.get(src);
72 + }
73 +
74 + @Override
75 + public Set<E> getEdgesTo(V dst) {
76 + return destinations.get(dst);
77 + }
78 +
79 + @Override
80 + public boolean equals(Object obj) {
81 + if (obj instanceof AdjacencyListsGraph) {
82 + AdjacencyListsGraph that = (AdjacencyListsGraph) obj;
83 + return this.getClass() == that.getClass() &&
84 + Objects.equals(this.vertexes, that.vertexes) &&
85 + Objects.equals(this.edges, that.edges);
86 + }
87 + return false;
88 + }
89 +
90 + @Override
91 + public int hashCode() {
92 + return Objects.hash(vertexes, edges);
93 + }
94 +
95 + @Override
96 + public String toString() {
97 + return com.google.common.base.Objects.toStringHelper(this)
98 + .add("vertexes", vertexes)
99 + .add("edges", edges)
100 + .toString();
101 + }
102 +}
1 +package org.onlab.graph;
2 +
3 +/**
4 + * Bellman-Ford graph search algorithm for locating shortest-paths in
5 + * directed graphs that may contain negative cycles.
6 + */
7 +public class BellmanFordGraphSearch<V extends Vertex, E extends Edge<V>>
8 + extends AbstractGraphPathSearch<V, E> {
9 +
10 + @Override
11 + public Result<V, E> search(Graph<V, E> graph, V src, V dst,
12 + EdgeWeight<V, E> weight) {
13 + checkArguments(graph, src, dst);
14 +
15 + // Prepare the graph search result.
16 + DefaultResult result = new DefaultResult(src, dst);
17 +
18 + // The source vertex has cost 0, of course.
19 + result.updateVertex(src, null, 0.0, true);
20 +
21 + int max = graph.getVertexes().size() - 1;
22 + for (int i = 0; i < max; i++) {
23 + // Relax, if possible, all egress edges of the current vertex.
24 + for (E edge : graph.getEdges()) {
25 + if (result.hasCost(edge.src())) {
26 + result.relaxEdge(edge, result.cost(edge.src()), weight);
27 + }
28 + }
29 + }
30 +
31 + // Remove any vertexes reached by traversing edges with negative weights.
32 + for (E edge : graph.getEdges()) {
33 + if (result.hasCost(edge.src())) {
34 + if (result.relaxEdge(edge, result.cost(edge.src()), weight)) {
35 + result.removeVertex(edge.dst());
36 + }
37 + }
38 + }
39 +
40 + // Finally, but the paths on the search result and return.
41 + result.buildPaths();
42 + return result;
43 + }
44 +
45 +}
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,
14 + EdgeWeight<V, E> weight) {
15 + checkArguments(graph, src, dst);
16 +
17 + // Prepare the graph result.
18 + DefaultResult result = new DefaultResult(src, dst);
19 +
20 + // Setup the starting frontier with the source as the sole vertex.
21 + Set<V> frontier = new HashSet<>();
22 + result.updateVertex(src, null, 0.0, true);
23 + frontier.add(src);
24 +
25 + boolean reachedEnd = false;
26 + while (!reachedEnd && !frontier.isEmpty()) {
27 + // Prepare the next frontier.
28 + Set<V> next = new HashSet<>();
29 +
30 + // Visit all vertexes in the current frontier.
31 + for (V vertex : frontier) {
32 + double cost = result.cost(vertex);
33 +
34 + // Visit all egress edges of the current frontier vertex.
35 + for (E edge : graph.getEdgesFrom(vertex)) {
36 + V nextVertex = edge.dst();
37 + if (!result.hasCost(nextVertex)) {
38 + // If this vertex has not been visited yet, update it.
39 + double newCost = cost + (weight == null ? 1.0 : weight.weight(edge));
40 + result.updateVertex(nextVertex, edge, newCost, true);
41 + // If we have reached our intended destination, bail.
42 + if (nextVertex.equals(dst)) {
43 + reachedEnd = true;
44 + break;
45 + }
46 + next.add(nextVertex);
47 + }
48 +
49 + if (reachedEnd) {
50 + break;
51 + }
52 + }
53 + }
54 +
55 + // Promote the next frontier.
56 + frontier = next;
57 + }
58 +
59 + // Finally, but the paths on the search result and return.
60 + result.buildPaths();
61 + return result;
62 + }
63 +
64 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.collect.ImmutableList;
4 +
5 +import java.util.ArrayList;
6 +import java.util.List;
7 +import java.util.Objects;
8 +
9 +import static com.google.common.base.Preconditions.checkArgument;
10 +import static com.google.common.base.Preconditions.checkNotNull;
11 +
12 +/**
13 + * Simple concrete implementation of a directed graph path.
14 + */
15 +public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements MutablePath<V, E> {
16 +
17 + private final List<E> edges = new ArrayList<>();
18 + private double cost = 0.0;
19 +
20 + /**
21 + * Creates a new empty path.
22 + */
23 + public DefaultMutablePath() {
24 + }
25 +
26 + /**
27 + * Creates a new path as a copy of another path.
28 + *
29 + * @param path path to be copied
30 + */
31 + public DefaultMutablePath(Path<V, E> path) {
32 + checkNotNull(path, "Path cannot be null");
33 + this.cost = path.cost();
34 + edges.addAll(path.edges());
35 + }
36 +
37 + @Override
38 + public V src() {
39 + return edges.isEmpty() ? null : edges.get(0).src();
40 + }
41 +
42 + @Override
43 + public V dst() {
44 + return edges.isEmpty() ? null : edges.get(edges.size() - 1).dst();
45 + }
46 +
47 + @Override
48 + public double cost() {
49 + return cost;
50 + }
51 +
52 + @Override
53 + public List<E> edges() {
54 + return ImmutableList.copyOf(edges);
55 + }
56 +
57 + @Override
58 + public void setCost(double cost) {
59 + this.cost = cost;
60 + }
61 +
62 + @Override
63 + public Path<V, E> toImmutable() {
64 + return new DefaultPath<>(edges, cost);
65 + }
66 +
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
76 + public void appendEdge(E edge) {
77 + checkNotNull(edge, "Edge cannot be null");
78 + checkArgument(edges.isEmpty() || dst().equals(edge.src()),
79 + "Edge source must be the same as the current path destination");
80 + edges.add(edge);
81 + }
82 +
83 + @Override
84 + public void removeEdge(E edge) {
85 + checkArgument(edge.src().equals(edge.dst()) ||
86 + edges.indexOf(edge) == 0 ||
87 + edges.lastIndexOf(edge) == edges.size() - 1,
88 + "Edge must be at start or end of path, or it must be a cyclic edge");
89 + edges.remove(edge);
90 + }
91 +
92 + @Override
93 + public String toString() {
94 + return com.google.common.base.Objects.toStringHelper(this)
95 + .add("src", src())
96 + .add("dst", dst())
97 + .add("cost", cost)
98 + .add("edges", edges)
99 + .toString();
100 + }
101 +
102 + @Override
103 + public int hashCode() {
104 + return Objects.hash(edges, cost);
105 + }
106 +
107 + @Override
108 + public boolean equals(Object obj) {
109 + if (obj instanceof DefaultMutablePath) {
110 + final DefaultMutablePath other = (DefaultMutablePath) obj;
111 + return Objects.equals(this.cost, other.cost) &&
112 + Objects.equals(this.edges, other.edges);
113 + }
114 + return false;
115 + }
116 +
117 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.collect.ImmutableList;
4 +
5 +import java.util.Collections;
6 +import java.util.List;
7 +import java.util.Objects;
8 +
9 +import static com.google.common.base.Preconditions.checkArgument;
10 +import static com.google.common.base.Preconditions.checkNotNull;
11 +
12 +/**
13 + * Simple concrete implementation of a directed graph path.
14 + */
15 +public class DefaultPath<V extends Vertex, E extends Edge<V>> implements Path<V, E> {
16 +
17 + private final V src;
18 + private final V dst;
19 + private final List<E> edges;
20 + private double cost = 0.0;
21 +
22 + /**
23 + * Creates a new path from the specified list of edges and cost.
24 + *
25 + * @param edges list of path edges
26 + * @param cost path cost as a unit-less number
27 + */
28 + public DefaultPath(List<E> edges, double cost) {
29 + checkNotNull(edges, "Edges list must not be null");
30 + checkArgument(!edges.isEmpty(), "There must be at least one edge");
31 + this.edges = ImmutableList.copyOf(edges);
32 + this.src = edges.get(0).src();
33 + this.dst = edges.get(edges.size() - 1).dst();
34 + this.cost = cost;
35 + }
36 +
37 + @Override
38 + public V src() {
39 + return src;
40 + }
41 +
42 + @Override
43 + public V dst() {
44 + return dst;
45 + }
46 +
47 + @Override
48 + public double cost() {
49 + return cost;
50 + }
51 +
52 + @Override
53 + public List<E> edges() {
54 + return Collections.unmodifiableList(edges);
55 + }
56 +
57 + @Override
58 + public String toString() {
59 + return com.google.common.base.Objects.toStringHelper(this)
60 + .add("src", src)
61 + .add("dst", dst)
62 + .add("cost", cost)
63 + .add("edges", edges)
64 + .toString();
65 + }
66 +
67 + @Override
68 + public int hashCode() {
69 + return Objects.hash(src, dst, edges, cost);
70 + }
71 +
72 + @Override
73 + public boolean equals(Object obj) {
74 + if (obj instanceof DefaultPath) {
75 + final DefaultPath other = (DefaultPath) obj;
76 + return Objects.equals(this.src, other.src) &&
77 + Objects.equals(this.dst, other.dst) &&
78 + Objects.equals(this.cost, other.cost) &&
79 + Objects.equals(this.edges, other.edges);
80 + }
81 + return false;
82 + }
83 +
84 +}
1 +package org.onlab.graph;
2 +
3 +import java.util.HashMap;
4 +import java.util.HashSet;
5 +import java.util.Map;
6 +import java.util.Set;
7 +import java.util.Stack;
8 +
9 +/**
10 + * DFS graph search algorithm implemented via iteration rather than recursion.
11 + */
12 +public class DepthFirstSearch<V extends Vertex, E extends Edge<V>>
13 + extends AbstractGraphPathSearch<V, E> {
14 +
15 + /**
16 + * Graph edge types as classified by the DFS algorithm.
17 + */
18 + public static enum EdgeType {
19 + TREE_EDGE, FORWARD_EDGE, BACK_EDGE, CROSS_EDGE
20 + }
21 +
22 + @Override
23 + public SpanningTreeResult search(Graph<V, E> graph, V src, V dst,
24 + EdgeWeight<V, E> weight) {
25 + checkArguments(graph, src, dst);
26 +
27 + // Prepare the search result.
28 + SpanningTreeResult result = new SpanningTreeResult(src, dst);
29 +
30 + // The source vertex has cost 0, of course.
31 + result.updateVertex(src, null, 0.0, true);
32 +
33 + // Track finished vertexes and keep a stack of vertexes that have been
34 + // started; start this stack with the source on it.
35 + Set<V> finished = new HashSet<>();
36 + Stack<V> stack = new Stack<>();
37 + stack.push(src);
38 +
39 + while (!stack.isEmpty()) {
40 + V vertex = stack.peek();
41 + if (vertex.equals(dst)) {
42 + // If we have reached our destination, bail.
43 + break;
44 + }
45 +
46 + double cost = result.cost(vertex);
47 + boolean tangent = false;
48 +
49 + // Visit all egress edges of the current vertex.
50 + for (E edge : graph.getEdgesFrom(vertex)) {
51 + // If we have seen the edge already, skip it.
52 + if (result.isEdgeMarked(edge)) {
53 + continue;
54 + }
55 +
56 + // Examine the destination of the current edge.
57 + V nextVertex = edge.dst();
58 + if (!result.hasCost(nextVertex)) {
59 + // If this vertex have not finished this vertex yet,
60 + // not started it, then start it as a tree-edge.
61 + result.markEdge(edge, EdgeType.TREE_EDGE);
62 + double newCost = cost + (weight == null ? 1.0 : weight.weight(edge));
63 + result.updateVertex(nextVertex, edge, newCost, true);
64 + stack.push(nextVertex);
65 + tangent = true;
66 + break;
67 +
68 + } else if (!finished.contains(nextVertex)) {
69 + // We started the vertex, but did not yet finish it, so
70 + // it must be a back-edge.
71 + result.markEdge(edge, EdgeType.BACK_EDGE);
72 + } else {
73 + // The target has been finished already, so what we have
74 + // here is either a forward-edge or a cross-edge.
75 + result.markEdge(edge, isForwardEdge(result, edge) ?
76 + EdgeType.FORWARD_EDGE : EdgeType.CROSS_EDGE);
77 + }
78 + }
79 +
80 + // If we have not been sent on a tangent search and reached the
81 + // end of the current scan normally, mark the node as finished
82 + // and pop it off the vertex stack.
83 + if (!tangent) {
84 + finished.add(vertex);
85 + stack.pop();
86 + }
87 + }
88 +
89 + // Finally, but the paths on the search result and return.
90 + result.buildPaths();
91 + return result;
92 + }
93 +
94 + /**
95 + * Determines whether the specified edge is a forward edge using the
96 + * accumulated set of parent edges for each vertex.
97 + *
98 + * @param result search result
99 + * @param edge edge to be classified
100 + * @return true if the edge is a forward edge
101 + */
102 + protected boolean isForwardEdge(DefaultResult result, E edge) {
103 + // Follow the parent edges until we hit the edge source vertex
104 + V target = edge.src();
105 + V vertex = edge.dst();
106 + Set<E> parentEdges;
107 + while ((parentEdges = result.parents.get(vertex)) != null) {
108 + for (E parentEdge : parentEdges) {
109 + vertex = parentEdge.src();
110 + if (vertex.equals(target)) {
111 + return true;
112 + }
113 + }
114 + }
115 + return false;
116 + }
117 +
118 + /**
119 + * Graph search result which includes edge classification for building
120 + * a spanning tree.
121 + */
122 + public class SpanningTreeResult extends DefaultResult {
123 +
124 + protected final Map<E, EdgeType> edges = new HashMap<>();
125 +
126 + /**
127 + * Creates a new spanning tree result.
128 + *
129 + * @param src search source
130 + * @param dst optional search destination
131 + */
132 + public SpanningTreeResult(V src, V dst) {
133 + super(src, dst);
134 + }
135 +
136 + /**
137 + * Returns the map of edge type.
138 + *
139 + * @return edge to edge type bindings
140 + */
141 + public Map<E, EdgeType> edges() {
142 + return edges;
143 + }
144 +
145 + /**
146 + * Indicates whether or not the edge has been marked with type.
147 + *
148 + * @param edge edge to test
149 + * @return true if the edge has been marked already
150 + */
151 + boolean isEdgeMarked(E edge) {
152 + return edges.containsKey(edge);
153 + }
154 +
155 + /**
156 + * Marks the edge with the specified type.
157 + *
158 + * @param edge edge to mark
159 + * @param type edge type
160 + */
161 + void markEdge(E edge, EdgeType type) {
162 + edges.put(edge, type);
163 + }
164 +
165 + }
166 +
167 +}
1 +package org.onlab.graph;
2 +
3 +import java.util.ArrayList;
4 +import java.util.Comparator;
5 +import java.util.Set;
6 +
7 +/**
8 + * Dijkstra shortest-path graph search algorithm capable of finding not just
9 + * one, but all shortest paths between the source and destinations.
10 + */
11 +public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>>
12 + extends AbstractGraphPathSearch<V, E> {
13 +
14 + @Override
15 + public Result<V, E> search(Graph<V, E> graph, V src, V dst,
16 + EdgeWeight<V, E> weight) {
17 + checkArguments(graph, src, dst);
18 +
19 + // Use the default result to remember cumulative costs and parent
20 + // edges to each each respective vertex.
21 + DefaultResult result = new DefaultResult(src, dst);
22 +
23 + // Cost to reach the source vertex is 0 of course.
24 + result.updateVertex(src, null, 0.0, false);
25 +
26 + // Use the min priority queue to progressively find each nearest
27 + // vertex until we reach the desired destination, if one was given,
28 + // or until we reach all possible destinations.
29 + Heap<V> minQueue = createMinQueue(graph.getVertexes(),
30 + new PathCostComparator(result));
31 + while (!minQueue.isEmpty()) {
32 + // Get the nearest vertex
33 + V nearest = minQueue.extractExtreme();
34 + if (nearest.equals(dst)) {
35 + break;
36 + }
37 +
38 + // Find its cost and use it to determine if the vertex is reachable.
39 + double cost = result.cost(nearest);
40 + if (cost < Double.MAX_VALUE) {
41 + // If the vertex is reachable, relax all its egress edges.
42 + for (E e : graph.getEdgesFrom(nearest)) {
43 + result.relaxEdge(e, cost, weight);
44 + }
45 + }
46 +
47 + // Re-prioritize the min queue.
48 + minQueue.heapify();
49 + }
50 +
51 + // Now construct a set of paths from the results.
52 + result.buildPaths();
53 + return result;
54 + }
55 +
56 + // Compares path weights using their accrued costs; used for sorting the
57 + // min priority queue.
58 + private final class PathCostComparator implements Comparator<V> {
59 + private final DefaultResult result;
60 +
61 + private PathCostComparator(DefaultResult result) {
62 + this.result = result;
63 + }
64 +
65 + @Override
66 + public int compare(V v1, V v2) {
67 + double delta = result.cost(v2) - result.cost(v1);
68 + return delta < 0 ? -1 : (delta > 0 ? 1 : 0);
69 + }
70 + }
71 +
72 + // Creates a min priority queue from the specified vertexes and comparator.
73 + private Heap<V> createMinQueue(Set<V> vertexes, Comparator<V> comparator) {
74 + return new Heap<>(new ArrayList<>(vertexes), comparator);
75 + }
76 +
77 +}
1 +package org.onlab.graph;
2 +
3 +/**
4 + * Representation of a graph edge.
5 + *
6 + * @param <V> vertex type
7 + */
8 +public interface Edge<V extends Vertex> {
9 +
10 + /**
11 + * Returns the edge source vertex.
12 + *
13 + * @return source vertex
14 + */
15 + V src();
16 +
17 + /**
18 + * Returns the edge destination vertex.
19 + *
20 + * @return destination vertex
21 + */
22 + V dst();
23 +
24 +}
1 +package org.onlab.graph;
2 +
3 +/**
4 + * Abstraction of a graph edge weight function.
5 + */
6 +public interface EdgeWeight<V extends Vertex, E extends Edge<V>> {
7 +
8 + /**
9 + * Returns the weight of the given edge as a unit-less number.
10 + *
11 + * @param edge edge to be weighed
12 + * @return edge weight as a unit-less number
13 + */
14 + double weight(E edge);
15 +
16 +}
1 +package org.onlab.graph;
2 +
3 +
4 +import java.util.Set;
5 +
6 +/**
7 + * Abstraction of a directed graph structure.
8 + *
9 + * @param <V> vertex type
10 + * @param <E> edge type
11 + */
12 +public interface Graph<V extends Vertex, E extends Edge> {
13 +
14 + /**
15 + * Returns the set of vertexes comprising the graph.
16 + *
17 + * @return set of vertexes
18 + */
19 + Set<V> getVertexes();
20 +
21 + /**
22 + * Returns the set of edges comprising the graph.
23 + *
24 + * @return set of edges
25 + */
26 + Set<E> getEdges();
27 +
28 + /**
29 + * Returns all edges leading out from the specified source vertex.
30 + *
31 + * @param src source vertex
32 + * @return set of egress edges; empty if no such edges
33 + */
34 + Set<E> getEdgesFrom(V src);
35 +
36 + /**
37 + * Returns all edges leading towards the specified destination vertex.
38 + *
39 + * @param dst destination vertex
40 + * @return set of ingress vertexes; empty if no such edges
41 + */
42 + Set<E> getEdgesTo(V dst);
43 +
44 +}
1 +package org.onlab.graph;
2 +
3 +import java.util.Map;
4 +import java.util.Set;
5 +
6 +/**
7 + * Representation of a graph path search algorithm.
8 + *
9 + * @param <V> vertex type
10 + * @param <E> edge type
11 + */
12 +public interface GraphPathSearch<V extends Vertex, E extends Edge<V>> {
13 +
14 + /**
15 + * Abstraction of a path search result.
16 + */
17 + public interface Result<V extends Vertex, E extends Edge<V>> {
18 +
19 + /**
20 + * Returns the search source.
21 + *
22 + * @return search source
23 + */
24 + public V src();
25 +
26 + /**
27 + * Returns the search destination, if was was given.
28 + *
29 + * @return optional search destination
30 + */
31 + public V dst();
32 +
33 + /**
34 + * Returns the set of paths produced as a result of the graph search.
35 + *
36 + * @return set of paths
37 + */
38 + Set<Path<V, E>> paths();
39 +
40 + /**
41 + * Returns bindings of each vertex to its parent edges in the path.
42 + *
43 + * @return map of vertex to its parent edge bindings
44 + */
45 + public Map<V, Set<E>> parents();
46 +
47 + /**
48 + * Return a bindings of each vertex to its cost in the path.
49 + *
50 + * @return map of vertex to path cost bindings
51 + */
52 + public Map<V, Double> costs();
53 + }
54 +
55 + /**
56 + * Searches the specified graph.
57 + *
58 + * @param graph graph to be searched
59 + * @param src optional source vertex
60 + * @param dst optional destination vertex; if null paths to all vertex
61 + * destinations will be searched
62 + * @param weight optional edge-weight; if null cost of each edge will be
63 + * assumed to be 1.0
64 + * @return search results
65 + */
66 + Result<V, E> search(Graph<V, E> graph, V src, V dst, EdgeWeight<V, E> weight);
67 +
68 +}
1 +package org.onlab.graph;
2 +
3 +/**
4 + * Representation of a graph search algorithm and its outcome.
5 + *
6 + * @param <V> vertex type
7 + * @param <E> edge type
8 + */
9 +public interface GraphSearch<V extends Vertex, E extends Edge<V>> {
10 +
11 + /**
12 + * Notion of a graph search result.
13 + */
14 + public interface Result<V extends Vertex, E extends Edge<V>> {
15 + }
16 +
17 + /**
18 + * Searches the specified graph.
19 + *
20 + * @param graph graph to be searched
21 + * @param weight optional edge-weight; if null cost of each edge will be
22 + * assumed to be 1.0
23 + *
24 + * @return search results
25 + */
26 + Result search(Graph<V, E> graph, EdgeWeight<V, E> weight);
27 +
28 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.collect.ImmutableList;
4 +
5 +import java.util.Comparator;
6 +import java.util.Iterator;
7 +import java.util.List;
8 +import java.util.Objects;
9 +
10 +import static com.google.common.base.Preconditions.checkNotNull;
11 +
12 +/**
13 + * Implementation of an array-backed heap structure whose sense of order is
14 + * imposed by the provided comparator.
15 + * <p/>
16 + * While this provides similar functionality to {@link java.util.PriorityQueue}
17 + * data structure, one key difference is that external entities can control
18 + * when to restore the heap property, which is done through invocation of the
19 + * {@link #heapify} method.
20 + * <p/>
21 + * This class is not thread-safe and care must be taken to prevent concurrent
22 + * modifications.
23 + *
24 + * @param <T> type of the items on the heap
25 + */
26 +public class Heap<T> {
27 +
28 + private final List<T> data;
29 + private final Comparator<T> comparator;
30 +
31 + /**
32 + * Creates a new heap backed by the specified list. In the interest of
33 + * efficiency, the list should be array-backed. Also, for the same reason,
34 + * the data is not copied and therefore, the caller must assure that the
35 + * backing data is not altered in any way.
36 + *
37 + * @param data backing data list
38 + * @param comparator comparator for ordering the heap items
39 + */
40 + public Heap(List<T> data, Comparator<T> comparator) {
41 + this.data = checkNotNull(data, "Data cannot be null");
42 + this.comparator = checkNotNull(comparator, "Comparator cannot be null");
43 + heapify();
44 + }
45 +
46 + /**
47 + * Restores the heap property by re-arranging the elements in the backing
48 + * array as necessary following any heap modifications.
49 + */
50 + public void heapify() {
51 + for (int i = data.size() / 2; i >= 0; i--) {
52 + heapify(i);
53 + }
54 + }
55 +
56 + /**
57 + * Returns the current size of the heap.
58 + *
59 + * @return number of items in the heap
60 + */
61 + public int size() {
62 + return data.size();
63 + }
64 +
65 + /**
66 + * Returns true if there are no items in the heap.
67 + *
68 + * @return true if heap is empty
69 + */
70 + public boolean isEmpty() {
71 + return data.isEmpty();
72 + }
73 +
74 + /**
75 + * Returns the most extreme item in the heap.
76 + *
77 + * @return heap extreme or null if the heap is empty
78 + */
79 + public T extreme() {
80 + return data.isEmpty() ? null : data.get(0);
81 + }
82 +
83 + /**
84 + * Extracts and returns the most extreme item from the heap.
85 + *
86 + * @return heap extreme or null if the heap is empty
87 + */
88 + public T extractExtreme() {
89 + if (!isEmpty()) {
90 + T extreme = extreme();
91 +
92 + data.set(0, data.get(data.size() - 1));
93 + data.remove(data.size() - 1);
94 + heapify();
95 + return extreme;
96 + }
97 + return null;
98 + }
99 +
100 + /**
101 + * Inserts the specified item into the heap and returns the modified heap.
102 + *
103 + * @param item item to be inserted
104 + * @return the heap self
105 + * @throws IllegalArgumentException if the heap is already full
106 + */
107 + public Heap<T> insert(T item) {
108 + data.add(item);
109 + bubbleUp();
110 + return this;
111 + }
112 +
113 + /**
114 + * Returns iterator to traverse the heap level-by-level. This iterator
115 + * does not permit removal of items.
116 + *
117 + * @return non-destructive heap iterator
118 + */
119 + public Iterator<T> iterator() {
120 + return ImmutableList.copyOf(data).iterator();
121 + }
122 +
123 + // Bubbles up the last item in the heap to its proper position to restore
124 + // the heap property.
125 + private void bubbleUp() {
126 + int child = data.size() - 1;
127 + while (child > 0) {
128 + int parent = child / 2;
129 + if (comparator.compare(data.get(child), data.get(parent)) < 0) {
130 + break;
131 + }
132 + swap(child, parent);
133 + child = parent;
134 + }
135 + }
136 +
137 + // Restores the heap property of the specified heap layer.
138 + private void heapify(int i) {
139 + int left = 2 * i + 1;
140 + int right = 2 * i;
141 + int extreme = i;
142 +
143 + if (left < data.size() &&
144 + comparator.compare(data.get(extreme), data.get(left)) < 0) {
145 + extreme = left;
146 + }
147 +
148 + if (right < data.size() &&
149 + comparator.compare(data.get(extreme), data.get(right)) < 0) {
150 + extreme = right;
151 + }
152 +
153 + if (extreme != i) {
154 + swap(i, extreme);
155 + heapify(extreme);
156 + }
157 + }
158 +
159 + // Swaps two heap items identified by their respective indexes.
160 + private void swap(int i, int k) {
161 + T aux = data.get(i);
162 + data.set(i, data.get(k));
163 + data.set(k, aux);
164 + }
165 +
166 + @Override
167 + public boolean equals(Object obj) {
168 + if (obj instanceof Heap) {
169 + Heap that = (Heap) obj;
170 + return this.getClass() == that.getClass() &&
171 + Objects.equals(this.comparator, that.comparator) &&
172 + Objects.deepEquals(this.data, that.data);
173 + }
174 + return false;
175 + }
176 +
177 + @Override
178 + public int hashCode() {
179 + return Objects.hash(comparator, data);
180 + }
181 +
182 + @Override
183 + public String toString() {
184 + return com.google.common.base.Objects.toStringHelper(this)
185 + .add("data", data)
186 + .add("comparator", comparator)
187 + .toString();
188 + }
189 +
190 +}
1 +package org.onlab.graph;
2 +
3 +/**
4 + * Abstraction of a mutable graph that can be constructed gradually.
5 + */
6 +public interface MutableGraph<V extends Vertex, E extends Edge> extends Graph<V, E> {
7 +
8 + /**
9 + * Adds the specified vertex to this graph.
10 + *
11 + * @param vertex new vertex
12 + */
13 + void addVertex(V vertex);
14 +
15 + /**
16 + * Removes the specified vertex from the graph.
17 + *
18 + * @param vertex vertex to be removed
19 + */
20 + void removeVertex(V vertex);
21 +
22 + /**
23 + * Adds the specified edge to this graph. If the edge vertexes are not
24 + * already in the graph, they will be added as well.
25 + *
26 + * @param edge new edge
27 + */
28 + void addEdge(E edge);
29 +
30 + /**
31 + * Removes the specified edge from the graph.
32 + *
33 + * @param edge edge to be removed
34 + */
35 + void removeEdge(E edge);
36 +
37 + /**
38 + * Returns an immutable copy of this graph.
39 + *
40 + * @return immutable copy
41 + */
42 + Graph<V, E> toImmutable();
43 +
44 +}
1 +package org.onlab.graph;
2 +
3 +/**
4 + * Abstraction of a mutable path that allows gradual construction.
5 + */
6 +public interface MutablePath<V extends Vertex, E extends Edge<V>> extends Path<V, E> {
7 +
8 + /**
9 + * Inserts a new edge at the beginning of this path. The edge must be
10 + * adjacent to the prior start of the path.
11 + *
12 + * @param edge edge to be inserted
13 + */
14 + void insertEdge(E edge);
15 +
16 + /**
17 + * Appends a new edge at the end of the this path. The edge must be
18 + * adjacent to the prior end of the path.
19 + *
20 + * @param edge edge to be inserted
21 + */
22 + void appendEdge(E edge);
23 +
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 + /**
34 + * Sets the total path cost as a unit-less double.
35 + *
36 + * @param cost new path cost
37 + */
38 + void setCost(double cost);
39 +
40 + /**
41 + * Returns an immutable copy of this path.
42 + *
43 + * @return immutable copy
44 + */
45 + Path<V, E> toImmutable();
46 +
47 +}
1 +package org.onlab.graph;
2 +
3 +import java.util.List;
4 +
5 +/**
6 + * Representation of a path in a graph as a sequence of edges. Paths are
7 + * assumed to be continuous, where adjacent edges must share a vertex.
8 + *
9 + * @param <V> vertex type
10 + * @param <E> edge type
11 + */
12 +public interface Path<V extends Vertex, E extends Edge<V>> extends Edge<V> {
13 +
14 + /**
15 + * Returns the list of edges comprising the path. Adjacent edges will
16 + * share the same vertex, meaning that a source of one edge, will be the
17 + * same as the destination of the prior edge.
18 + *
19 + * @return list of path edges
20 + */
21 + List<E> edges();
22 +
23 + /**
24 + * Returns the total cost of the path as a unit-less number.
25 + *
26 + * @return path cost as a unit-less number
27 + */
28 + double cost();
29 +
30 +}
1 +package org.onlab.graph;
2 +
3 +/**
4 + * Representation of a graph vertex.
5 + */
6 +public interface Vertex {
7 +}
1 +<body>
2 +Graph abstractions and graph path finding algorithms.
3 +</body>
...\ No newline at end of file ...\ No newline at end of file
1 +<body>
2 +Miscellaneous domain-agnostic utilities.
3 +</body>
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onlab.graph;
2 +
3 +import com.google.common.testing.EqualsTester;
4 +import org.junit.Test;
5 +
6 +/**
7 + * Test of the base edge implementation.
8 + */
9 +public class AbstractEdgeTest {
10 +
11 + @Test
12 + public void equality() {
13 + TestVertex v1 = new TestVertex("1");
14 + TestVertex v2 = new TestVertex("2");
15 + new EqualsTester()
16 + .addEqualityGroup(new TestEdge(v1, v2, 1),
17 + new TestEdge(v1, v2, 1))
18 + .addEqualityGroup(new TestEdge(v2, v1, 1))
19 + .testEquals();
20 + }
21 +
22 +}
1 +package org.onlab.graph;
2 +
3 +import org.junit.Test;
4 +
5 +import static com.google.common.collect.ImmutableSet.of;
6 +import static org.junit.Assert.assertEquals;
7 +
8 +/**
9 + * Base for all graph search tests.
10 + */
11 +public abstract class AbstractGraphPathSearchTest extends GraphTest {
12 +
13 + /**
14 + * Creates a test-specific graph search to exercise.
15 + *
16 + * @return graph search
17 + */
18 + protected abstract AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch();
19 +
20 + @Test(expected = IllegalArgumentException.class)
21 + public void noSuchSourceArgument() {
22 + graphSearch().search(new AdjacencyListsGraph<>(of(B, C),
23 + of(new TestEdge(B, C, 1))),
24 + A, H, weight);
25 + }
26 +
27 + @Test(expected = NullPointerException.class)
28 + public void nullGraphArgument() {
29 + graphSearch().search(null, A, H, weight);
30 + }
31 +
32 + @Test(expected = NullPointerException.class)
33 + public void nullSourceArgument() {
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);
44 + }
45 +
46 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.collect.ImmutableSet;
4 +import com.google.common.testing.EqualsTester;
5 +import org.junit.Test;
6 +
7 +import java.util.Set;
8 +
9 +import static org.junit.Assert.assertEquals;
10 +
11 +/**
12 + * Tests of the graph implementation.
13 + */
14 +public class AdjacencyListsGraphTest {
15 +
16 + private static final TestVertex A = new TestVertex("A");
17 + private static final TestVertex B = new TestVertex("B");
18 + private static final TestVertex C = new TestVertex("C");
19 + private static final TestVertex D = new TestVertex("D");
20 + private static final TestVertex E = new TestVertex("E");
21 + private static final TestVertex F = new TestVertex("F");
22 + private static final TestVertex G = new TestVertex("G");
23 +
24 + private final Set<TestEdge> edges =
25 + ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(B, C, 1),
26 + new TestEdge(C, D, 1), new TestEdge(D, A, 1),
27 + new TestEdge(B, D, 1));
28 +
29 + @Test
30 + public void equality() {
31 + Set<TestVertex> vertexes = ImmutableSet.of(A, B, C, D, E, F);
32 + Set<TestVertex> vertexes2 = ImmutableSet.of(A, B, C, D, E, F, G);
33 +
34 + AdjacencyListsGraph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(vertexes, edges);
35 + AdjacencyListsGraph<TestVertex, TestEdge> same = new AdjacencyListsGraph<>(vertexes, edges);
36 + AdjacencyListsGraph<TestVertex, TestEdge> different = new AdjacencyListsGraph<>(vertexes2, edges);
37 +
38 + new EqualsTester()
39 + .addEqualityGroup(graph, same)
40 + .addEqualityGroup(different)
41 + .testEquals();
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 + }
57 +}
1 +package org.onlab.graph;
2 +
3 +import org.junit.Test;
4 +
5 +import java.util.HashSet;
6 +import java.util.Set;
7 +
8 +import static org.junit.Assert.assertEquals;
9 +
10 +/**
11 + * Test of the Bellman-Ford algorithm.
12 + */
13 +public class BellmanFordGraphSearchTest extends BreadthFirstSearchTest {
14 +
15 + @Override
16 + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() {
17 + return new BellmanFordGraphSearch<>();
18 + }
19 +
20 + @Test
21 + @Override
22 + public void defaultGraphTest() {
23 + executeDefaultTest(7, 5, 5.0);
24 + }
25 +
26 + @Test
27 + public void defaultHopCountWeight() {
28 + weight = null;
29 + executeDefaultTest(10, 3, 3.0);
30 + }
31 +
32 + @Test
33 + public void searchGraphWithNegativeCycles() {
34 + Set<TestVertex> vertexes = new HashSet<>(vertices());
35 + vertexes.add(Z);
36 +
37 + Set<TestEdge> edges = new HashSet<>(edges());
38 + edges.add(new TestEdge(G, Z, 1.0));
39 + edges.add(new TestEdge(Z, G, -2.0));
40 +
41 + g = new AdjacencyListsGraph<>(vertexes, edges);
42 +
43 + GraphPathSearch<TestVertex, TestEdge> search = graphSearch();
44 + Set<Path<TestVertex, TestEdge>> paths = search.search(g, A, H, weight).paths();
45 + assertEquals("incorrect paths count", 1, paths.size());
46 +
47 + Path p = paths.iterator().next();
48 + assertEquals("incorrect src", A, p.src());
49 + assertEquals("incorrect dst", H, p.dst());
50 + assertEquals("incorrect path length", 5, p.edges().size());
51 + assertEquals("incorrect path cost", 5.0, p.cost(), 0.1);
52 +
53 + paths = search.search(g, A, G, weight).paths();
54 + assertEquals("incorrect paths count", 0, paths.size());
55 +
56 + paths = search.search(g, A, null, weight).paths();
57 + printPaths(paths);
58 + assertEquals("incorrect paths count", 6, paths.size());
59 + }
60 +
61 +}
1 +package org.onlab.graph;
2 +
3 +import org.junit.Test;
4 +
5 +import java.util.Set;
6 +
7 +import static org.junit.Assert.assertEquals;
8 +
9 +/**
10 + * Test of the BFS and similar path search algorithms.
11 + */
12 +public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest {
13 +
14 + @Override
15 + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() {
16 + return new BreadthFirstSearch<>();
17 + }
18 +
19 + @Test
20 + public void defaultGraphTest() {
21 + executeDefaultTest(7, 3, 8.0);
22 + }
23 +
24 + @Test
25 + public void defaultHopCountWeight() {
26 + weight = null;
27 + executeDefaultTest(7, 3, 3.0);
28 + }
29 +
30 + // Executes the default test
31 + protected void executeDefaultTest(int pathCount, int pathLength, double pathCost) {
32 + g = new AdjacencyListsGraph<>(vertices(), edges());
33 +
34 + GraphPathSearch<TestVertex, TestEdge> search = graphSearch();
35 + Set<Path<TestVertex, TestEdge>> paths = search.search(g, A, H, weight).paths();
36 + assertEquals("incorrect paths count", 1, paths.size());
37 +
38 + Path p = paths.iterator().next();
39 + assertEquals("incorrect src", A, p.src());
40 + assertEquals("incorrect dst", H, p.dst());
41 + assertEquals("incorrect path length", pathLength, p.edges().size());
42 + assertEquals("incorrect path cost", pathCost, p.cost(), 0.1);
43 +
44 + paths = search.search(g, A, null, weight).paths();
45 + printPaths(paths);
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 + }
64 + }
65 +
66 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.testing.EqualsTester;
4 +import org.junit.Test;
5 +
6 +import static com.google.common.collect.ImmutableList.of;
7 +import static org.junit.Assert.assertEquals;
8 +import static org.junit.Assert.assertNull;
9 +
10 +/**
11 + * Test of the default mutable path.
12 + */
13 +public class DefaultMutablePathTest extends DefaultPathTest {
14 +
15 + @Test
16 + public void equality() {
17 + DefaultPath<TestVertex, TestEdge> p1 =
18 + new DefaultPath<>(of(new TestEdge(A, B, 1),
19 + new TestEdge(B, C, 1)), 2.0);
20 + DefaultPath<TestVertex, TestEdge> p2 =
21 + new DefaultPath<>(of(new TestEdge(A, B, 1),
22 + new TestEdge(B, D, 1)), 2.0);
23 + new EqualsTester().addEqualityGroup(new DefaultMutablePath<>(p1),
24 + new DefaultMutablePath<>(p1))
25 + .addEqualityGroup(new DefaultMutablePath<>(p2))
26 + .testEquals();
27 + }
28 +
29 + @Test
30 + public void empty() {
31 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
32 + assertNull("src should be null", p.src());
33 + assertNull("dst should be null", p.dst());
34 + assertEquals("incorrect edge count", 0, p.edges().size());
35 + assertEquals("incorrect path cost", 0.0, p.cost(), 0.1);
36 + }
37 +
38 + @Test
39 + public void pathCost() {
40 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
41 + p.setCost(4);
42 + assertEquals("incorrect path cost", 4.0, p.cost(), 0.1);
43 + }
44 +
45 + private void validatePath(Path<TestVertex, TestEdge> p,
46 + TestVertex src, TestVertex dst, int length) {
47 + validatePath(p, src, dst, length, 0.0);
48 + }
49 +
50 + @Test
51 + public void insertEdge() {
52 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
53 + p.insertEdge(new TestEdge(B, C, 1));
54 + p.insertEdge(new TestEdge(A, B, 1));
55 + validatePath(p, A, C, 2);
56 + }
57 +
58 + @Test
59 + public void appendEdge() {
60 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
61 + p.appendEdge(new TestEdge(A, B, 1));
62 + p.appendEdge(new TestEdge(B, C, 1));
63 + validatePath(p, A, C, 2);
64 + }
65 +
66 + @Test
67 + public void removeEdge() {
68 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
69 + p.appendEdge(new TestEdge(A, B, 1));
70 + p.appendEdge(new TestEdge(B, C, 1));
71 + p.appendEdge(new TestEdge(C, C, 2));
72 + p.appendEdge(new TestEdge(C, D, 1));
73 + validatePath(p, A, D, 4);
74 +
75 + p.removeEdge(new TestEdge(A, B, 1));
76 + validatePath(p, B, D, 3);
77 +
78 + p.removeEdge(new TestEdge(C, C, 2));
79 + validatePath(p, B, D, 2);
80 +
81 + p.removeEdge(new TestEdge(C, D, 1));
82 + validatePath(p, B, C, 1);
83 + }
84 +
85 + @Test
86 + public void toImmutable() {
87 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
88 + p.appendEdge(new TestEdge(A, B, 1));
89 + p.appendEdge(new TestEdge(B, C, 1));
90 + validatePath(p, A, C, 2);
91 +
92 + assertEquals("immutables should equal", p.toImmutable(), p.toImmutable());
93 + validatePath(p.toImmutable(), A, C, 2);
94 + }
95 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.testing.EqualsTester;
4 +import org.junit.Test;
5 +
6 +import java.util.List;
7 +
8 +import static com.google.common.collect.ImmutableList.of;
9 +import static org.junit.Assert.assertEquals;
10 +
11 +/**
12 + * Test of the default path.
13 + */
14 +public class DefaultPathTest extends GraphTest {
15 +
16 + @Test
17 + public void equality() {
18 + List<TestEdge> edges = of(new TestEdge(A, B, 1), new TestEdge(B, C, 1));
19 + new EqualsTester().addEqualityGroup(new DefaultPath<>(edges, 2.0),
20 + new DefaultPath<>(edges, 2.0))
21 + .addEqualityGroup(new DefaultPath<>(edges, 3.0))
22 + .testEquals();
23 + }
24 +
25 + @Test
26 + public void basics() {
27 + Path<TestVertex, TestEdge> p = new DefaultPath<>(of(new TestEdge(A, B, 1),
28 + new TestEdge(B, C, 1)), 2.0);
29 + validatePath(p, A, C, 2, 2.0);
30 + }
31 +
32 + // Validates the path against expected attributes
33 + protected void validatePath(Path<TestVertex, TestEdge> p,
34 + TestVertex src, TestVertex dst,
35 + int length, double cost) {
36 + assertEquals("incorrect path length", length, p.edges().size());
37 + assertEquals("incorrect source", src, p.src());
38 + assertEquals("incorrect destination", dst, p.dst());
39 + assertEquals("incorrect path cost", cost, p.cost(), 0.1);
40 + }
41 +
42 +}
1 +package org.onlab.graph;
2 +
3 +import org.junit.Test;
4 +
5 +import java.util.Set;
6 +
7 +import static org.junit.Assert.assertEquals;
8 +import static org.junit.Assert.assertTrue;
9 +import static org.onlab.graph.DepthFirstSearch.EdgeType;
10 +
11 +/**
12 + * Test of the DFS algorithm.
13 + */
14 +public class DepthFirstSearchTest extends AbstractGraphPathSearchTest {
15 +
16 + @Override
17 + protected DepthFirstSearch<TestVertex, TestEdge> graphSearch() {
18 + return new DepthFirstSearch<>();
19 + }
20 +
21 + @Test
22 + public void defaultGraphTest() {
23 + executeDefaultTest(3, 6, 5.0, 12.0);
24 + executeBroadSearch();
25 + }
26 +
27 + @Test
28 + public void defaultHopCountWeight() {
29 + weight = null;
30 + executeDefaultTest(3, 6, 3.0, 6.0);
31 + executeBroadSearch();
32 + }
33 +
34 + protected void executeDefaultTest(int minLength, int maxLength,
35 + double minCost, double maxCost) {
36 + g = new AdjacencyListsGraph<>(vertices(), edges());
37 + DepthFirstSearch<TestVertex, TestEdge> search = graphSearch();
38 +
39 + DepthFirstSearch<TestVertex, TestEdge>.SpanningTreeResult result =
40 + search.search(g, A, H, weight);
41 + Set<Path<TestVertex, TestEdge>> paths = result.paths();
42 + assertEquals("incorrect path count", 1, paths.size());
43 +
44 + Path path = paths.iterator().next();
45 + System.out.println(path);
46 + assertEquals("incorrect src", A, path.src());
47 + assertEquals("incorrect dst", H, path.dst());
48 +
49 + int l = path.edges().size();
50 + assertTrue("incorrect path length " + l,
51 + minLength <= l && l <= maxLength);
52 + assertTrue("incorrect path cost " + path.cost(),
53 + minCost <= path.cost() && path.cost() <= maxCost);
54 +
55 + System.out.println(result.edges());
56 + printPaths(paths);
57 + }
58 +
59 + public void executeBroadSearch() {
60 + g = new AdjacencyListsGraph<>(vertices(), edges());
61 + DepthFirstSearch<TestVertex, TestEdge> search = graphSearch();
62 +
63 + // Perform narrow path search to a specific destination.
64 + DepthFirstSearch<TestVertex, TestEdge>.SpanningTreeResult result =
65 + search.search(g, A, null, weight);
66 + assertEquals("incorrect paths count", 7, result.paths().size());
67 +
68 + int[] types = new int[]{0, 0, 0, 0};
69 + for (EdgeType t : result.edges().values()) {
70 + types[t.ordinal()] += 1;
71 + }
72 + assertEquals("incorrect tree-edge count", 7,
73 + types[EdgeType.TREE_EDGE.ordinal()]);
74 + assertEquals("incorrect back-edge count", 1,
75 + types[EdgeType.BACK_EDGE.ordinal()]);
76 + assertEquals("incorrect cross-edge & forward-edge count", 4,
77 + types[EdgeType.FORWARD_EDGE.ordinal()] +
78 + types[EdgeType.CROSS_EDGE.ordinal()]);
79 + }
80 +
81 +}
1 +package org.onlab.graph;
2 +
3 +import org.junit.Test;
4 +
5 +import java.util.Set;
6 +
7 +import static com.google.common.collect.ImmutableSet.of;
8 +import static org.junit.Assert.assertEquals;
9 +
10 +/**
11 + * Test of the Dijkstra algorithm.
12 + */
13 +public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
14 +
15 + @Override
16 + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() {
17 + return new DijkstraGraphSearch<>();
18 + }
19 +
20 + @Test
21 + @Override
22 + public void defaultGraphTest() {
23 + executeDefaultTest(7, 5, 5.0);
24 + }
25 +
26 + @Test
27 + @Override
28 + public void defaultHopCountWeight() {
29 + weight = null;
30 + executeDefaultTest(10, 3, 3.0);
31 + }
32 +
33 + @Test
34 + public void noPath() {
35 + g = new AdjacencyListsGraph<>(of(A, B, C, D),
36 + of(new TestEdge(A, B, 1),
37 + new TestEdge(B, A, 1),
38 + new TestEdge(C, D, 1),
39 + new TestEdge(D, C, 1)));
40 + GraphPathSearch<TestVertex, TestEdge> gs = graphSearch();
41 + Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, B, weight).paths();
42 + printPaths(paths);
43 + assertEquals("incorrect paths count", 1, paths.size());
44 + assertEquals("incorrect path cost", 1.0, paths.iterator().next().cost(), 0.1);
45 +
46 + paths = gs.search(g, A, D, weight).paths();
47 + printPaths(paths);
48 + assertEquals("incorrect paths count", 0, paths.size());
49 +
50 + paths = gs.search(g, A, null, weight).paths();
51 + printPaths(paths);
52 + assertEquals("incorrect paths count", 1, paths.size());
53 + assertEquals("incorrect path cost", 1.0, paths.iterator().next().cost(), 0.1);
54 + }
55 +
56 + @Test
57 + public void simpleMultiplePath() {
58 + g = new AdjacencyListsGraph<>(of(A, B, C, D),
59 + of(new TestEdge(A, B, 1),
60 + new TestEdge(A, C, 1),
61 + new TestEdge(B, D, 1),
62 + new TestEdge(C, D, 1)));
63 + executeSearch(graphSearch(), g, A, D, weight, 2, 2.0);
64 + }
65 +
66 + @Test
67 + public void denseMultiplePath() {
68 + g = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G),
69 + of(new TestEdge(A, B, 1),
70 + new TestEdge(A, C, 1),
71 + new TestEdge(B, D, 1),
72 + new TestEdge(C, D, 1),
73 + new TestEdge(D, E, 1),
74 + new TestEdge(D, F, 1),
75 + new TestEdge(E, G, 1),
76 + new TestEdge(F, G, 1),
77 + new TestEdge(A, G, 4)));
78 + executeSearch(graphSearch(), g, A, G, weight, 5, 4.0);
79 + }
80 +
81 + @Test
82 + public void dualEdgeMultiplePath() {
83 + g = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G, H),
84 + of(new TestEdge(A, B, 1), new TestEdge(A, C, 3),
85 + new TestEdge(B, D, 2), new TestEdge(B, C, 1),
86 + new TestEdge(B, E, 4), new TestEdge(C, E, 1),
87 + new TestEdge(D, H, 5), new TestEdge(D, E, 1),
88 + new TestEdge(E, F, 1), new TestEdge(F, D, 1),
89 + new TestEdge(F, G, 1), new TestEdge(F, H, 1),
90 + new TestEdge(A, E, 3), new TestEdge(B, D, 1)));
91 + executeSearch(graphSearch(), g, A, E, weight, 3, 3.0);
92 + }
93 +
94 +}
1 +package org.onlab.graph;
2 +
3 +import java.util.Set;
4 +
5 +import static com.google.common.collect.ImmutableSet.of;
6 +
7 +/**
8 + * Base class for various graph-related tests.
9 + */
10 +public class GraphTest {
11 +
12 + static final TestVertex A = new TestVertex("A");
13 + static final TestVertex B = new TestVertex("B");
14 + static final TestVertex C = new TestVertex("C");
15 + static final TestVertex D = new TestVertex("D");
16 + static final TestVertex E = new TestVertex("E");
17 + static final TestVertex F = new TestVertex("F");
18 + static final TestVertex G = new TestVertex("G");
19 + static final TestVertex H = new TestVertex("H");
20 + static final TestVertex Z = new TestVertex("Z");
21 +
22 + protected Graph<TestVertex, TestEdge> g;
23 +
24 + protected EdgeWeight<TestVertex, TestEdge> weight =
25 + new EdgeWeight<TestVertex, TestEdge>() {
26 + @Override
27 + public double weight(TestEdge edge) {
28 + return edge.weight();
29 + }
30 + };
31 +
32 + protected void printPaths(Set<Path<TestVertex, TestEdge>> paths) {
33 + for (Path p : paths) {
34 + System.out.println(p);
35 + }
36 + }
37 +
38 + protected Set<TestVertex> vertices() {
39 + return of(A, B, C, D, E, F, G, H);
40 + }
41 +
42 + protected Set<TestEdge> edges() {
43 + return of(new TestEdge(A, B, 1), new TestEdge(A, C, 3),
44 + new TestEdge(B, D, 2), new TestEdge(B, C, 1),
45 + new TestEdge(B, E, 4), new TestEdge(C, E, 1),
46 + new TestEdge(D, H, 5), new TestEdge(D, E, 1),
47 + new TestEdge(E, F, 1), new TestEdge(F, D, 1),
48 + new TestEdge(F, G, 1), new TestEdge(F, H, 1));
49 + }
50 +
51 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.collect.Ordering;
4 +import com.google.common.testing.EqualsTester;
5 +import org.junit.Test;
6 +
7 +import java.util.ArrayList;
8 +import java.util.Comparator;
9 +
10 +import static com.google.common.collect.ImmutableList.of;
11 +import static org.junit.Assert.*;
12 +
13 +/**
14 + * Heap data structure tests.
15 + */
16 +public class HeapTest {
17 +
18 + private ArrayList<Integer> data =
19 + new ArrayList<>(of(6, 4, 5, 9, 8, 3, 2, 1, 7, 0));
20 +
21 + private static final Comparator<Integer> MIN = Ordering.natural().reverse();
22 + private static final Comparator<Integer> MAX = Ordering.natural();
23 +
24 + @Test
25 + public void equality() {
26 + new EqualsTester()
27 + .addEqualityGroup(new Heap<>(data, MIN),
28 + new Heap<>(data, MIN))
29 + .addEqualityGroup(new Heap<>(data, MAX))
30 + .testEquals();
31 + }
32 +
33 + @Test
34 + public void empty() {
35 + Heap<Integer> h = new Heap<>(new ArrayList<Integer>(), MIN);
36 + assertTrue("should be empty", h.isEmpty());
37 + assertEquals("incorrect size", 0, h.size());
38 + assertNull("no item expected", h.extreme());
39 + assertNull("no item expected", h.extractExtreme());
40 + }
41 +
42 + @Test
43 + public void insert() {
44 + Heap<Integer> h = new Heap<>(data, MIN);
45 + assertEquals("incorrect size", 10, h.size());
46 + h.insert(3);
47 + assertEquals("incorrect size", 11, h.size());
48 + }
49 +
50 + @Test
51 + public void minQueue() {
52 + Heap<Integer> h = new Heap<>(data, MIN);
53 + assertFalse("should not be empty", h.isEmpty());
54 + assertEquals("incorrect size", 10, h.size());
55 + assertEquals("incorrect extreme", (Integer) 0, h.extreme());
56 +
57 + for (int i = 0, n = h.size(); i < n; i++) {
58 + assertEquals("incorrect element", (Integer) i, h.extractExtreme());
59 + }
60 + assertTrue("should be empty", h.isEmpty());
61 + }
62 +
63 + @Test
64 + public void maxQueue() {
65 + Heap<Integer> h = new Heap<>(data, MAX);
66 + assertFalse("should not be empty", h.isEmpty());
67 + assertEquals("incorrect size", 10, h.size());
68 + assertEquals("incorrect extreme", (Integer) 9, h.extreme());
69 +
70 + for (int i = h.size(); i > 0; i--) {
71 + assertEquals("incorrect element", (Integer) (i - 1), h.extractExtreme());
72 + }
73 + assertTrue("should be empty", h.isEmpty());
74 + }
75 +
76 + @Test
77 + public void iterator() {
78 + Heap<Integer> h = new Heap<>(data, MIN);
79 + assertTrue("should have next element", h.iterator().hasNext());
80 + }
81 +
82 +}
1 +package org.onlab.graph;
2 +
3 +import java.util.Objects;
4 +
5 +import static com.google.common.base.Objects.toStringHelper;
6 +
7 +/**
8 + * Test edge.
9 + */
10 +public class TestEdge extends AbstractEdge<TestVertex> {
11 +
12 + private final double weight;
13 +
14 + /**
15 + * Creates a new edge between the specified source and destination vertexes.
16 + *
17 + * @param src source vertex
18 + * @param dst destination vertex
19 + * @param weight edge weight
20 + */
21 + public TestEdge(TestVertex src, TestVertex dst, double weight) {
22 + super(src, dst);
23 + this.weight = weight;
24 + }
25 +
26 + /**
27 + * Returns the edge weight.
28 + *
29 + * @return edge weight
30 + */
31 + public double weight() {
32 + return weight;
33 + }
34 +
35 + @Override
36 + public int hashCode() {
37 + return 31 * super.hashCode() + Objects.hash(weight);
38 + }
39 +
40 + @Override
41 + public boolean equals(Object obj) {
42 + if (obj instanceof TestEdge) {
43 + final TestEdge other = (TestEdge) obj;
44 + return super.equals(obj) && Objects.equals(this.weight, other.weight);
45 + }
46 + return false;
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 +
55 +}
1 +package org.onlab.graph;
2 +
3 +import java.util.Objects;
4 +
5 +/**
6 + * Test vertex.
7 + */
8 +public class TestVertex implements Vertex {
9 +
10 + private final String name;
11 +
12 + public TestVertex(String name) {
13 + this.name = name;
14 + }
15 +
16 + @Override
17 + public int hashCode() {
18 + return Objects.hash(name);
19 + }
20 +
21 + @Override
22 + public boolean equals(Object obj) {
23 + if (obj instanceof TestVertex) {
24 + final TestVertex other = (TestVertex) obj;
25 + return Objects.equals(this.name, other.name);
26 + }
27 + return false;
28 + }
29 +
30 + @Override
31 + public String toString() {
32 + return name;
33 + }
34 +
35 +}