Init
- init with the first interface and tests - added some basic class for the tests
This commit is contained in:
BIN
.gitignore
vendored
Normal file
BIN
.gitignore
vendored
Normal file
Binary file not shown.
463
src/berack96/sim/util/graph/Graph.java
Normal file
463
src/berack96/sim/util/graph/Graph.java
Normal file
@@ -0,0 +1,463 @@
|
||||
package berack96.sim.util.graph;
|
||||
|
||||
import berack96.sim.util.graph.visit.VisitStrategy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An interface for the graphs.<br>
|
||||
* This interface is used for the graphs with Directed edges.<br>
|
||||
* A directed edge between V1 and V2 is an edge that has V1 as source and V2 as destination.<br>
|
||||
*
|
||||
* @param <V> The Object that represent a vertex
|
||||
* @param <W> The Object that represent the edge (more specifically the weight of the edge)
|
||||
* @author Berack96
|
||||
*/
|
||||
public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
|
||||
String NOT_DAG = "The graph is not a DAG";
|
||||
String NOT_CONNECTED = "The source vertex doesn't have a path that reach the destination";
|
||||
String PARAM_NULL = "The parameter must not be null";
|
||||
String VERTEX_NOT_CONTAINED = "The vertex must be contained in the graph";
|
||||
|
||||
/**
|
||||
* Tells if the graph has some cycle.<br>
|
||||
* A cycle is detected if visiting the graph G starting from V1 (that is any of the vertex of G),
|
||||
* the visit can return to V1 in any point.
|
||||
*
|
||||
* @return true if has cycle, false otherwise
|
||||
*/
|
||||
boolean isCyclic();
|
||||
|
||||
/**
|
||||
* Tells if the graph has the property of DAG (Directed Acyclic Graph).<br>
|
||||
* A graph is a DAG only if absent of any cycle. ( see {@link #isCyclic()} )
|
||||
*
|
||||
* @return true if is a DAG, false otherwise
|
||||
*/
|
||||
boolean isDAG();
|
||||
|
||||
/**
|
||||
* Add the vertex to the graph. If it's already in the graph it will be replaced.<br>
|
||||
* Of course the vertex added will have no edge to any other vertex nor form any other vertex.
|
||||
*
|
||||
* @param vertex the vertex to add
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
void addVertex(V vertex) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Add the specified vertex to the graph only if the graph doesn't contains it.<br>
|
||||
* The graph contains a vertex only if the method {@link #contains(V)} returns true.
|
||||
*
|
||||
* @param vertex the vertex to add
|
||||
* @return true if the vertex is added, false if the graph contains the vertex and therefore the new one is not added
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
boolean addVertexIfAbsent(V vertex) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Add all the vertices contained in the set to the graph.<br>
|
||||
* If a vertex is contained in the set and in the graph is ignored and it will not be replaced.<br>
|
||||
* Null vertices will be ignored and they will not be added to the graph.
|
||||
*
|
||||
* @param vertices a set containing the vertices
|
||||
* @throws NullPointerException if the set is null
|
||||
*/
|
||||
void addAllVertices(Set<V> vertices) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Remove the selected vertex from the graph.<br>
|
||||
* After this method's call the vertex will be no longer present in the graph, and nether all his edges.
|
||||
*
|
||||
* @param vertex the vertex to remove
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
void removeVertex(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Remove all the vertex contained in the graph.<br>
|
||||
* After this method's call the graph will be empty; no vertices nor edges.
|
||||
*/
|
||||
void removeAllVertex();
|
||||
|
||||
/**
|
||||
* Check if the vertex passed is contained in the graph or not.<br>
|
||||
* The vertex V1 is contained in the graph G, if and only if:<br>
|
||||
* exist V2 in G such that V2.equals(V1)
|
||||
*
|
||||
* @param vertex the vertex to check
|
||||
* @return true if the vertex is contained, false otherwise
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
boolean contains(V vertex) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Add an edge between the two vertex.<br>
|
||||
* The edge will be created from the vertex V1 and the vertex V2<br>
|
||||
* This method will overwrite any existing edge between the two vertex.<br>
|
||||
* If there was a previous edge then it is returned
|
||||
*
|
||||
* @param vertex1 a vertex of the graph
|
||||
* @param vertex2 a vertex of the graph
|
||||
* @param weight the weight of the edge
|
||||
* @return null or the previous value of the edge if there was already one
|
||||
* @throws NullPointerException if one of the parameter is null
|
||||
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
|
||||
*/
|
||||
W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* This particular function add an edge to the graph.<br>
|
||||
* If one of the two, or both vertices aren't contained in the graph, then the vertices will be added.<br>
|
||||
* The edge will be created from the vertex V1 and the vertex V2<br>
|
||||
* This method will overwrite any existing edge between the two vertex.<br>
|
||||
* If there was a previous edge then it is returned
|
||||
*
|
||||
* @param vertex1 a vertex of the graph
|
||||
* @param vertex2 a vertex of the graph
|
||||
* @param weight the weight of the edge
|
||||
* @return null or the previous value of the edge if there was already one
|
||||
* @throws NullPointerException if one of the parameter is null
|
||||
*/
|
||||
W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Add all the edges of the set in the graph.<br>
|
||||
* If one of the two, or both vertices aren't contained in the graph, then the vertices will be added.<br>
|
||||
* Any null edges will be ignored.<br>
|
||||
* This method will overwrite any existing edge between the two vertex.
|
||||
*
|
||||
* @param edges the edges to add
|
||||
* @throws NullPointerException if the set is null
|
||||
*/
|
||||
void addAllEdges(Set<Edge<V, W>> edges) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Get the weight of the selected edge.<br>
|
||||
* If the edge doesn't exist, then null is returned
|
||||
*
|
||||
* @param vertex1 a vertex of the graph
|
||||
* @param vertex2 a vertex of the graph
|
||||
* @return the weight previously set, or null if the edge doesn't exist
|
||||
* @throws NullPointerException if one of the parameters is null
|
||||
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
|
||||
*/
|
||||
W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Remove the edge between the two vertex.<br>
|
||||
* If the edge doesn't exist, then this call does nothing.<br>
|
||||
* After this method's call it will be no longer possible to travel from V1 to V2, nether from V2 to V1.
|
||||
*
|
||||
* @param vertex1 a vertex of the graph
|
||||
* @param vertex2 a vertex of the graph
|
||||
* @throws NullPointerException if one of the parameters is null
|
||||
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
|
||||
*/
|
||||
void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Remove all the edges that goes in the vertex.<br>
|
||||
* After this method's call it will be no longer possible travel to this vertex.
|
||||
*
|
||||
* @param vertex a vertex of the graph
|
||||
* @throws NullPointerException if one of the parameters is null
|
||||
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
|
||||
*/
|
||||
void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Remove all the edges that start from this vertex.<br>
|
||||
* After this method's call it will be no longer possible travel to any vertex from this one.
|
||||
*
|
||||
* @param vertex a vertex of the graph
|
||||
* @throws NullPointerException if one of the parameters is null
|
||||
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
|
||||
*/
|
||||
void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Remove all edges form a particular vertex of the graph.<br>
|
||||
* After this method's call the selected vertex will have 0 edges.<br>
|
||||
* It will be no longer possible to reach this vertex from any other vertex, and vice versa.
|
||||
*
|
||||
* @param vertex a vertex of the graph
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Remove all the edges of the graph.<br>
|
||||
* After this method's call the graph will have only vertices, and no edge.
|
||||
*/
|
||||
void removeAllEdge();
|
||||
|
||||
/**
|
||||
* Check if the edge between the two vertex passed is contained in the graph or not.<br>
|
||||
* An edge between V1 and V2 is contained in the graph if and only if i can travel from V1 to V2.
|
||||
*
|
||||
* @param vertex1 a vertex of the graph
|
||||
* @param vertex2 a vertex of the graph
|
||||
* @return true if the edge is contained, false otherwise
|
||||
* @throws NullPointerException if one of the parameters is null
|
||||
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
|
||||
*/
|
||||
boolean containsEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Get all the vertices in the graph.<br>
|
||||
* If the graph doesn't contains vertices, it'll return an empty set.<br>
|
||||
* Note that this set is completely different than the set used for the vertices, so any modification of this set will not change the graph.
|
||||
*
|
||||
* @return a set that include all the vertices
|
||||
*/
|
||||
Set<V> vertices();
|
||||
|
||||
/**
|
||||
* Get all the edges in the graph.<br>
|
||||
* If the graph doesn't contains edges, it'll return an empty set.<br>
|
||||
* Note that this set is completely different than the set used for the edges, so any modification of this set will not change the graph.
|
||||
*
|
||||
* @return a set that include all the edges
|
||||
*/
|
||||
Set<Edge<V, W>> edges();
|
||||
|
||||
/**
|
||||
* Get all the vertices that are children of the vertex passed as parameter.<br>
|
||||
* The vertices V(0-N) that are 'children' of a vertex V1, are all the vertices that have an edge
|
||||
* where V1 is the source of that edge.
|
||||
*
|
||||
* @param vertex the source vertex
|
||||
* @return a set of vertices
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
Set<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* This method will get all the child of the vertex selected.<br>
|
||||
* The map created will be a {@link java.util.LinkedHashMap LinkedHashMap}<br>
|
||||
* The order in which the vertex are iterated in the map will be from the vertex with the lowest weight to the one with the highest.
|
||||
*
|
||||
* @param vertex a vertex of the graph
|
||||
* @return a map of all the child and their respective weight
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
Map<V, W> getChildrenAndWeight(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Get all the vertices that have the vertex passed as their child.<br>
|
||||
* Basically is the opposite of {@link #getChildren(Object)}
|
||||
*
|
||||
* @param vertex a vertex of the graph
|
||||
* @return a set of ancestors of the vertex
|
||||
* @throws NullPointerException if one of the parameters is null
|
||||
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
|
||||
*/
|
||||
Set<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tells the degree of all the edges that goes to this vertex.<br>
|
||||
* Basically, it'll count how many edge towards himself it have.
|
||||
*
|
||||
* @param vertex a vertex of the graph
|
||||
* @return the in degree of the vertex
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tells the degree of all the edges that goes form this vertex to others.<br>
|
||||
* Basically, it'll count how many edge towards any other vertex it have.
|
||||
*
|
||||
* @param vertex a vertex of the graph
|
||||
* @return the out degree of the vertex
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tells the degree of a vertex.<br>
|
||||
* The degree of a vertex is the quantity of edges that have.<br>
|
||||
* Basically, it'll count how many edge it have.
|
||||
*
|
||||
* @param vertex a vertex of the graph
|
||||
* @return the degree of the vertex
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
int degree(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tells how many vertices are in the graph.
|
||||
*
|
||||
* @return the number of vertices
|
||||
*/
|
||||
int numberOfVertices();
|
||||
|
||||
/**
|
||||
* Tells how many edges are in the graph.
|
||||
*
|
||||
* @return the number of edges
|
||||
*/
|
||||
int numberOfEdges();
|
||||
|
||||
/**
|
||||
* Visit the graph accordingly to the strategy that is passed.<br>
|
||||
* This method visit the graph from the source to all the vertex that are reachable form the source.<br>
|
||||
* Some strategy can accept a source vertex null, because they visit all the graph anyway.
|
||||
*
|
||||
* @param source the source vertex of the visit
|
||||
* @param strategy the algorithm for visiting the graph
|
||||
* @param visit the function to apply at each vertex
|
||||
* @throws NullPointerException if one of the parameter is null (except the consumer)
|
||||
* @throws IllegalArgumentException if the vertex is not in the graph
|
||||
*/
|
||||
void visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* This method will create a new Graph that is the transposed version of the original.<br>
|
||||
* At the end of this method the new graph will have all the edges inverted in orientation.<br>
|
||||
* Example: if the graph G contains (V1, V2, V3) as vertex, and (V1->V2, V3->V2) as edges, the transpose graph G' will contain (V1, V2, V3) as vertex, and (V2->V1, V2->V3) as edges.
|
||||
*
|
||||
* @return a transposed graph of this instance
|
||||
*/
|
||||
Graph<V, W> transpose();
|
||||
|
||||
/**
|
||||
* If the current graph is a DAG, it returns a topological sort of this graph.<br>
|
||||
* A topological ordering of a graph is a linear ordering of its vertices such that for every directed edge (V1, V2) from vertex V1 to vertex V2, V2 comes before V1 in the ordering.
|
||||
*
|
||||
* @return an array containing the topological order of the vertices
|
||||
* @throws UnsupportedOperationException if the graph is not a DAG (see {@link #isDAG()})
|
||||
*/
|
||||
List<V> topologicalSort() throws UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* The strongly connected components or diconnected components of an arbitrary directed graph form a partition into subgraphs that are themselves strongly connected.
|
||||
*
|
||||
* @return a set containing the strongly connected components
|
||||
*/
|
||||
Set<Set<V>> stronglyConnectedComponents();
|
||||
|
||||
/**
|
||||
* Get a sub-graph of the current one based on the maximum depth that is given.<br>
|
||||
* If the depth is 1 then only the source and it's children will be in the sub-graph.<br>
|
||||
* If the depth is 2 then only the source, it's children and it's children of it's children will be in the sub-graph.<br>
|
||||
* And so on.<br>
|
||||
* Of course the sub-graph will contain the edges that link the vertices, but only the one selected.
|
||||
*
|
||||
* @param source the source vertex
|
||||
* @param depth the maximum depth (must be a positive number, if >=0 a graph containing only the source is returned)
|
||||
* @return a sub-graph of the original
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is null
|
||||
*/
|
||||
Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Get the minimum path from the source vertex to the destination vertex.<br>
|
||||
* If the source vertex can't reach the destination, then an exception is thrown.
|
||||
*
|
||||
* @param source the vertex where to start
|
||||
* @param destination the destination chosen
|
||||
* @return an ordered list of edges from source to destination that represent the minimum path between the two vertices
|
||||
* @throws NullPointerException if one of the parameter is null (except the consumer)
|
||||
* @throws IllegalArgumentException if the vertex is not in the graph
|
||||
* @throws UnsupportedOperationException if from the source it's not possible to reach the destination
|
||||
*/
|
||||
List<Edge<V, W>> distance(V source, V destination) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Get the minimum path from the source vertex to all the possible reachable vertices.
|
||||
*
|
||||
* @param source the vertex where to start
|
||||
* @return a map containing all the possible reachable vertices from the source and the minimum path to reach them
|
||||
* @throws NullPointerException if one of the parameter is null (except the consumer)
|
||||
* @throws IllegalArgumentException if the vertex is not in the graph
|
||||
*/
|
||||
Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
// TODO maybe -> STATIC saveOnFile(orString) INSTANCE loadFromFile(orString), but need JSON parser
|
||||
// TODO maybe, but i don't think so... STATIC DISTANCE V* -> V*
|
||||
|
||||
/**
|
||||
* Class used for retrieving the edges of the graph.
|
||||
*
|
||||
* @param <V> the vertices
|
||||
* @param <W> the weight of the edge
|
||||
*/
|
||||
class Edge<V, W extends Number> {
|
||||
private final V source;
|
||||
private final V destination;
|
||||
private final W weight;
|
||||
|
||||
/**
|
||||
* Create an final version of this object
|
||||
*
|
||||
* @param source the source of the edge
|
||||
* @param destination the destination of the edge
|
||||
* @param weight the weight od the edge
|
||||
*/
|
||||
public Edge(V source, V destination, W weight) {
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* The vertex where the edge goes
|
||||
*
|
||||
* @return the vertex
|
||||
*/
|
||||
public V getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* The vertex where the edge starts from
|
||||
*
|
||||
* @return the vertex
|
||||
*/
|
||||
public V getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* The weight of the edge
|
||||
*
|
||||
* @return the weight
|
||||
*/
|
||||
public W getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + source + " -> " + destination + ", " + weight + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
try {
|
||||
return obj.getClass().equals(getClass()) && obj.toString().equals(toString());
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/berack96/sim/util/graph/visit/BFS.java
Normal file
52
src/berack96/sim/util/graph/visit/BFS.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package berack96.sim.util.graph.visit;
|
||||
|
||||
import berack96.sim.util.graph.Graph;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Breadth-first search<br>
|
||||
* The algorithm starts at the root node and explores all of the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level.
|
||||
*
|
||||
* @param <V> the vertex of the graph
|
||||
* @param <W> the weight of the graph
|
||||
*/
|
||||
public class BFS<V, W extends Number> implements VisitStrategy<V, W> {
|
||||
|
||||
private VisitInfo<V> lastVisit = null;
|
||||
|
||||
/**
|
||||
* Retrieve the info of the last visit
|
||||
*
|
||||
* @return an info of the visit
|
||||
*/
|
||||
public VisitInfo<V> getLastVisit() {
|
||||
return lastVisit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
|
||||
lastVisit = new VisitInfo<>(source);
|
||||
final LinkedList<V> toVisitChildren = new LinkedList<>();
|
||||
|
||||
toVisitChildren.push(source);
|
||||
if (visit != null)
|
||||
visit.accept(source);
|
||||
lastVisit.setVisited(source);
|
||||
|
||||
while (!toVisitChildren.isEmpty()) {
|
||||
V current = toVisitChildren.removeFirst();
|
||||
|
||||
for (V child : graph.getChildren(current))
|
||||
if (!lastVisit.isDiscovered(child)) {
|
||||
toVisitChildren.addLast(child);
|
||||
|
||||
lastVisit.setVisited(child);
|
||||
lastVisit.setParent(current, child);
|
||||
if (visit != null)
|
||||
visit.accept(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/berack96/sim/util/graph/visit/DFS.java
Normal file
58
src/berack96/sim/util/graph/visit/DFS.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package berack96.sim.util.graph.visit;
|
||||
|
||||
import berack96.sim.util.graph.Graph;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Depth-first search<br>
|
||||
* The algorithm starts at the root node and explores as far as possible along each branch before backtracking.
|
||||
*
|
||||
* @param <V> the vertex of the graph
|
||||
* @param <W> the weight of the graph
|
||||
*/
|
||||
public class DFS<V, W extends Number> implements VisitStrategy<V, W> {
|
||||
|
||||
private VisitInfo<V> lastVisit = null;
|
||||
|
||||
/**
|
||||
* Retrieve the info of the last visit
|
||||
*
|
||||
* @return an info of the visit
|
||||
*/
|
||||
public VisitInfo<V> getLastVisit() {
|
||||
return lastVisit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
|
||||
lastVisit = new VisitInfo<>(source);
|
||||
final Stack<V> toVisit = new Stack<>();
|
||||
|
||||
toVisit.push(source);
|
||||
|
||||
while (!toVisit.isEmpty()) {
|
||||
V current = toVisit.peek();
|
||||
boolean hasChildToVisit = false;
|
||||
Iterator<V> iter = graph.getChildren(current).iterator();
|
||||
|
||||
while (iter.hasNext() && !hasChildToVisit) {
|
||||
V child = iter.next();
|
||||
if (!lastVisit.isDiscovered(child)) {
|
||||
hasChildToVisit = true;
|
||||
toVisit.push(child);
|
||||
lastVisit.setParent(current, child);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasChildToVisit) {
|
||||
toVisit.pop();
|
||||
lastVisit.setVisited(current);
|
||||
if (visit != null)
|
||||
visit.accept(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
193
src/berack96/sim/util/graph/visit/VisitStrategy.java
Normal file
193
src/berack96/sim/util/graph/visit/VisitStrategy.java
Normal file
@@ -0,0 +1,193 @@
|
||||
package berack96.sim.util.graph.visit;
|
||||
|
||||
import berack96.sim.util.graph.Graph;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This class is used for define some strategy for the visit of a graph.
|
||||
*
|
||||
* @param <V> The Object that represent a vertex
|
||||
* @param <W> The Object that represent the edge (more specifically the weight of the edge)
|
||||
* @author Berack96
|
||||
*/
|
||||
public interface VisitStrategy<V, W extends Number> {
|
||||
|
||||
/**
|
||||
* With this the graph will be visited accordingly to the strategy of the visit.<br>
|
||||
* Some strategy can accept a source vertex null, because they visit all the graph anyway.<br>
|
||||
* If you want to stop the visit of the graph, you just have to throw any exception in the visit function, but be sure to catch it
|
||||
*
|
||||
* @param graph the graph to visit
|
||||
* @param source the source of the visit
|
||||
* @param visit the function to apply at each vertex when they are visited
|
||||
* @throws NullPointerException if one of the arguments is null (only the consumers can be null)
|
||||
* @throws IllegalArgumentException if the source vertex is not in the graph
|
||||
* @throws UnsupportedOperationException in the case that the visit algorithm cannot be applied to the graph
|
||||
*/
|
||||
void visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* The class used for getting the info of the visit.<br>
|
||||
* It could be used with the algorithm of the visit for set some useful data.
|
||||
*
|
||||
* @param <V> the vertex of the visit
|
||||
* @author Berack96
|
||||
*/
|
||||
class VisitInfo<V> {
|
||||
private final Map<V, Long> discovered;
|
||||
private final Map<V, Long> visited;
|
||||
private final Map<V, V> parent;
|
||||
private final V source;
|
||||
private long time;
|
||||
|
||||
/**
|
||||
* Need a source for initialize the basic values
|
||||
*
|
||||
* @param source the source of the visit
|
||||
* @throws NullPointerException if the source is null
|
||||
*/
|
||||
public VisitInfo(V source) {
|
||||
if (source == null)
|
||||
throw new NullPointerException();
|
||||
|
||||
discovered = new Hashtable<>();
|
||||
visited = new Hashtable<>();
|
||||
parent = new Hashtable<>();
|
||||
|
||||
this.time = 0;
|
||||
this.source = source;
|
||||
setDiscovered(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* The time of the vertex when it is discovered in the visit.<br>
|
||||
* For "discovered" i mean when the node is first found by the visit algorithm. It may depends form {@link VisitStrategy}<br>
|
||||
* The time starts at 0 and for each vertex discovered it is increased by one. If a vertex is visited it also increase the time<br>
|
||||
*
|
||||
* @param vertex the vertex needed
|
||||
* @return the time of it's discovery
|
||||
* @throws IllegalArgumentException if the vertex is not discovered
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
public long getTimeDiscover(V vertex) throws IllegalArgumentException, NullPointerException {
|
||||
Long time = discovered.get(vertex);
|
||||
if (time == null)
|
||||
throw new IllegalArgumentException();
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* The time when the vertex is visited by the algorithm<br>
|
||||
* For "visited" i mean when the node is finally visited by the visit algorithm. It may depends form {@link VisitStrategy}<br>
|
||||
* The time starts at 0 and for each vertex discovered or visited is increased by one<br>
|
||||
*
|
||||
* @param vertex the vertex needed
|
||||
* @return the time of it's visit
|
||||
* @throws IllegalArgumentException if the vertex is not visited
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
public long getTimeVisit(V vertex) throws IllegalArgumentException, NullPointerException {
|
||||
Long time = visited.get(vertex);
|
||||
if (time == null)
|
||||
throw new IllegalArgumentException();
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if a vertex is discovered or not
|
||||
*
|
||||
* @param vertex the vertex chosen
|
||||
* @return true if is discovered
|
||||
*/
|
||||
public boolean isDiscovered(V vertex) throws NullPointerException {
|
||||
try {
|
||||
return discovered.containsKey(vertex);
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the vertex is visited or not
|
||||
*
|
||||
* @param vertex the vertex chosen
|
||||
* @return true if is visited
|
||||
*/
|
||||
public boolean isVisited(V vertex) throws NullPointerException {
|
||||
try {
|
||||
return visited.containsKey(vertex);
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a vertex as "visited". After this call the vertex is set as discovered (if not already) and visited.<br>
|
||||
* Next this call it will be possible to get the time of visit of that vertex<br>
|
||||
* Does nothing if the vertex is already been visited.
|
||||
*
|
||||
* @param vertex the vertex that has been visited
|
||||
*/
|
||||
public synchronized void setVisited(V vertex) {
|
||||
setDiscovered(vertex);
|
||||
if (!visited.containsKey(vertex))
|
||||
visited.put(vertex, time++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a vertex as "discovered". After this call the vertex is set as discovered and it will be possible to get the time of it's discovery<br>
|
||||
* Does nothing if the vertex is already been discovered.
|
||||
*
|
||||
* @param vertex the vertex that has been discovered
|
||||
*/
|
||||
public synchronized void setDiscovered(V vertex) {
|
||||
if (!discovered.containsKey(vertex))
|
||||
discovered.put(vertex, time++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent of a particular vertex<br>
|
||||
* The parent of a vertex is the one that has discovered it<br>
|
||||
* If the target vertex is not already discovered, then {@link #setDiscovered(Object)} is called<br>
|
||||
*
|
||||
* @param parent the vertex that is the parent
|
||||
* @param child the vertex discovered
|
||||
* @throws IllegalArgumentException if the parent is not already discovered
|
||||
*/
|
||||
public synchronized void setParent(V parent, V child) throws IllegalArgumentException {
|
||||
if (!isDiscovered(parent))
|
||||
throw new IllegalArgumentException(parent.toString());
|
||||
|
||||
setDiscovered(child);
|
||||
this.parent.putIfAbsent(child, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source of the visit.
|
||||
*
|
||||
* @return the source vertex where it's started the visit
|
||||
*/
|
||||
public V getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent of a particular vertex.<br>
|
||||
* The parent of a vertex is the one that has discovered it<br>
|
||||
* If the vertex has no parent (it has not been set by the visit algorithm or it's the source) then null is returned.
|
||||
*
|
||||
* @param vertex the child vertex
|
||||
* @return the parent of the child
|
||||
* @throws IllegalArgumentException if the vertex has not been discovered yet
|
||||
*/
|
||||
public V getParentOf(V vertex) throws IllegalArgumentException {
|
||||
if (isDiscovered(vertex))
|
||||
return parent.get(vertex);
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
907
test/berack96/test/sim/TestGraph.java
Normal file
907
test/berack96/test/sim/TestGraph.java
Normal file
@@ -0,0 +1,907 @@
|
||||
package berack96.test.sim;
|
||||
|
||||
import berack96.sim.util.graph.Graph;
|
||||
import berack96.sim.util.graph.visit.BFS;
|
||||
import berack96.sim.util.graph.visit.DFS;
|
||||
import berack96.sim.util.graph.visit.VisitStrategy;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class TestGraph {
|
||||
|
||||
private Graph<String, Integer> graph;
|
||||
|
||||
private final Exception nullException = new NullPointerException(Graph.PARAM_NULL);
|
||||
private final Exception notException = new IllegalArgumentException(Graph.VERTEX_NOT_CONTAINED);
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
// Change here the instance for changing all the test for that particular class
|
||||
graph = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicVertex() {
|
||||
assertEquals(0, graph.numberOfVertices());
|
||||
|
||||
graph.addVertex("1");
|
||||
graph.addVertex("2");
|
||||
shouldThrow(nullException, () -> graph.addVertex(null));
|
||||
|
||||
assertTrue(graph.contains("1"));
|
||||
assertFalse(graph.contains("0"));
|
||||
assertTrue(graph.contains("2"));
|
||||
assertFalse(graph.contains("3"));
|
||||
assertEquals(2, graph.numberOfVertices());
|
||||
|
||||
graph.removeVertex("1");
|
||||
assertFalse(graph.contains("1"));
|
||||
assertTrue(graph.contains("2"));
|
||||
assertEquals(1, graph.numberOfVertices());
|
||||
|
||||
graph.addVertex("3");
|
||||
assertTrue(graph.contains("3"));
|
||||
shouldThrow(nullException, () -> graph.contains(null));
|
||||
shouldThrow(nullException, () -> graph.addVertexIfAbsent(null));
|
||||
|
||||
assertTrue(graph.addVertexIfAbsent("4"));
|
||||
assertFalse(graph.addVertexIfAbsent("4"));
|
||||
assertFalse(graph.addVertexIfAbsent("2"));
|
||||
|
||||
assertEquals(3, graph.numberOfVertices());
|
||||
shouldContain(graph.vertices(), "2", "3", "4");
|
||||
|
||||
graph.removeAllVertex();
|
||||
shouldContain(graph.vertices());
|
||||
|
||||
Set<String> vertices = new HashSet<>(Arrays.asList("1", "5", "24", "2", "3"));
|
||||
graph.addAllVertices(vertices);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
graph.removeVertex("1");
|
||||
graph.removeVertex("24");
|
||||
shouldContain(graph.vertices(), "5", "2", "3");
|
||||
graph.addAllVertices(vertices);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
|
||||
shouldThrow(nullException, () -> graph.addAllVertices(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicEdge() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2
|
||||
* | |
|
||||
* v v
|
||||
* 3 <-> 5 -> 4
|
||||
*/
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
|
||||
shouldThrow(nullException, () -> graph.addEdge(null, "2", 1));
|
||||
shouldThrow(nullException, () -> graph.addEdge(null, null, 1));
|
||||
shouldThrow(nullException, () -> graph.addEdge("1", null, 1));
|
||||
shouldThrow(nullException, () -> graph.containsEdge(null, "2"));
|
||||
shouldThrow(nullException, () -> graph.containsEdge(null, null));
|
||||
shouldThrow(nullException, () -> graph.containsEdge("1", null));
|
||||
shouldThrow(nullException, () -> graph.removeEdge(null, "2"));
|
||||
shouldThrow(nullException, () -> graph.removeEdge(null, null));
|
||||
shouldThrow(nullException, () -> graph.removeEdge("1", null));
|
||||
shouldThrow(nullException, () -> graph.removeAllEdge(null));
|
||||
shouldThrow(nullException, () -> graph.removeAllOutEdge(null));
|
||||
shouldThrow(nullException, () -> graph.removeAllInEdge(null));
|
||||
|
||||
shouldThrow(notException, () -> graph.addEdge("0", "2", 1));
|
||||
shouldThrow(notException, () -> graph.addEdge("2", "8", 1));
|
||||
shouldThrow(notException, () -> graph.addEdge("9", "6", 1));
|
||||
shouldThrow(notException, () -> graph.containsEdge("01", "4"));
|
||||
shouldThrow(notException, () -> graph.containsEdge("3", "8132"));
|
||||
shouldThrow(notException, () -> graph.containsEdge("9423", "516"));
|
||||
shouldThrow(notException, () -> graph.removeEdge("012", "2"));
|
||||
shouldThrow(notException, () -> graph.removeEdge("2", "28"));
|
||||
shouldThrow(notException, () -> graph.removeEdge("4329", "62"));
|
||||
shouldThrow(notException, () -> graph.removeAllEdge("0"));
|
||||
shouldThrow(notException, () -> graph.removeAllInEdge("011"));
|
||||
shouldThrow(notException, () -> graph.removeAllOutEdge("9"));
|
||||
|
||||
assertEquals(0, graph.numberOfEdges());
|
||||
|
||||
assertNull(graph.addEdge("1", "2", 1));
|
||||
assertNull(graph.addEdge("1", "3", 1));
|
||||
assertNull(graph.addEdge("2", "5", 4));
|
||||
assertNull(graph.addEdge("3", "5", 2));
|
||||
assertNull(graph.addEdge("5", "3", 2));
|
||||
assertNull(graph.addEdge("5", "4", 3));
|
||||
|
||||
assertEquals(6, graph.numberOfEdges());
|
||||
|
||||
// All this calls should do nothing
|
||||
graph.removeEdge("1", "5");
|
||||
graph.removeEdge("1", "4");
|
||||
graph.removeEdge("2", "3");
|
||||
graph.removeEdge("3", "1");
|
||||
graph.removeEdge("4", "5");
|
||||
|
||||
assertEquals(6, graph.numberOfEdges());
|
||||
|
||||
assertEquals(new Integer(1), graph.getWeight("1", "2"));
|
||||
assertEquals(new Integer(1), graph.getWeight("1", "3"));
|
||||
assertEquals(new Integer(4), graph.getWeight("2", "5"));
|
||||
assertEquals(new Integer(2), graph.getWeight("3", "5"));
|
||||
assertEquals(new Integer(2), graph.getWeight("5", "3"));
|
||||
assertEquals(new Integer(3), graph.getWeight("5", "4"));
|
||||
|
||||
assertNull(graph.getWeight("1", "4"));
|
||||
|
||||
assertEquals(new Integer(1), graph.addEdge("1", "2", 102));
|
||||
assertEquals(new Integer(102), graph.addEdge("1", "2", 3));
|
||||
assertEquals(new Integer(3), graph.addEdge("1", "2", 1));
|
||||
|
||||
assertEquals(6, graph.numberOfEdges());
|
||||
assertTrue(graph.containsEdge("1", "2"));
|
||||
assertFalse(graph.containsEdge("4", "3"));
|
||||
assertFalse(graph.containsEdge("2", "1"));
|
||||
assertFalse(graph.containsEdge("1", "4"));
|
||||
assertTrue(graph.containsEdge("1", "3"));
|
||||
assertTrue(graph.containsEdge("3", "5"));
|
||||
assertTrue(graph.containsEdge("2", "5"));
|
||||
|
||||
graph.removeEdge("2", "5");
|
||||
assertFalse(graph.containsEdge("2", "5"));
|
||||
assertEquals(5, graph.numberOfEdges());
|
||||
|
||||
graph.removeEdge("1", "2");
|
||||
assertFalse(graph.containsEdge("1", "2"));
|
||||
assertTrue(graph.containsEdge("1", "3"));
|
||||
assertEquals(4, graph.numberOfEdges());
|
||||
graph.addEdge("1", "2", 2);
|
||||
|
||||
graph.removeAllOutEdge("1");
|
||||
assertFalse(graph.containsEdge("1", "2"));
|
||||
assertFalse(graph.containsEdge("1", "3"));
|
||||
assertEquals(3, graph.numberOfEdges());
|
||||
graph.addEdge("1", "2", 2);
|
||||
graph.addEdge("1", "3", 2);
|
||||
assertEquals(5, graph.numberOfEdges());
|
||||
|
||||
graph.removeAllInEdge("3");
|
||||
assertFalse(graph.containsEdge("5", "3"));
|
||||
assertFalse(graph.containsEdge("1", "3"));
|
||||
assertTrue(graph.containsEdge("3", "5"));
|
||||
assertEquals(3, graph.numberOfEdges());
|
||||
graph.addEdge("1", "3", 2);
|
||||
graph.addEdge("5", "3", 2);
|
||||
|
||||
graph.removeAllEdge("3");
|
||||
assertFalse(graph.containsEdge("5", "3"));
|
||||
assertFalse(graph.containsEdge("1", "3"));
|
||||
assertFalse(graph.containsEdge("3", "5"));
|
||||
assertEquals(2, graph.numberOfEdges());
|
||||
|
||||
graph.removeAllEdge();
|
||||
assertFalse(graph.containsEdge("1", "2"));
|
||||
assertFalse(graph.containsEdge("1", "3"));
|
||||
assertFalse(graph.containsEdge("2", "5"));
|
||||
assertFalse(graph.containsEdge("3", "5"));
|
||||
assertFalse(graph.containsEdge("5", "3"));
|
||||
assertFalse(graph.containsEdge("5", "4"));
|
||||
assertEquals(0, graph.numberOfEdges());
|
||||
|
||||
shouldThrow(notException, () -> graph.containsEdge("2", "323"));
|
||||
graph.addEdgeAndVertices("2", "323", 3);
|
||||
assertTrue(graph.containsEdge("2", "323"));
|
||||
shouldThrow(notException, () -> graph.containsEdge("2aa", "323"));
|
||||
graph.addEdgeAndVertices("2aa", "323", 3);
|
||||
assertTrue(graph.containsEdge("2aa", "323"));
|
||||
shouldThrow(notException, () -> graph.containsEdge("2bbb", "323bbb"));
|
||||
graph.addEdgeAndVertices("2bbb", "323bbb", 3);
|
||||
assertTrue(graph.containsEdge("2bbb", "323bbb"));
|
||||
shouldThrow(nullException, () -> graph.addEdgeAndVertices(null, "1", 1));
|
||||
shouldThrow(nullException, () -> graph.addEdgeAndVertices(null, null, 1));
|
||||
shouldThrow(nullException, () -> graph.addEdgeAndVertices("2", null, 1));
|
||||
|
||||
graph.removeAllVertex();
|
||||
graph.addVertex("aaa");
|
||||
graph.addVertex("1");
|
||||
graph.addVertex("2");
|
||||
|
||||
shouldContain(graph.vertices(), "1", "2", "aaa");
|
||||
shouldContain(graph.edges());
|
||||
|
||||
Set<Graph.Edge<String, Integer>> edges = new HashSet<>();
|
||||
edges.add(new Graph.Edge<>("aaa", "bbb", 3));
|
||||
edges.add(new Graph.Edge<>("bbb", "ccc", 4));
|
||||
edges.add(new Graph.Edge<>("ccc", "aaa", 5));
|
||||
edges.add(new Graph.Edge<>("1", "2", 2));
|
||||
graph.addAllEdges(edges);
|
||||
|
||||
shouldContain(graph.vertices(), "1", "2", "aaa", "bbb", "ccc");
|
||||
shouldContain(graph.edges(),
|
||||
new Graph.Edge<>("aaa", "bbb", 3),
|
||||
new Graph.Edge<>("bbb", "ccc", 4),
|
||||
new Graph.Edge<>("ccc", "aaa", 5),
|
||||
new Graph.Edge<>("1", "2", 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void advancedEdge() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 -> 6
|
||||
* ^
|
||||
* | | |
|
||||
* v v
|
||||
* 3 <-> 5 -> 4
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
|
||||
shouldContain(graph.edges());
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("2", "6", 5);
|
||||
graph.addEdge("3", "5", 2);
|
||||
graph.addEdge("4", "6", 6);
|
||||
graph.addEdge("5", "3", 9);
|
||||
graph.addEdge("5", "4", 5);
|
||||
|
||||
shouldContain(graph.getChildren("1"), "2", "3");
|
||||
shouldContain(graph.getChildren("2"), "5", "6");
|
||||
shouldContain(graph.getChildren("3"), "5");
|
||||
shouldContain(graph.getChildren("4"), "6");
|
||||
shouldContain(graph.getChildren("5"), "3", "4");
|
||||
shouldContain(graph.getChildren("6"));
|
||||
|
||||
shouldContain(graph.getAncestors("1"));
|
||||
shouldContain(graph.getAncestors("2"), "1");
|
||||
shouldContain(graph.getAncestors("3"), "1", "5");
|
||||
shouldContain(graph.getAncestors("4"), "5");
|
||||
shouldContain(graph.getAncestors("5"), "2", "3");
|
||||
shouldContain(graph.getAncestors("6"), "2", "4");
|
||||
|
||||
shouldContain(graph.getChildrenAndWeight("1").entrySet(), new AbstractMap.SimpleEntry<>("2", 1), new AbstractMap.SimpleEntry<>("3", 1));
|
||||
shouldContain(graph.getChildrenAndWeight("2").entrySet(), new AbstractMap.SimpleEntry<>("5", 4), new AbstractMap.SimpleEntry<>("6", 5));
|
||||
shouldContain(graph.getChildrenAndWeight("3").entrySet(), new AbstractMap.SimpleEntry<>("5", 2));
|
||||
shouldContain(graph.getChildrenAndWeight("4").entrySet(), new AbstractMap.SimpleEntry<>("6", 6));
|
||||
shouldContain(graph.getChildrenAndWeight("5").entrySet(), new AbstractMap.SimpleEntry<>("3", 9), new AbstractMap.SimpleEntry<>("4", 5));
|
||||
shouldContain(graph.getChildrenAndWeight("6").entrySet());
|
||||
|
||||
assertEquals(0, graph.degreeIn("1"));
|
||||
assertEquals(1, graph.degreeIn("2"));
|
||||
assertEquals(2, graph.degreeIn("3"));
|
||||
assertEquals(1, graph.degreeIn("4"));
|
||||
assertEquals(2, graph.degreeIn("5"));
|
||||
assertEquals(2, graph.degreeIn("6"));
|
||||
|
||||
assertEquals(2, graph.degreeOut("1"));
|
||||
assertEquals(2, graph.degreeOut("2"));
|
||||
assertEquals(1, graph.degreeOut("3"));
|
||||
assertEquals(1, graph.degreeOut("4"));
|
||||
assertEquals(2, graph.degreeOut("5"));
|
||||
assertEquals(0, graph.degreeOut("6"));
|
||||
|
||||
assertEquals(2, graph.degree("1"));
|
||||
assertEquals(3, graph.degree("2"));
|
||||
assertEquals(3, graph.degree("3"));
|
||||
assertEquals(2, graph.degree("4"));
|
||||
assertEquals(4, graph.degree("5"));
|
||||
assertEquals(2, graph.degree("6"));
|
||||
|
||||
shouldContain(graph.edges(),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("1", "3", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("2", "6", 5),
|
||||
new Graph.Edge<>("3", "5", 2),
|
||||
new Graph.Edge<>("4", "6", 6),
|
||||
new Graph.Edge<>("5", "3", 9),
|
||||
new Graph.Edge<>("5", "4", 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preBasicVisit() {
|
||||
VisitStrategy.VisitInfo<Integer> info = new VisitStrategy.VisitInfo<>(0);
|
||||
assertTrue(info.isDiscovered(0));
|
||||
assertFalse(info.isVisited(0));
|
||||
assertEquals(0, info.getTimeDiscover(0));
|
||||
assertEquals(new Integer(0), info.getSource());
|
||||
assertNull(info.getParentOf(0));
|
||||
|
||||
assertFalse(info.isVisited(null));
|
||||
assertFalse(info.isDiscovered(null));
|
||||
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getTimeVisit(0));
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getTimeDiscover(1));
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getParentOf(2));
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getParentOf(null));
|
||||
|
||||
shouldThrow(new NullPointerException(), () -> info.getTimeDiscover(null));
|
||||
shouldThrow(new NullPointerException(), () -> info.getTimeVisit(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicVisit() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 <- 6 7
|
||||
* ^ ^
|
||||
* | | | |
|
||||
* v v v
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("4", "6", 5);
|
||||
graph.addEdge("5", "3", 6);
|
||||
graph.addEdge("5", "4", 3);
|
||||
graph.addEdge("6", "2", 2);
|
||||
graph.addEdge("7", "8", 8);
|
||||
graph.addEdge("8", "7", 8);
|
||||
|
||||
Exception nullP = new NullPointerException();
|
||||
shouldThrow(nullP, () -> graph.visit(null, new DFS<>(), null));
|
||||
shouldThrow(nullP, () -> graph.visit(null, null, null));
|
||||
shouldThrow(nullP, () -> graph.visit("1", null, null));
|
||||
|
||||
shouldThrow(notException, () -> graph.visit("1010", new DFS<>(), null));
|
||||
|
||||
DFS<String, Integer> dfs = new DFS<>();
|
||||
graph.visit("1", dfs, null);
|
||||
VisitStrategy.VisitInfo<String> visitDFS = dfs.getLastVisit();
|
||||
assertEquals(0, visitDFS.getTimeDiscover("1"));
|
||||
assertEquals(1, visitDFS.getTimeDiscover("2"));
|
||||
assertEquals(2, visitDFS.getTimeDiscover("5"));
|
||||
assertEquals(3, visitDFS.getTimeDiscover("3"));
|
||||
assertEquals(4, visitDFS.getTimeVisit("3"));
|
||||
assertEquals(5, visitDFS.getTimeDiscover("4"));
|
||||
assertEquals(6, visitDFS.getTimeDiscover("6"));
|
||||
assertEquals(7, visitDFS.getTimeVisit("6"));
|
||||
assertEquals(8, visitDFS.getTimeVisit("4"));
|
||||
assertEquals(9, visitDFS.getTimeVisit("5"));
|
||||
assertEquals(10, visitDFS.getTimeVisit("2"));
|
||||
assertEquals(11, visitDFS.getTimeVisit("1"));
|
||||
assertFalse(visitDFS.isDiscovered("7"));
|
||||
assertFalse(visitDFS.isDiscovered("8"));
|
||||
|
||||
BFS<String, Integer> bfs = new BFS<>();
|
||||
graph.visit("1", bfs, null);
|
||||
VisitStrategy.VisitInfo<String> visitBFS = bfs.getLastVisit();
|
||||
assertEquals(0, visitBFS.getTimeDiscover("1"));
|
||||
assertEquals(1, visitBFS.getTimeVisit("1"));
|
||||
assertEquals(2, visitBFS.getTimeDiscover("2"));
|
||||
assertEquals(3, visitBFS.getTimeVisit("2"));
|
||||
assertEquals(4, visitBFS.getTimeDiscover("3"));
|
||||
assertEquals(5, visitBFS.getTimeVisit("3"));
|
||||
assertEquals(6, visitBFS.getTimeDiscover("5"));
|
||||
assertEquals(7, visitBFS.getTimeVisit("5"));
|
||||
assertEquals(8, visitBFS.getTimeDiscover("4"));
|
||||
assertEquals(9, visitBFS.getTimeVisit("4"));
|
||||
assertEquals(10, visitBFS.getTimeDiscover("6"));
|
||||
assertEquals(11, visitBFS.getTimeVisit("6"));
|
||||
assertFalse(visitBFS.isDiscovered("7"));
|
||||
assertFalse(visitBFS.isDiscovered("8"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void iterable() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 <- 6 7
|
||||
* ^ ^
|
||||
* | | | |
|
||||
* v v v
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("4", "6", 5);
|
||||
graph.addEdge("5", "3", 6);
|
||||
graph.addEdge("5", "4", 3);
|
||||
graph.addEdge("6", "2", 2);
|
||||
graph.addEdge("7", "8", 8);
|
||||
graph.addEdge("8", "7", 8);
|
||||
|
||||
Set<String> vertices = new HashSet<>();
|
||||
for (String vertex : graph)
|
||||
vertices.add(vertex);
|
||||
shouldContain(vertices, "1", "2", "3", "4", "5", "6", "7", "8");
|
||||
|
||||
vertices.clear();
|
||||
graph.forEach(vertices::add);
|
||||
shouldContain(vertices, "1", "2", "3", "4", "5", "6", "7", "8");
|
||||
|
||||
vertices.clear();
|
||||
Iterator<String> iter = graph.iterator();
|
||||
while (iter.hasNext())
|
||||
vertices.add(iter.next());
|
||||
|
||||
shouldContain(vertices, "1", "2", "3", "4", "5", "6", "7", "8");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scc() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 -> 6
|
||||
* ^
|
||||
* | | |
|
||||
* v v
|
||||
* 3 <-> 5 -> 4
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("2", "6", 5);
|
||||
graph.addEdge("3", "5", 2);
|
||||
graph.addEdge("4", "6", 6);
|
||||
graph.addEdge("5", "3", 9);
|
||||
graph.addEdge("5", "4", 5);
|
||||
|
||||
shouldContain(graph.stronglyConnectedComponents(), new HashSet<>(Collections.singletonList("6")), new HashSet<>(Arrays.asList("3", "5")), new HashSet<>(Collections.singletonList("4")), new HashSet<>(Collections.singletonList("1")), new HashSet<>(Collections.singletonList("2")));
|
||||
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 <- 6 7
|
||||
* ^ ^
|
||||
* | | | |
|
||||
* v v v
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
before();
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("4", "6", 5);
|
||||
graph.addEdge("5", "3", 6);
|
||||
graph.addEdge("5", "4", 3);
|
||||
graph.addEdge("6", "2", 2);
|
||||
graph.addEdge("7", "8", 8);
|
||||
graph.addEdge("8", "7", 8);
|
||||
|
||||
shouldContain(graph.stronglyConnectedComponents(), new HashSet<>(Arrays.asList("7", "8")), new HashSet<>(Arrays.asList("2", "5", "4", "6")), new HashSet<>(Collections.singletonList("3")), new HashSet<>(Collections.singletonList("1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cyclic() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 -> 6
|
||||
* ^
|
||||
* | | |
|
||||
* v v
|
||||
* 3 -> 5 -> 4
|
||||
*/
|
||||
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("2", "6", 5);
|
||||
graph.addEdge("3", "5", 2);
|
||||
graph.addEdge("4", "6", 6);
|
||||
graph.addEdge("5", "4", 5);
|
||||
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 <- 6
|
||||
* ^
|
||||
* | | |
|
||||
* v v
|
||||
* 3 <- 5 -> 4
|
||||
*/
|
||||
before();
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
graph.addEdge("1", "3", 1);
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
graph.addEdge("2", "5", 4);
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
graph.addEdge("4", "6", 5);
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
graph.addEdge("5", "3", 6);
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
graph.addEdge("5", "4", 3);
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
graph.addEdge("6", "2", 2);
|
||||
assertTrue(graph.isCyclic());
|
||||
assertFalse(graph.isDAG());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transpose() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 <- 6 7
|
||||
* ^
|
||||
* | | | |
|
||||
* v v v
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("4", "6", 5);
|
||||
graph.addEdge("5", "3", 6);
|
||||
graph.addEdge("5", "4", 3);
|
||||
graph.addEdge("6", "2", 2);
|
||||
graph.addEdge("7", "8", 8);
|
||||
|
||||
Graph<String, Integer> transposed = graph.transpose();
|
||||
|
||||
DFS<String, Integer> dfs = new DFS<>();
|
||||
transposed.visit("6", dfs, null);
|
||||
VisitStrategy.VisitInfo<String> visitDFS = dfs.getLastVisit();
|
||||
assertEquals(0, visitDFS.getTimeDiscover("6"));
|
||||
assertEquals(1, visitDFS.getTimeDiscover("4"));
|
||||
assertEquals(2, visitDFS.getTimeDiscover("5"));
|
||||
assertEquals(3, visitDFS.getTimeDiscover("2"));
|
||||
assertEquals(4, visitDFS.getTimeDiscover("1"));
|
||||
assertEquals(5, visitDFS.getTimeVisit("1"));
|
||||
assertEquals(6, visitDFS.getTimeVisit("2"));
|
||||
assertEquals(7, visitDFS.getTimeVisit("5"));
|
||||
assertEquals(8, visitDFS.getTimeVisit("4"));
|
||||
assertEquals(9, visitDFS.getTimeVisit("6"));
|
||||
assertFalse(visitDFS.isDiscovered("3"));
|
||||
assertFalse(visitDFS.isDiscovered("7"));
|
||||
assertFalse(visitDFS.isDiscovered("8"));
|
||||
|
||||
transposed.visit("8", dfs, null);
|
||||
visitDFS = dfs.getLastVisit();
|
||||
assertEquals(0, visitDFS.getTimeDiscover("8"));
|
||||
assertEquals(1, visitDFS.getTimeDiscover("7"));
|
||||
assertEquals(2, visitDFS.getTimeVisit("7"));
|
||||
assertEquals(3, visitDFS.getTimeVisit("8"));
|
||||
assertFalse(visitDFS.isDiscovered("1"));
|
||||
assertFalse(visitDFS.isDiscovered("2"));
|
||||
assertFalse(visitDFS.isDiscovered("3"));
|
||||
assertFalse(visitDFS.isDiscovered("4"));
|
||||
assertFalse(visitDFS.isDiscovered("5"));
|
||||
assertFalse(visitDFS.isDiscovered("6"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void topologicalSort() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 -> 6
|
||||
* ^
|
||||
* | | |
|
||||
* v v
|
||||
* 3 -> 5 -> 4
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("2", "6", 5);
|
||||
graph.addEdge("3", "5", 2);
|
||||
graph.addEdge("4", "6", 6);
|
||||
graph.addEdge("5", "4", 5);
|
||||
|
||||
shouldContainInOrder(graph.topologicalSort(), "1", "3", "2", "5", "4", "6");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void distanceVV() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 <- 6 7
|
||||
* ^
|
||||
* | | | |
|
||||
* v v v
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 10);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("4", "6", 5);
|
||||
graph.addEdge("5", "3", 3);
|
||||
graph.addEdge("5", "4", 3);
|
||||
graph.addEdge("6", "2", 2);
|
||||
graph.addEdge("7", "8", 8);
|
||||
|
||||
List<Graph.Edge<String, Integer>> distance = graph.distance("1", "6");
|
||||
int sum = distance.stream().mapToInt(Graph.Edge::getWeight).sum();
|
||||
assertEquals(13, sum);
|
||||
shouldContainInOrder(distance,
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("5", "4", 3),
|
||||
new Graph.Edge<>("4", "6", 5));
|
||||
distance = graph.distance("1", "3");
|
||||
sum = distance.stream().mapToInt(Graph.Edge::getWeight).sum();
|
||||
assertEquals(8, sum);
|
||||
shouldContainInOrder(distance,
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("5", "3", 3));
|
||||
|
||||
shouldContainInOrder(graph.distance("7", "8"), new Graph.Edge<>("7", "8", 8));
|
||||
|
||||
shouldThrow(nullException, () -> graph.distance(null, "1"));
|
||||
shouldThrow(nullException, () -> graph.distance(null, null));
|
||||
shouldThrow(nullException, () -> graph.distance("1", null));
|
||||
shouldThrow(notException, () -> graph.distance("34", "1"));
|
||||
shouldThrow(notException, () -> graph.distance("2", "36"));
|
||||
shouldThrow(notException, () -> graph.distance("689", "374"));
|
||||
shouldThrow(new UnsupportedOperationException(Graph.NOT_CONNECTED), () -> graph.distance("1", "7"));
|
||||
shouldThrow(new UnsupportedOperationException(Graph.NOT_CONNECTED), () -> graph.distance("3", "2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void distanceVtoAll() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 <- 6 7
|
||||
* ^
|
||||
* | | | |
|
||||
* v v v
|
||||
* 3 <- 5 -> 4 -> 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 10);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("4", "6", 5);
|
||||
graph.addEdge("4", "8", 2);
|
||||
graph.addEdge("5", "3", 3);
|
||||
graph.addEdge("5", "4", 3);
|
||||
graph.addEdge("6", "2", 2);
|
||||
graph.addEdge("7", "8", 8);
|
||||
|
||||
Map<String, List<Graph.Edge<String, Integer>>> distance = graph.distance("1");
|
||||
assertNull(distance.get("1"));
|
||||
shouldContainInOrder(distance.get("2"),
|
||||
new Graph.Edge<>("1", "2", 1));
|
||||
shouldContainInOrder(distance.get("3"),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("5", "3", 3));
|
||||
shouldContain(distance.get("4"),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("5", "4", 3));
|
||||
shouldContain(distance.get("5"),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("2", "5", 4));
|
||||
shouldContain(distance.get("6"),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("5", "4", 3),
|
||||
new Graph.Edge<>("4", "6", 5));
|
||||
assertNull(distance.get("7"));
|
||||
shouldContain(distance.get("8"),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("5", "4", 3),
|
||||
new Graph.Edge<>("4", "8", 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subGraph() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
*
|
||||
* 1 -> 2 <- 6
|
||||
* ^
|
||||
* | | |
|
||||
* v v
|
||||
* 3 <- 5 -> 4
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("4", "6", 6);
|
||||
graph.addEdge("5", "3", 2);
|
||||
graph.addEdge("5", "4", 5);
|
||||
graph.addEdge("6", "2", 2);
|
||||
|
||||
Graph<String, Integer> sub = graph.subGraph("1", -541);
|
||||
shouldContain(sub.vertices(), "1");
|
||||
shouldContain(sub.edges());
|
||||
|
||||
sub = graph.subGraph("1", 0);
|
||||
shouldContain(sub.vertices(), "1");
|
||||
shouldContain(sub.edges());
|
||||
|
||||
sub = graph.subGraph("1", 1);
|
||||
shouldContain(sub.vertices(), "1", "2", "3");
|
||||
shouldContain(sub.edges(),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("1", "3", 1));
|
||||
|
||||
sub = graph.subGraph("1", 3);
|
||||
shouldContain(sub.vertices(), "1", "2", "3", "5", "4");
|
||||
shouldContain(sub.edges(),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("1", "3", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("5", "3", 2),
|
||||
new Graph.Edge<>("5", "4", 5));
|
||||
|
||||
sub = graph.subGraph("6", 2);
|
||||
shouldContain(sub.vertices(), "6", "2", "5");
|
||||
shouldContain(sub.edges(),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("6", "2", 2));
|
||||
|
||||
sub = graph.subGraph("1", 77689);
|
||||
shouldContain(sub.vertices(), "1", "2", "3", "5", "4", "6");
|
||||
shouldContain(sub.edges(),
|
||||
new Graph.Edge<>("1", "2", 1),
|
||||
new Graph.Edge<>("1", "3", 1),
|
||||
new Graph.Edge<>("2", "5", 4),
|
||||
new Graph.Edge<>("4", "6", 6),
|
||||
new Graph.Edge<>("5", "3", 2),
|
||||
new Graph.Edge<>("5", "4", 5),
|
||||
new Graph.Edge<>("6", "2", 2));
|
||||
}
|
||||
|
||||
// TODO test saveFile
|
||||
|
||||
private void shouldContain(Collection<?> actual, Object... expected) {
|
||||
assertEquals("They have not the same number of elements\nActual: " + actual, expected.length, actual.size());
|
||||
|
||||
for (Object obj : expected)
|
||||
assertTrue("Not containing: [" + obj + "]\nBut has: " + actual, actual.contains(obj));
|
||||
}
|
||||
|
||||
private void shouldContainInOrder(List<?> actual, Object... expected) {
|
||||
assertEquals("They have not the same number of elements\nActual: " + actual, expected.length, actual.size());
|
||||
|
||||
for (int i = 0; i < actual.size(); i++)
|
||||
assertEquals("Index: " + i, expected[i], actual.get(i));
|
||||
}
|
||||
|
||||
private void shouldThrow(Exception expected, Runnable runnable) {
|
||||
try {
|
||||
runnable.run();
|
||||
fail("It has't thrown: " + expected.getClass().getSimpleName());
|
||||
} catch (Exception actual) {
|
||||
assertEquals(expected.getClass(), actual.getClass());
|
||||
assertEquals(expected.getMessage(), actual.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user