Updating graph

* Implemented MatrixGraph
* Changed save/load logics (test not passing)
This commit is contained in:
2021-01-06 16:28:01 +01:00
parent ddc81330ab
commit 7f16252890
27 changed files with 1678 additions and 1771 deletions

View File

@@ -14,13 +14,9 @@ test {
useJUnitPlatform()
}
sourceSets {
main {
java {
srcDirs "src"
srcDirs "test"
}
}
sourceSets.main.java {
srcDirs "src"
srcDirs "test"
}
repositories {
@@ -28,8 +24,9 @@ repositories {
}
dependencies {
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
implementation 'org.junit.jupiter:junit-jupiter:5.5.2'
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
/*compile group: 'commons-collections', name: 'commons-collections', version: '3.2'*/
testCompile 'junit:junit:4.4'
testCompile 'junit:junit:5.5.2'
}

View File

@@ -1,21 +1,13 @@
package berack96.lib.graph;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.VisitInfo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import berack96.lib.graph.models.GraphSaveStructure;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.VisitInfo;
/**
* An interface for the graphs.<br>
* This interface is used for the graphs with Directed edges.<br>
@@ -27,11 +19,10 @@ import berack96.lib.graph.visit.impl.VisitInfo;
*/
public interface Graph<V, W extends Number> extends Iterable<V> {
final String NOT_DAG = "The graph is not a DAG";
final String NOT_CONNECTED = "The source vertex doesn't have a path that reach the destination";
final String PARAM_NULL = "The parameter must not be null";
final String VERTEX_NOT_CONTAINED = "The vertex must be contained in the graph";
final Gson GSON = new Gson();
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>
@@ -70,16 +61,16 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
Vertex<V> getVertex(V vertex) throws NullPointerException, IllegalArgumentException;
Vertex<V> get(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Add the vertex to the graph. If it's already in the graph it will be replaced.<br>
* Add the vertex to the graph. If it's already in the graph it will be replaced and all its edges will be resetted.<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;
void add(V vertex) throws NullPointerException;
/**
* Add the specified vertex to the graph only if the graph doesn't contains it.<br>
@@ -89,7 +80,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* @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;
boolean addIfAbsent(V vertex) throws NullPointerException;
/**
* Add all the vertices contained in the collection to the graph.<br>
@@ -99,7 +90,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* @param vertices a collection of the vertices to add
* @throws NullPointerException if the set is null
*/
void addAllVertices(Collection<V> vertices) throws NullPointerException;
void addAll(Collection<V> vertices) throws NullPointerException;
/**
* Remove the selected vertex from the graph.<br>
@@ -109,13 +100,13 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained
*/
void removeVertex(V vertex) throws NullPointerException, IllegalArgumentException;
void remove(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();
void removeAll();
/**
* Get all the marks of this graph.<br>
@@ -408,11 +399,11 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException;
Collection<V> getChildrens(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)}<br>
* Basically is the opposite of {@link #getChildrens(Object)}<br>
* Note: depending on the implementation, modifying the returned collection<br>
* could affect the graph behavior and the changes could be reflected to the graph.
*
@@ -462,7 +453,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
*
* @return the number of vertices
*/
int numberOfVertices();
int size();
/**
* Tells how many edges are in the graph.
@@ -500,7 +491,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* 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
* @return a list containing the topological order of the vertices
* @throws UnsupportedOperationException if the graph is not a DAG (see {@link #isDAG()})
*/
List<V> topologicalSort() throws UnsupportedOperationException;
@@ -521,7 +512,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* 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 &gt;=0 a graph containing only the source is returned)
* @param depth the maximum depth (must be a positive number, if &lt;=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 not contained
@@ -562,91 +553,5 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
*/
Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException;
/**
* Save the Graph passed as input to a file inserted as parameter.<br>
* The resulting file is a Json string representing all the graph.<br>
* If the directory for getting through the file do not exist,<br>
* then it is created.<br>
* For now the marks are not included.
*
* @param graph the graph to save
* @param file the name of the file
* @throws IOException for various reason that appear in the message, but the most common is that the file is not found.
*/
static void save(Graph<?, ?> graph, String file) throws IOException {
save(graph, "", file);
}
/**
* Save the Graph passed as input to a file inserted as parameter.<br>
* The resulting file is a Json string representing all the graph.<br>
* If the directory for getting through the file do not exist,<br>
* then it is created.<br>
* For now the marks are not included.<br>
* The additional parameter is used if you want to save other as well as the graph.
*
* @param graph the graph to save
* @param other other things to save
* @param file the name of the file
* @throws IOException for various reason that appear in the message, but the most common is that the file is not found.
*/
static void save(Graph<?, ?> graph, String other, String file) throws IOException {
GraphSaveStructure save = new GraphSaveStructure(graph, other);
int slash = file.lastIndexOf("\\");
if(slash == -1)
slash = file.lastIndexOf("/");
if(slash != -1) {
String dir = file.substring(0, slash);
File fDir = new File(dir);
fDir.mkdirs();
}
FileWriter writer = new FileWriter(file);
GSON.toJson(save, writer);
writer.close();
}
/**
* Load an already saved graph in an instance of a graph.
* Before loading the graph, it is emptied.
*
* @param <V> the parameter needed for the vertex
* @param <W> the parameter needed for the weight
* @param graph the graph to load with
* @param file the file where the graph is saved
* @param classV the class used for the Vertex
* @param classW the class used for the Weight
* @return the string saved in other, if any
* @throws IOException for any possible reason, the most common: the file doesn't exist
* @throws NullPointerException if the graph is null
* @throws JsonSyntaxException if the file is malformed or corrupted
*/
static <V, W extends Number> String load(Graph<V, W> graph, String file, Class<V> classV, Class<W> classW) throws IOException, NullPointerException, JsonSyntaxException {
FileReader reader = new FileReader(file);
StringBuilder fileContent = new StringBuilder();
int c;
while((c = reader.read()) != -1)
fileContent.append((char)c);
reader.close();
GraphSaveStructure save = GSON.fromJson(fileContent.toString(), GraphSaveStructure.class);
graph.removeAllVertex();
for(String str : save.vertices)
graph.addVertex(GSON.fromJson(str, classV));
for(int i = 0; i<save.edges.length; i++)
graph.addEdge(
GSON.fromJson(save.edges[i].src, classV),
GSON.fromJson(save.edges[i].dest, classV),
GSON.fromJson(save.edges[i].weight, classW));
/*
for(int i = 0; i<save.marks.length; i++)
graph.mark(GSON.fromJson(save.marks[i].vert, classV), save.marks[i].mark);
*/
return save.other;
}
// TODO maybe, but i don't think so... STATIC DISTANCE V* -> V*
}

View File

@@ -1,12 +1,12 @@
package berack96.lib.graph;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.VisitInfo;
import java.util.Collection;
import java.util.HashSet;
import java.util.function.Consumer;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.VisitInfo;
/**
* Class used for represent a vertex of the graph.<br>
* The vertex contained is linked with the graph, so if any changes are made to
@@ -105,7 +105,7 @@ public class Vertex<V> {
*/
public Collection<V> getChildren() throws UnsupportedOperationException {
throwIfNotContained();
return graph.getChildren(vertex);
return graph.getChildrens(vertex);
}
/**
@@ -219,7 +219,7 @@ public class Vertex<V> {
* Add the vertex to the graph only if it's not already in the graph.
*/
public void addIfAbsent() {
graph.addVertexIfAbsent(vertex);
graph.addIfAbsent(vertex);
}
/**
@@ -228,7 +228,7 @@ public class Vertex<V> {
*/
public void remove() {
if (graph.contains(vertex))
graph.removeVertex(vertex);
graph.remove(vertex);
}
/**
@@ -240,7 +240,7 @@ public class Vertex<V> {
* @throws NullPointerException if the strategy is null
* @throws UnsupportedOperationException if the vertex is not in the graph anymore
*/
public VisitInfo<V> visit(final VisitStrategy strategy, final Consumer<V> visit) throws NullPointerException, UnsupportedOperationException {
public VisitInfo<V> visit(final VisitStrategy<V, ?> strategy, final Consumer<V> visit) throws NullPointerException, UnsupportedOperationException {
throwIfNotContained();
return graph.visit(vertex, (VisitStrategy<V, Number>) strategy, visit);
}

View File

@@ -0,0 +1,579 @@
package berack96.lib.graph.impl;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.Vertex;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.Depth;
import berack96.lib.graph.visit.impl.Dijkstra;
import berack96.lib.graph.visit.impl.Tarjan;
import berack96.lib.graph.visit.impl.VisitInfo;
import java.util.*;
import java.util.function.Consumer;
/**
* An abstract class used for a basic implementation of a graph.<br>
* It implements the visits, the markers and some other stupid to implement methods.<br>
* It might not be super efficient but it works and you can always overwrite its methods for better performance
*
* @param <V> the vertex
* @param <W> the weight
* @author Berack96
*/
public abstract class AGraph<V, W extends Number> implements Graph<V, W> {
/**
* Map that contains the marker as key and a set of all the vertices that has it as the value.<br>
* This map is build like this for performance in creating the marker for multiple vertices.<br>
* If you flip the parameters (object and set) then has more performance over the single vertex.
*/
private final Map<Object, Set<V>> markers = new HashMap<>();
/**
* Need this variable for not calculating each time the SCC or the cyclic part if the graph doesn't change
*/
private Tarjan<V, W> tarjan = null;
/**
* Need this variable for not calculating each time the distance from a vertex to all his destinations if the graph doesn't change
*/
final private Map<V, Dijkstra<V, W>> dijkstra = new HashMap<>();
/**
* Get a new instance of this Graph.
*
* @return A new instance of the graph
*/
protected abstract Graph<V, W> getNewInstance();
/**
* Add a vertex to the graph
*
* @param vertex the vertex to add
*/
protected abstract void addVertex(V vertex);
/**
* Check if a vertex is in the graph
*
* @param vertex the vertex to check
* @return true if is contained, false otherwise
*/
protected abstract boolean containsVertex(V vertex);
/**
* Remove a vertex from the graph
*
* @param vertex the vertex to remove
*/
protected abstract void removeVertex(V vertex);
/**
* Remove all vertices from the graph
*/
protected abstract void removeAllVertices();
/**
* Check if the edge is in the graph
* @param vertex1 the source vertex
* @param vertex2 the destination vertex
* @return true if the edge is in the graph, false otherwise
*/
protected abstract boolean containsEdgeImpl(V vertex1, V vertex2);
/**
* Add a new edge to the graph.<br>
* If the edge already exist then replace the weight and returns the old one.
*
* @param vertex1 the source vertex
* @param vertex2 the destination vertex
* @param weight the weight of the new edge
* @return the old weight, null otherwise
*/
protected abstract W addEdgeImpl(V vertex1, V vertex2, W weight);
/**
* Get the weight of the edge
*
* @param vertex1 the source vertex
* @param vertex2 the destination vertex
* @return the weight of the edge
*/
protected abstract W getWeightImpl(V vertex1, V vertex2);
/**
* Retrieves all the edges that goes out of a vertex.<br>
* (where the vertex is the source)
*
* @param vertex the source vertex
* @return a collection of edges
*/
protected abstract Collection<Edge<V, W>> getEdgesOutImpl(V vertex);
/**
* Retrieves all the edges that goes in of a vertex.<br>
* (where the vertex is the destination)
*
* @param vertex the destination vertex
* @return a collection of edges
*/
protected abstract Collection<Edge<V, W>> getEdgesInImpl(V vertex);
/**
* Remove the edge from the graph
* @param vertex1 the source vertex
* @param vertex2 the destination vertex
*/
protected abstract void removeEdgeImpl(V vertex1, V vertex2);
/**
* Removes all the edges that goes out of a vertex.<br>
* (where the vertex is the source)
* @param vertex the source vertex
*/
protected abstract void removeAllOutEdgeImpl(V vertex);
/**
* Removes all the edges that goes in of a vertex.<br>
* (where the vertex is the destination)
*
* @param vertex the destination vertex
*/
protected abstract void removeAllInEdgeImpl(V vertex);
@Override
public boolean isCyclic() {
return stronglyConnectedComponents().size() != size();
}
@Override
public boolean isDAG() {
return !isCyclic();
}
@Override
public Vertex<V> get(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
return new Vertex<>(this, vertex);
}
@Override
public boolean contains(V vertex) throws NullPointerException {
checkNull(vertex);
return containsVertex(vertex);
}
@Override
public void add(V vertex) throws NullPointerException {
checkNull(vertex);
if(containsVertex(vertex))
remove(vertex);
addVertex(vertex);
graphChanged();
}
@Override
public boolean addIfAbsent(V vertex) throws NullPointerException {
if(contains(vertex))
return false;
add(vertex);
return true;
}
@Override
public void addAll(Collection<V> vertices) throws NullPointerException {
checkNull(vertices);
vertices.forEach(this::addIfAbsent);
}
@Override
public void remove(V vertex) throws NullPointerException, IllegalArgumentException {
unMark(vertex);
removeVertex(vertex);
graphChanged();
}
@Override
public void removeAll() {
unMarkAll();
removeAllVertices();
graphChanged();
}
@Override
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
checkNull(vertex1);
checkNull(vertex2);
return containsEdgeImpl(vertex1, vertex2);
}
@Override
public W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex1);
checkNullAndExist(vertex2);
graphChanged();
return addEdgeImpl(vertex1, vertex2, weight);
}
@Override
public W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
checkNull(edge);
return addEdge(edge.getSource(), edge.getDestination(), edge.getWeight());
}
@Override
public W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException {
addIfAbsent(vertex1);
addIfAbsent(vertex2);
return addEdge(vertex1, vertex2, weight);
}
@Override
public W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
return addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight());
}
@Override
public void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException {
edges.forEach((edge) -> addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight()));
}
@Override
public W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex1);
checkNullAndExist(vertex2);
return getWeightImpl(vertex1, vertex2);
}
@Override
public Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
return getEdgesOutImpl(vertex);
}
@Override
public Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
return getEdgesInImpl(vertex);
}
@Override
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex1);
checkNullAndExist(vertex2);
removeEdgeImpl(vertex1, vertex2);
graphChanged();
}
@Override
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
removeAllOutEdgeImpl(vertex);
graphChanged();
}
@Override
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
removeAllInEdgeImpl(vertex);
graphChanged();
}
@Override
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
removeVertex(vertex);
addVertex(vertex);
}
@Override
public void removeAllEdge() {
Collection<V> vert = vertices();
removeAllVertices();
addAll(vert);
graphChanged();
}
@Override
public Collection<V> vertices() {
Set<V> set = new HashSet<>();
this.forEach(set::add);
return set;
}
@Override
public Collection<Edge<V, W>> edges() {
Set<Edge<V,W>> set = new HashSet<>();
this.forEach( v -> set.addAll(this.getEdgesOut(v)));
return set;
}
@Override
public int size() {
return vertices().size();
}
@Override
public int numberOfEdges() {
return edges().size();
}
@Override
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
return degreeIn(vertex) + degreeOut(vertex);
}
@Override
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
return getAncestors(vertex).size();
}
@Override
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
return getChildrens(vertex).size();
}
@Override
public Collection<Object> marks() {
Collection<Object> ret = new HashSet<>();
markers.forEach((m, v) -> {
if(v.size() > 0)
ret.add(m);
});
return ret;
}
@Override
public void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
checkNull(mark);
Set<V> set = markers.computeIfAbsent(mark, (v) -> new HashSet<>());
set.add(vertex);
}
@Override
public void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
checkNull(mark);
markers.get(mark).remove(vertex);
}
@Override
public void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
markers.forEach( (mark, set) -> set.remove(vertex) );
}
@Override
public Collection<V> getMarkedWith(Object mark) throws NullPointerException {
checkNull(mark);
return markers.computeIfAbsent(mark, (v) -> new HashSet<>());
}
@Override
public Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
Collection<Object> marks = new HashSet<>();
markers.forEach( (mark, set) -> {
if (set.contains(vertex))
marks.add(mark);
});
return marks;
}
@Override
public void unMarkAll(Object mark) {
checkNull(mark);
markers.remove(mark);
}
@Override
public void unMarkAll() {
markers.clear();
}
@Override
public Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
Collection<Edge<V,W>> coll = getEdgesIn(vertex);
coll.addAll(getEdgesOut(vertex));
return coll;
}
@Override
public Collection<V> getChildrens(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
Set<V> set = new HashSet<>();
getEdgesOut(vertex).forEach(e -> set.add(e.getDestination()));
return set;
}
@Override
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
Set<V> set = new HashSet<>();
getEdgesIn(vertex).forEach(e -> set.add(e.getSource()));
return set;
}
@Override
public VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
return strategy.visit(this, source, visit);
}
@Override
public Graph<V, W> transpose() {
Graph<V, W> graph = getNewInstance();
graph.addAll(vertices());
for(Edge<V, W> edge : edges())
graph.addEdge(edge.getDestination(), edge.getSource(), edge.getWeight());
return graph;
}
@Override
public List<V> topologicalSort() throws UnsupportedOperationException {
if (!isDAG())
throw new UnsupportedOperationException(NOT_DAG);
return getTarjan().getTopologicalSort();
}
@Override
public Collection<Collection<V>> stronglyConnectedComponents() {
return getTarjan().getSCC();
}
@Override
public Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
Graph<V, W> sub = getNewInstance();
Set<V> vertices = new HashSet<>();
new Depth<V, W>(Math.max(depth, 0)).visit(this, source, vertices::add);
sub.addAll(vertices);
for (V vertex : vertices)
getEdgesOut(vertex).forEach((edge) -> {
if(sub.contains(edge.getSource()) && sub.contains(edge.getDestination()))
sub.addEdge(edge);
});
return sub;
}
@Override
public Graph<V, W> subGraph(final Object...marker) {
final Graph<V, W> sub = getNewInstance();
final Set<V> allVertices = new HashSet<>();
final Set<Object> allMarkers = new HashSet<>();
final boolean isEmpty = (marker == null || marker.length == 0);
if (!isEmpty)
Collections.addAll(allMarkers, marker);
markers.forEach( (mark, set) -> {
if (isEmpty || allMarkers.contains(mark))
allVertices.addAll(set);
});
if (isEmpty) {
Collection<V> toAdd = vertices();
toAdd.removeAll(allVertices);
allVertices.clear();
allVertices.addAll(toAdd);
}
sub.addAll(allVertices);
for (V vertex : sub.vertices())
this.edgesOf(vertex).forEach( (edge) -> {
if(sub.contains(edge.getSource()) && sub.contains(edge.getDestination()))
sub.addEdge(edge);
});
return sub;
}
@Override
public List<Edge<V, W>> distance(V source, V destination) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
checkNullAndExist(source);
checkNullAndExist(destination);
Dijkstra<V, W> dijkstra = getDijkstra(source); /* Cached */
List<Edge<V, W>> path = dijkstra.getLastDistance().get(destination);
if (path == null)
throw new UnsupportedOperationException(NOT_CONNECTED);
return new ArrayList<>(path);
}
@Override
public Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(source);
return new HashMap<>(getDijkstra(source).getLastDistance()); /* Cached */
}
/**
* Simple function that reset all the caching variables if the graph changed
*/
private void graphChanged() {
tarjan = null;
dijkstra.clear();
}
/**
* Test if the object passed is null.
* If it is throw an exception.
* @param object the object to test
*/
private void checkNull(Object object) {
if (object == null)
throw new NullPointerException(PARAM_NULL);
}
/**
* Check if the vertex passed is null and if exist in the graph.
* If not then throws eventual exception
* @param vertex the vertex to test
*/
private void checkNullAndExist(V vertex) {
checkNull(vertex);
if (!contains(vertex))
throw new IllegalArgumentException(VERTEX_NOT_CONTAINED);
}
/**
* Simple function that return the result of the Dijkstra visit, with the starting point as source.<br>
* It also cache it, so multiple call will return always the same value unless the graph has changed.
* @param source the source of the visit
* @return the complete visit
*/
private Dijkstra<V, W> getDijkstra(V source) {
if (dijkstra.get(source) == null) {
Dijkstra<V, W> newDijkstra = new Dijkstra<>();
newDijkstra.visit(this, source, null);
dijkstra.put(source, newDijkstra);
}
return dijkstra.get(source);
}
/**
* Simple function that return the result of the Tarjan visit.<br>
* It also cache it, so multiple call will return always the same value unless the graph has changed.
* @return the tarjan visit
*/
private Tarjan<V, W> getTarjan() {
if (tarjan == null) {
tarjan = new Tarjan<>();
tarjan.visit(this, null, null);
}
return tarjan;
}
}

View File

@@ -1,319 +0,0 @@
package berack96.lib.graph.impl;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.Vertex;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.VisitInfo;
public class AdjGraph<V, W extends Number> implements Graph<V, W> {
@Override
public Iterator<V> iterator() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isCyclic() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isDAG() {
// TODO Auto-generated method stub
return false;
}
@Override
public Vertex<V> getVertex(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public void addVertex(V vertex) throws NullPointerException {
// TODO Auto-generated method stub
}
@Override
public boolean addVertexIfAbsent(V vertex) throws NullPointerException {
// TODO Auto-generated method stub
return false;
}
@Override
public void addAllVertices(Collection<V> vertices) throws NullPointerException {
// TODO Auto-generated method stub
}
@Override
public void removeVertex(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllVertex() {
// TODO Auto-generated method stub
}
@Override
public boolean contains(V vertex) throws NullPointerException {
// TODO Auto-generated method stub
return false;
}
@Override
public Collection<Object> marks() {
// TODO Auto-generated method stub
return null;
}
@Override
public void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public Collection<V> getMarkedWith(Object mark) throws NullPointerException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public void unMarkAll(Object mark) throws NullPointerException {
// TODO Auto-generated method stub
}
@Override
public void unMarkAll() {
// TODO Auto-generated method stub
}
@Override
public W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException {
// TODO Auto-generated method stub
return null;
}
@Override
public W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException {
// TODO Auto-generated method stub
}
@Override
public W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllEdge() {
// TODO Auto-generated method stub
}
@Override
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
// TODO Auto-generated method stub
return false;
}
@Override
public Collection<V> vertices() {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Edge<V, W>> edges() {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int numberOfVertices() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int numberOfEdges() {
// TODO Auto-generated method stub
return 0;
}
@Override
public VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit)
throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Graph<V, W> transpose() {
// TODO Auto-generated method stub
return null;
}
@Override
public List<V> topologicalSort() throws UnsupportedOperationException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Collection<V>> stronglyConnectedComponents() {
// TODO Auto-generated method stub
return null;
}
@Override
public Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Graph<V, W> subGraph(Object... marker) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Edge<V, W>> distance(V source, V destination)
throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -0,0 +1,144 @@
package berack96.lib.graph.impl;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import java.util.*;
/**
* An implementation of the graph using an adjacent list for representing the edges
*
* @param <V> the vertex
* @param <W> the weight
* @author Berack96
*/
public class ListGraph<V, W extends Number> extends AGraph<V, W> {
final private Map<V, List<Adj>> adj = new HashMap<>();
@Override
public Iterator<V> iterator() {
return adj.keySet().iterator();
}
@Override
protected Graph<V, W> getNewInstance() {
return new ListGraph<>();
}
@Override
protected void addVertex(V vertex) {
adj.put(vertex, new LinkedList<>());
}
@Override
protected boolean containsVertex(V vertex) {
return adj.containsKey(vertex);
}
@Override
protected void removeVertex(V vertex) {
adj.remove(vertex);
adj.forEach((v, l) -> {
Set<Adj> set = new HashSet<>();
l.forEach(adj -> {
if(adj.vertex.equals(vertex))
set.add(adj);
});
l.removeAll(set);
});
}
@Override
protected void removeAllVertices() {
adj.clear();
}
@Override
protected boolean containsEdgeImpl(V vertex1, V vertex2) {
if(!adj.containsKey(vertex1))
return false;
for(Adj a : adj.get(vertex1))
if(a.vertex.equals(vertex2))
return true;
return false;
}
@Override
protected W addEdgeImpl(V vertex1, V vertex2, W weight) {
W ret = null;
List<Adj> l = adj.get(vertex1);
for(Adj a : l)
if(a.vertex.equals(vertex2)) {
ret = a.weight;
a.weight = weight;
}
if(ret == null)
l.add(new Adj(vertex2, weight));
return ret;
}
@Override
protected W getWeightImpl(V vertex1, V vertex2) {
W ret = null;
for(Adj a : adj.get(vertex1))
if(a.vertex.equals(vertex2))
ret = a.weight;
return ret;
}
@Override
protected Collection<Edge<V, W>> getEdgesOutImpl(V vertex) {
Set<Edge<V,W>> set = new HashSet<>();
adj.get(vertex).forEach(a -> set.add(new Edge<>(vertex, a.vertex, a.weight)));
return set;
}
@Override
protected Collection<Edge<V, W>> getEdgesInImpl(V vertex) {
Set<Edge<V,W>> set = new HashSet<>();
adj.forEach((v, l) -> l.forEach(a -> {
if(a.vertex.equals(vertex))
set.add(new Edge<>(v, a.vertex, a.weight));
}));
return set;
}
@Override
protected void removeEdgeImpl(V vertex1, V vertex2) {
Adj ret = null;
List<Adj> l = adj.get(vertex1);
for(Adj a : l)
if(a.vertex.equals(vertex2))
ret = a;
l.remove(ret);
}
@Override
protected void removeAllOutEdgeImpl(V vertex) {
adj.compute(vertex,(v, l) -> new LinkedList<>());
}
@Override
protected void removeAllInEdgeImpl(V vertex) {
adj.forEach((v, l) -> {
Set<Adj> set = new HashSet<>();
l.forEach(adj -> {
if(adj.vertex.equals(vertex))
set.add(adj);
});
l.removeAll(set);
});
}
private class Adj {
private final V vertex;
private W weight;
private Adj(V vertex, W weight) {
this.vertex = vertex;
this.weight = weight;
}
}
}

View File

@@ -1,16 +1,10 @@
package berack96.lib.graph.impl;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.Vertex;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.Dijkstra;
import berack96.lib.graph.visit.impl.Tarjan;
import berack96.lib.graph.visit.impl.VisitInfo;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Graph that uses HashMap for vertices and edges<br>
@@ -23,7 +17,7 @@ import berack96.lib.graph.visit.impl.VisitInfo;
* @param <W> the weight of the edges
* @author Berack96
*/
public class MapGraph<V, W extends Number> implements Graph<V, W> {
public class MapGraph<V, W extends Number> extends AGraph<V, W> {
/**
* Map that contains the edges from a vertex to another<br>
@@ -31,321 +25,88 @@ public class MapGraph<V, W extends Number> implements Graph<V, W> {
* If an edge exist, then it's weight is returned
*/
private final Map<V, Map<V, W>> edges = new HashMap<>();
/**
* Map that contains the marker as key and a set of all the vertices that has it as the value.<br>
* This map is build like this for performance in creating the marker for multiple vertices.<br>
* If you flip the parameters (object and set) then has more performance over the single vertex.
*/
private final Map<Object, Set<V>> markers = new HashMap<>();
/**
* Need this variable for not calculating each time the SCC or the cyclic part if the graph doesn't change
*/
private Tarjan<V, W> tarjan = null;
/**
* Need this variable for not calculating each time the distance from a vertex to all his destinations if the graph doesn't change
*/
private Map<V, Dijkstra<V, W>> dijkstra = new HashMap<>();
@Override
public boolean isCyclic() {
return stronglyConnectedComponents().size() != numberOfVertices();
}
@Override
public boolean isDAG() {
return !isCyclic();
}
@Override
public Vertex<V> getVertex(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
return new Vertex<>(this, vertex);
}
@Override
public void addVertex(V vertex) throws NullPointerException {
checkNull(vertex);
edges.put(vertex, new HashMap<>());
graphChanged();
}
@Override
public boolean addVertexIfAbsent(V vertex) throws NullPointerException {
if (contains(vertex))
return false;
addVertex(vertex);
return true;
}
@Override
public void addAllVertices(Collection<V> vertices) throws NullPointerException {
checkNull(vertices);
vertices.forEach(this::addVertexIfAbsent);
}
@Override
public void removeVertex(V vertex) throws NullPointerException {
if (contains(vertex)) {
edges.remove(vertex);
edges.forEach((v, map) -> map.remove(vertex));
markers.forEach((mark, set) -> set.remove(vertex));
graphChanged();
}
}
@Override
public void removeAllVertex() {
edges.clear();
markers.clear();
graphChanged();
}
@Override
public boolean contains(V vertex) throws NullPointerException {
checkNull(vertex);
return edges.containsKey(vertex);
}
@Override
public Collection<Object> marks() {
Collection<Object> ret = new HashSet<>();
markers.forEach((m, v) -> {
if(v.size() > 0)
ret.add(m);
});
return ret;
public Iterator<V> iterator() {
return edges.keySet().iterator();
}
@Override
public void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
checkNull(mark);
Set<V> set = markers.computeIfAbsent(mark, (v) -> new HashSet<>());
set.add(vertex);
}
@Override
public void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
checkNull(mark);
markers.get(mark).remove(vertex);
}
@Override
public void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
markers.forEach( (mark, set) -> set.remove(vertex) );
}
@Override
public Collection<V> getMarkedWith(Object mark) throws NullPointerException {
checkNull(mark);
return markers.computeIfAbsent(mark, (v) -> new HashSet<>());
protected Graph<V, W> getNewInstance() {
return new MapGraph<>();
}
@Override
protected void addVertex(V vertex) {
edges.put(vertex, new HashMap<>());
}
@Override
protected boolean containsVertex(V vertex) {
return edges.containsKey(vertex);
}
@Override
protected void removeVertex(V vertex) {
edges.remove(vertex);
edges.forEach((v, map) -> map.remove(vertex));
}
@Override
protected void removeAllVertices() {
edges.clear();
}
@Override
protected boolean containsEdgeImpl(V vertex1, V vertex2) {
return contains(vertex1) && contains(vertex2) && edges.get(vertex1).containsKey(vertex2);
}
@Override
protected W addEdgeImpl(V vertex1, V vertex2, W weight) {
return edges.get(vertex1).put(vertex2, weight);
}
@Override
protected W getWeightImpl(V vertex1, V vertex2) {
return edges.get(vertex1).get(vertex2);
}
@Override
public Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
Collection<Object> marks = new HashSet<>();
markers.forEach( (mark, set) -> {
if (set.contains(vertex))
marks.add(mark);
});
return marks;
}
@Override
public void unMarkAll(Object mark) {
checkNull(mark);
markers.remove(mark);
}
@Override
public void unMarkAll() {
markers.clear();
}
@Override
public W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex1);
checkNullAndExist(vertex2);
checkNull(weight);
W old = edges.get(vertex1).put(vertex2, weight);
graphChanged();
return old;
}
@Override
public W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
return addEdge(edge.getSource(), edge.getDestination(), edge.getWeight());
}
@Override
public W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException {
addVertexIfAbsent(vertex1);
addVertexIfAbsent(vertex2);
return addEdge(vertex1, vertex2, weight);
}
@Override
public W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
return addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight());
}
@Override
public void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException {
edges.forEach((edge) -> addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight()));
}
@Override
public W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex1);
checkNullAndExist(vertex2);
return edges.get(vertex1).get(vertex2);
}
@Override
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex1);
checkNullAndExist(vertex2);
edges.get(vertex1).remove(vertex2);
graphChanged();
}
@Override
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
edges.forEach((v, map) -> map.remove(vertex));
graphChanged();
}
@Override
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
edges.put(vertex, new HashMap<>());
graphChanged();
}
@Override
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
removeVertex(vertex);
addVertex(vertex);
}
@Override
public void removeAllEdge() {
edges.forEach((v, map) -> map.clear());
graphChanged();
}
@Override
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
return (contains(vertex1) && contains(vertex2)) && edges.get(vertex1).get(vertex2) != null;
}
@Override
public Collection<V> vertices() {
return new HashSet<>(edges.keySet());
}
@Override
public Collection<Edge<V, W>> edges() {
Set<Edge<V, W>> allEdges = new HashSet<>();
edges.forEach((source, map) -> map.forEach((destination, weight) -> allEdges.add(new Edge<>(source, destination, weight))));
return allEdges;
}
@Override
public Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
Set<Edge<V, W>> set = new HashSet<>();
edges.forEach((source, map) -> map.forEach((destination, weight) -> {
if (destination.equals(vertex) || source.equals(vertex))
set.add(new Edge<>(source, destination, weight));
}));
return set;
}
@Override
public Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
protected Collection<Edge<V, W>> getEdgesOutImpl(V vertex) {
Collection<Edge<V, W>> collection = new HashSet<>();
edges.get(vertex).forEach((dest, weight) -> collection.add(new Edge<>(vertex, dest, weight)));
return collection;
}
@Override
protected Collection<Edge<V, W>> getEdgesInImpl(V vertex) {
Collection<Edge<V, W>> collection = new HashSet<>();
edges.forEach((source, edge) -> {
if (edge.get(vertex) != null)
collection.add(new Edge<>(source, vertex, edge.get(vertex)));
});
return collection;
}
}
@Override
public Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
Collection<Edge<V, W>> collection = new HashSet<>();
edges.get(vertex).forEach((dest, weight) -> collection.add(new Edge<>(vertex, dest, weight)));
@Override
protected void removeEdgeImpl(V vertex1, V vertex2) {
edges.get(vertex1).remove(vertex2);
}
return collection;
}
@Override
protected void removeAllOutEdgeImpl(V vertex) {
edges.put(vertex, new HashMap<>());
}
@Override
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
return new HashSet<>(edges.get(vertex).keySet());
}
@Override
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
Set<V> set = new HashSet<>();
edges.forEach((v, map) -> {
if (map.containsKey(vertex)) set.add(v);
});
return set;
}
@Override
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
AtomicInteger sum = new AtomicInteger();
edges.forEach((v, map) -> {
if (map.containsKey(vertex))
sum.getAndIncrement();
});
return sum.get();
}
@Override
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(vertex);
return edges.get(vertex).size();
}
@Override
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
return degreeIn(vertex) + degreeOut(vertex);
}
@Override
public int numberOfVertices() {
@Override
protected void removeAllInEdgeImpl(V vertex) {
edges.forEach((v, map) -> map.remove(vertex));
}
@Override
public int size() {
return edges.size();
}
@@ -356,189 +117,4 @@ public class MapGraph<V, W extends Number> implements Graph<V, W> {
return sum.get();
}
@Override
public VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
return strategy.visit(this, source, visit);
}
@Override
public Graph<V, W> transpose() {
Graph<V, W> graph = new MapGraph<>();
for (V vertex : edges.keySet())
graph.addVertex(vertex);
edges.forEach((source, map) -> map.forEach((destination, weight) -> graph.addEdge(destination, source, weight)));
return graph;
}
@Override
public List<V> topologicalSort() throws UnsupportedOperationException {
if (!isDAG())
throw new UnsupportedOperationException(NOT_DAG);
return getTarjan().getTopologicalSort();
}
@Override
public Collection<Collection<V>> stronglyConnectedComponents() {
return getTarjan().getSCC();
}
@Override
public Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
Graph<V, W> sub = new MapGraph<>();
Set<V> vertices = new HashSet<>();
int finalDepth = depth > 0 ? depth : 0;
VisitStrategy<V, W> strategy = (graph, sourceVertex, visit) -> {
int currentDepth = 0;
final LinkedList<Map.Entry<V, Integer>> toVisitChildren = new LinkedList<>();
toVisitChildren.add(new AbstractMap.SimpleEntry<>(sourceVertex, 0));
vertices.add(source);
while (!toVisitChildren.isEmpty() && currentDepth + 1 <= finalDepth) {
final Map.Entry<V, Integer> current = toVisitChildren.removeFirst();
currentDepth = current.getValue() + 1;
final int finalCurrentDepth = currentDepth;
for (V child : graph.getChildren(current.getKey()))
if (!vertices.contains(child)) {
toVisitChildren.addLast(new AbstractMap.SimpleEntry<>(child, finalCurrentDepth));
vertices.add(child);
}
}
return null;
};
strategy.visit(this, source, null);
sub.addAllVertices(vertices);
for (V vertex : vertices)
getEdgesOut(vertex).forEach((edge) -> {
try {
sub.addEdge(edge);
} catch (Exception ignored) {
}
});
return sub;
}
@Override
public Graph<V, W> subGraph(final Object...marker) {
final Graph<V, W> sub = new MapGraph<>();
final Set<V> allVertices = new HashSet<>();
final Set<Object> allMarkers = new HashSet<>();
final boolean isEmpty = (marker == null || marker.length == 0);
if (!isEmpty)
for (Object mark: marker)
allMarkers.add(mark);
markers.forEach( (mark, set) -> {
if (isEmpty || allMarkers.contains(mark))
allVertices.addAll(set);
});
if (isEmpty) {
Collection<V> toAdd = vertices();
toAdd.removeAll(allVertices);
allVertices.clear();
allVertices.addAll(toAdd);
}
sub.addAllVertices(allVertices);
for (V vertex : sub.vertices())
edges.get(vertex).forEach( (dest, weight) -> {
try {
sub.addEdge(vertex, dest, weight);
} catch (Exception ignored) {}
});
return sub;
}
@Override
public List<Edge<V, W>> distance(V source, V destination) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
checkNullAndExist(source);
checkNullAndExist(destination);
Dijkstra<V, W> dijkstra = getDijkstra(source); /* Cached */
List<Edge<V, W>> path = dijkstra.getLastDistance().get(destination);
if (path == null)
throw new UnsupportedOperationException(NOT_CONNECTED);
return new ArrayList<>(path);
}
@Override
public Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException {
checkNullAndExist(source);
return new HashMap<>(getDijkstra(source).getLastDistance()); /* Cached */
}
@Override
public Iterator<V> iterator() {
return edges.keySet().iterator();
}
/**
* Simple function that reset all the caching variables if the graph changed
*/
private void graphChanged() {
tarjan = null;
dijkstra.clear();
}
/**
* Simple function that return the result of the Dijkstra visit, with the starting point as source.<br>
* It also cache it, so multiple call will return always the same value unless the graph has changed.
* @param source the source of the visit
* @return the complete visit
*/
private Dijkstra<V, W> getDijkstra(V source) {
if (dijkstra.get(source) == null) {
Dijkstra<V, W> newDijkstra = new Dijkstra<>();
newDijkstra.visit(this, source, null);
dijkstra.put(source, newDijkstra);
}
return dijkstra.get(source);
}
/**
* Simple function that return the result of the Tarjan visit.<br>
* It also cache it, so multiple call will return always the same value unless the graph has changed.
* @return the tarjan visit
*/
private Tarjan<V, W> getTarjan() {
if (tarjan == null) {
tarjan = new Tarjan<>();
tarjan.visit(this, null, null);
}
return tarjan;
}
/**
* Test if the object passed is null.
* If it is throw an exception.
* @param object the object to test
*/
private void checkNull(Object object) {
if (object == null)
throw new NullPointerException(PARAM_NULL);
}
/**
* Check if the vertex passed is null and if exist in the graph.
* If not then throws eventual exception
* @param vertex the vertex to test
*/
private void checkNullAndExist(V vertex) {
checkNull(vertex);
if (!edges.containsKey(vertex))
throw new IllegalArgumentException(VERTEX_NOT_CONTAINED);
}
}

View File

@@ -1,319 +1,132 @@
package berack96.lib.graph.impl;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.Vertex;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.VisitInfo;
public class MatrixGraph<V, W extends Number> implements Graph<V, W> {
import java.util.*;
/**
* An implementation of the graph using a matrix for representing the edges
*
* @param <V> the vertex
* @param <W> the weight
* @author Berack96
*/
public class MatrixGraph<V, W extends Number> extends AGraph<V, W> {
final Map<V, Integer> map = new HashMap<>();
final List<List<W>> matrix = new ArrayList<>();
@Override
public Iterator<V> iterator() {
// TODO Auto-generated method stub
return null;
return map.keySet().iterator();
}
@Override
public boolean isCyclic() {
// TODO Auto-generated method stub
return false;
protected Graph<V, W> getNewInstance() {
return new MatrixGraph<>();
}
@Override
public boolean isDAG() {
// TODO Auto-generated method stub
return false;
protected void addVertex(V vertex) {
map.put(vertex, map.size());
List<W> newVert = new ArrayList<>(map.size());
for (int i=0; i<map.size(); i++)
newVert.add(null);
matrix.forEach(list -> list.add(null));
matrix.add(newVert);
}
@Override
public Vertex<V> getVertex(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
protected boolean containsVertex(V vertex) {
return map.containsKey(vertex);
}
@Override
public void addVertex(V vertex) throws NullPointerException {
// TODO Auto-generated method stub
protected void removeVertex(V vertex) {
int x = map.remove(vertex);
map.replaceAll((vert, index) -> index>x? index-1:index);
matrix.remove(x);
matrix.forEach(list -> {
int i;
for(i=x; i<list.size()-1; i++)
list.set(i, list.get(i+1));
if(--i>0)
list.remove(i);
});
}
@Override
public boolean addVertexIfAbsent(V vertex) throws NullPointerException {
// TODO Auto-generated method stub
return false;
protected void removeAllVertices() {
map.clear();
matrix.clear();
}
@Override
public void addAllVertices(Collection<V> vertices) throws NullPointerException {
// TODO Auto-generated method stub
protected boolean containsEdgeImpl(V vertex1, V vertex2) {
try {
return matrix.get(map.get(vertex1)).get(map.get(vertex2)) != null;
} catch (Exception ignore) {
return false;
}
}
@Override
public void removeVertex(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
protected W addEdgeImpl(V vertex1, V vertex2, W weight) {
return matrix.get(map.get(vertex1)).set(map.get(vertex2), weight);
}
@Override
public void removeAllVertex() {
// TODO Auto-generated method stub
protected W getWeightImpl(V vertex1, V vertex2) {
return matrix.get(map.get(vertex1)).get(map.get(vertex2));
}
@Override
public boolean contains(V vertex) throws NullPointerException {
// TODO Auto-generated method stub
return false;
protected Collection<Edge<V, W>> getEdgesOutImpl(V vertex) {
Set<Edge<V,W>> set = new HashSet<>();
Map<Integer, V> inverted = new HashMap<>();
map.keySet().forEach(v -> inverted.put(map.get(v), v));
List<W> list = matrix.get(map.get(vertex));
for(int i=0; i<list.size(); i++) {
W weight = list.get(i);
if (weight != null)
set.add(new Edge<>(vertex, inverted.get(i), weight));
}
return set;
}
@Override
public Collection<Object> marks() {
// TODO Auto-generated method stub
return null;
protected Collection<Edge<V, W>> getEdgesInImpl(V vertex) {
Set<Edge<V,W>> set = new HashSet<>();
Map<Integer, V> inverted = new HashMap<>();
map.keySet().forEach(v -> inverted.put(map.get(v), v));
int x = map.get(vertex);
for(int i=0; i<matrix.size(); i++) {
W weight = matrix.get(i).get(x);
if (weight != null)
set.add(new Edge<>(inverted.get(i), vertex, weight));
}
return set;
}
@Override
public void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
protected void removeEdgeImpl(V vertex1, V vertex2) {
matrix.get(map.get(vertex1)).set(map.get(vertex2), null);
}
@Override
public void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
protected void removeAllOutEdgeImpl(V vertex) {
matrix.get(map.get(vertex)).replaceAll(var -> null);
}
@Override
public void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
protected void removeAllInEdgeImpl(V vertex) {
int x = map.get(vertex);
matrix.forEach(list -> list.set(x, null));
}
@Override
public Collection<V> getMarkedWith(Object mark) throws NullPointerException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public void unMarkAll(Object mark) throws NullPointerException {
// TODO Auto-generated method stub
}
@Override
public void unMarkAll() {
// TODO Auto-generated method stub
}
@Override
public W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException {
// TODO Auto-generated method stub
return null;
}
@Override
public W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException {
// TODO Auto-generated method stub
}
@Override
public W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public void removeAllEdge() {
// TODO Auto-generated method stub
}
@Override
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
// TODO Auto-generated method stub
return false;
}
@Override
public Collection<V> vertices() {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Edge<V, W>> edges() {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int numberOfVertices() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int numberOfEdges() {
// TODO Auto-generated method stub
return 0;
}
@Override
public VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit)
throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Graph<V, W> transpose() {
// TODO Auto-generated method stub
return null;
}
@Override
public List<V> topologicalSort() throws UnsupportedOperationException {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<Collection<V>> stronglyConnectedComponents() {
// TODO Auto-generated method stub
return null;
}
@Override
public Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
@Override
public Graph<V, W> subGraph(Object... marker) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Edge<V, W>> distance(V source, V destination)
throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -7,7 +7,6 @@ package berack96.lib.graph.models;
*
*/
public class EdgeSaveStructure {
public EdgeSaveStructure() {}
protected EdgeSaveStructure(String s, String d, String w) {
this.src = s;
this.dest = d;

View File

@@ -2,6 +2,14 @@ package berack96.lib.graph.models;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import com.google.gson.JsonSyntaxException;
import com.google.gson.stream.JsonReader;
import java.io.*;
import java.lang.reflect.Type;
/**
* Support class used for saving a Graph in a file.
@@ -9,33 +17,97 @@ import berack96.lib.graph.Graph;
* @author Berack96
*
*/
public class GraphSaveStructure {
public GraphSaveStructure() {}
public GraphSaveStructure(Graph<?, ?> graph, String other) {
this.vertices = new String[graph.numberOfVertices()];
int i = 0;
for(Object o: graph.vertices()) {
this.vertices[i] = Graph.GSON.toJson(o);
i++;
}
this.edges = new EdgeSaveStructure[graph.numberOfEdges()];
i = 0;
for (Edge<?, ?> edge : graph.edges()) {
this.edges[i] = new EdgeSaveStructure(
Graph.GSON.toJson(edge.getSource()),
Graph.GSON.toJson(edge.getDestination()),
Graph.GSON.toJson(edge.getWeight())
);
i++;
}
this.other = other;
}
public class GraphSaveStructure<V, W extends Number> {
final public Gson gson = new Gson();
public String[] vertices;
public EdgeSaveStructure[] edges;
//public MarkSaveStructure[] marks;
public String other;
/*
* Load the graph saved in this class in an instance of a graph passed.
* Before loading the graph, it is emptied.
*/
public final void load(Graph<V, W> graph, String fileName, Class<V> classV, Class<W> classW) throws FileNotFoundException {
Gson gson = new GsonBuilder().registerTypeAdapter(this.getClass(), new Creator(this)).create();
JsonReader reader = new JsonReader(new FileReader(fileName));
gson.fromJson(reader, this.getClass());
loadGraph(graph, classV, classW);
}
/**
* This method can be used by sub-classes for saving other stuff from the graph
*
* @param graph the graph to load with
* @param classV the class used for the Vertex
* @param classW the class used for the Weight
* @throws NullPointerException if the graph is null
* @throws JsonSyntaxException if the file is malformed or corrupted
*/
protected void loadGraph(Graph<V, W> graph, Class<V> classV, Class<W> classW) throws NullPointerException, JsonSyntaxException {
graph.removeAll();
for(String str : vertices)
graph.add(gson.fromJson(str, classV));
for (EdgeSaveStructure edge : edges)
graph.addEdge(
gson.fromJson(edge.src, classV),
gson.fromJson(edge.dest, classV),
gson.fromJson(edge.weight, classW)
);
}
/**
* Save the Graph passed as input to a file inserted as parameter.<br>
* The resulting file is a Json string representing all the graph.<br>
* If the directory for getting through the file do not exist,<br>
* then it is created.<br>
* Marks are not included.<br>
* The additional parameter is used if you want to save other as well as the graph.
*
* @param graph the graph to save
* @param file the name of the file
* @throws IOException for various reason that appear in the message, but the most common is that the file is not found.
*/
public final void save(Graph<V,W> graph, String file) throws IOException {
saveGraph(graph);
int slash = file.lastIndexOf("\\");
if(slash == -1)
slash = file.lastIndexOf("/");
if(slash != -1) {
String dir = file.substring(0, slash);
File fDir = new File(dir);
//noinspection ResultOfMethodCallIgnored
fDir.mkdirs();
}
FileWriter writer = new FileWriter(file);
gson.toJson(this, writer);
writer.close();
}
/**
* This method can be used by sub-classes for saving other stuff from the graph
* @param graph the graph to save
*/
protected void saveGraph(Graph<V,W> graph) {
this.vertices = new String[graph.size()];
int i = 0;
for(Object o: graph.vertices())
this.vertices[i++] = gson.toJson(o);
this.edges = new EdgeSaveStructure[graph.numberOfEdges()];
i = 0;
for (Edge<?, ?> edge : graph.edges())
this.edges[i++] = new EdgeSaveStructure(
gson.toJson(edge.getSource()),
gson.toJson(edge.getDestination()),
gson.toJson(edge.getWeight())
);
}
private class Creator implements InstanceCreator<GraphSaveStructure<V,W>> {
private final GraphSaveStructure<V,W> save;
public Creator(GraphSaveStructure<V,W> save) { this.save = save; }
public GraphSaveStructure<V,W> createInstance(Type type) { return save; }
}
}

View File

@@ -7,7 +7,6 @@ package berack96.lib.graph.models;
*
*/
public class MarkSaveStructure {
public MarkSaveStructure() {}
protected MarkSaveStructure(String v, Object m) {
this.vert = v;
this.mark = m;

View File

@@ -1,33 +1,23 @@
package berack96.lib.graph.view;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;
import berack96.lib.graph.Graph;
import berack96.lib.graph.view.edge.EdgeListener;
import berack96.lib.graph.view.vertex.VertexListener;
import berack96.lib.graph.visit.VisitStrategy;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.io.IOException;
import java.io.Serial;
import java.util.List;
import java.util.*;
public class GraphInfo<V, W extends Number> extends JPanel {
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = 1L;
private final Map<String, VisitListener<V>> visits;
@@ -43,7 +33,7 @@ public class GraphInfo<V, W extends Number> extends JPanel {
/* FIRST (GRAPH INFO) */
JLabel vNumber = new JLabel(String.valueOf(graphPanel.getGraph().numberOfVertices()));
JLabel vNumber = new JLabel(String.valueOf(graphPanel.getGraph().size()));
JLabel eNumber = new JLabel(String.valueOf(graphPanel.getGraph().numberOfEdges()));
JLabel gCyclic = new JLabel(String.valueOf(graphPanel.getGraph().isCyclic()));
@@ -194,7 +184,7 @@ public class GraphInfo<V, W extends Number> extends JPanel {
graphPanel.addObserver((o, arg) -> {
Graph<V, W> graph = graphPanel.getGraph();
if(arg.equals(graph)) {
vNumber.setText(String.valueOf(graph.numberOfVertices()));
vNumber.setText(String.valueOf(graph.size()));
eNumber.setText(String.valueOf(graph.numberOfEdges()));
gCyclic.setText(String.valueOf(graph.isCyclic()));

View File

@@ -16,12 +16,12 @@ public interface GraphListener extends MouseListener, MouseMotionListener, KeyLi
* This function is called when the listener is removed to the graph.
* Here you could remove any other thing that you have done.
*/
public void remove();
void remove();
/**
* Get the description of this listener, in a way to interact with the user.
*
* @return a string describing the functionalities of this listener
*/
public String getDescription();
String getDescription();
}

View File

@@ -1,23 +1,5 @@
package berack96.lib.graph.view;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Observer;
import java.util.Set;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.Vertex;
@@ -25,17 +7,29 @@ import berack96.lib.graph.impl.MapGraph;
import berack96.lib.graph.view.edge.EdgeComponent;
import berack96.lib.graph.view.vertex.VertexComponent;
import java.awt.*;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.IOException;
import java.io.Serial;
import java.util.Collection;
import java.util.HashSet;
import java.util.Observer;
import java.util.Set;
@SuppressWarnings({"unchecked", "deprecation"})
public class GraphPanel<V, W extends Number> extends Component {
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = 1L;
private final GraphicalView<VertexComponent<V>> vertexRender;
private final GraphicalView<EdgeComponent<V, W>> edgeRender;
private final Class<V> classV;
private final Class<W> classW;
private final Container vertices = new Container();
private final Container edges = new Container();
final Container vertices = new Container();
final Container edges = new Container();
private final Graph<V, W> graph = new MapGraph<>();
private final Set<Observer> observers = new HashSet<>();
@@ -78,8 +72,10 @@ public class GraphPanel<V, W extends Number> extends Component {
boolean isContained = false;
for(Component comp : vertices.getComponents())
if (comp.equals(v))
isContained = true;
if (comp.equals(v)) {
isContained = true;
break;
}
if (!isContained) {
v.setBounds(vertexRender.getBox(v, center));
@@ -122,8 +118,8 @@ public class GraphPanel<V, W extends Number> extends Component {
edgeComponent.setBounds(edgeRender.getBox(edgeComponent, center));
edges.add(edgeComponent);
graph.addEdge(edgeComponent.edge);
} catch (Exception ignore) {
ignore.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
@@ -165,26 +161,11 @@ public class GraphPanel<V, W extends Number> extends Component {
}
public void save(String fileName) throws IOException {
GraphGraphicalSave save = new GraphGraphicalSave(vertices);
Graph.save(graph, Graph.GSON.toJson(save), fileName);
new GraphPointsSave<>(this).save(graph, fileName);
}
public void load(String fileName) throws IOException {
String saveContent = Graph.load(graph, fileName, classV, classW);
GraphGraphicalSave save = Graph.GSON.fromJson(saveContent, GraphGraphicalSave.class);
vertices.removeAll();
edges.removeAll();
for(int i = 0; i<save.vertices.length; i++) {
V v = Graph.GSON.fromJson(save.vertices[i], classV);
Point p = save.points[i];
addVertex(p, v);
}
for(String v : save.vertices)
graph.getEdgesOut(Graph.GSON.fromJson(v, classV)).forEach(e -> addEdge(e));
repaint();
new GraphPointsSave<>(this).load(graph, fileName, classV, classW);
}
@Override
@@ -229,37 +210,5 @@ public class GraphPanel<V, W extends Number> extends Component {
observers.forEach(observer -> observer.update(null, this.graph));
}
class GraphGraphicalSave {
public GraphGraphicalSave() {}
protected GraphGraphicalSave(Container vertices) {
List<String> v = new LinkedList<>();
List<Point> p = new LinkedList<>();
for(Component vertex : vertices.getComponents()) {
Point temp = new Point(vertex.getX(), vertex.getY());
temp.x += vertex.getWidth() / 2;
temp.y += vertex.getHeight() / 2;
p.add(temp);
v.add(Graph.GSON.toJson(((VertexComponent<V>) vertex).vertex.getValue()));
}
int i = 0;
this.vertices = new String[v.size()];
for(String s : v) {
this.vertices[i] = s;
i++;
}
i = 0;
this.points = new Point[p.size()];
for(Point pt : p) {
this.points[i] = pt;
i++;
}
}
public String[] vertices;
public Point[] points;
}
}

View File

@@ -0,0 +1,54 @@
package berack96.lib.graph.view;
import berack96.lib.graph.Graph;
import berack96.lib.graph.models.GraphSaveStructure;
import java.awt.*;
import java.util.LinkedList;
import java.util.List;
public class GraphPointsSave<V, W extends Number> extends GraphSaveStructure<V, W> {
final private GraphPanel<V,W> panel;
public Point[] points;
public GraphPointsSave(GraphPanel<V,W> panel) {
this.panel = panel;
}
@Override
protected void saveGraph(Graph<V, W> graph) {
super.saveGraph(graph);
List<Point> p = new LinkedList<>();
for(Component vertex : panel.vertices.getComponents()) {
Point temp = new Point(vertex.getX(), vertex.getY());
temp.x += vertex.getWidth() / 2;
temp.y += vertex.getHeight() / 2;
p.add(temp);
}
int i = 0;
this.points = new Point[p.size()];
for(Point pt : p)
this.points[i++] = pt;
}
@Override
public void loadGraph(Graph<V, W> graph, Class<V> classV, Class<W> classW) {
super.loadGraph(graph, classV, classW);
panel.vertices.removeAll();
panel.edges.removeAll();
for(int i = 0; i<vertices.length; i++) {
V v = gson.fromJson(vertices[i], classV);
Point p = points[i];
panel.addVertex(p, v);
}
for(String v : vertices)
graph.getEdgesOut(gson.fromJson(v, classV)).forEach(panel::addEdge);
panel.repaint();
}
}

View File

@@ -1,11 +1,5 @@
package berack96.lib.graph.view;
import java.awt.BorderLayout;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.swing.JFrame;
import berack96.lib.graph.view.edge.EdgeListener;
import berack96.lib.graph.view.vertex.VertexListener;
import berack96.lib.graph.visit.VisitStrategy;
@@ -14,6 +8,12 @@ import berack96.lib.graph.visit.impl.DFS;
import berack96.lib.graph.visit.impl.Dijkstra;
import berack96.lib.graph.visit.impl.Tarjan;
import javax.swing.*;
import java.awt.*;
import java.io.Serial;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* This class is the Window that appear for building the graph and playing around with it
*
@@ -21,10 +21,10 @@ import berack96.lib.graph.visit.impl.Tarjan;
*/
public class GraphWindow<V, W extends Number> extends JFrame {
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = 1L;
private final GraphPanel<V, W> graphPanel;
private final GraphInfo<V, W> infoPanel;
public GraphWindow(GraphPanel<V, W> graphPanel, VertexListener<V> vListener, EdgeListener<V, W> eListener) {
this.setTitle("Grafo");
@@ -37,14 +37,14 @@ public class GraphWindow<V, W extends Number> extends JFrame {
strats.add(new Dijkstra<>());
strats.add(new Tarjan<>());
this.infoPanel = new GraphInfo<>(graphPanel, vListener, eListener, strats);
GraphInfo<V, W> infoPanel = new GraphInfo<>(graphPanel, vListener, eListener, strats);
this.graphPanel = graphPanel;
this.add(infoPanel, BorderLayout.EAST);
this.add(graphPanel);
}
public void visitRefresh(int millisec) {
VisitListener.changeRefresh(millisec);
public void visitRefresh(int millis) {
VisitListener.changeRefresh(millis);
}
public GraphPanel<V, W> getGraphPanel() {

View File

@@ -25,13 +25,13 @@ public class VisitListener<V> implements GraphListener {
this.strategy = strategy;
}
public static void changeRefresh(int millisec) {
refreshTime = millisec;
public static void changeRefresh(int mills) {
refreshTime = mills;
}
@Override
public void remove() {
timers.forEach(t -> t.stop());
timers.forEach(Timer::stop);
timers.clear();
}

View File

@@ -1,10 +1,12 @@
package berack96.lib.graph.view.vertex;
import java.awt.*;
import berack96.lib.graph.Vertex;
import java.awt.*;
import java.io.Serial;
public class VertexComponent<V> extends Component {
@Serial
private static final long serialVersionUID = 1L;
public final Vertex<V> vertex;

View File

@@ -1,10 +1,10 @@
package berack96.lib.graph.view.vertex;
import java.util.Arrays;
import berack96.lib.graph.Graph;
import berack96.lib.graph.view.GraphPanel;
import java.util.Arrays;
public class VertexIntListener extends VertexListener<Integer> {
public VertexIntListener(GraphPanel<Integer, ?> panel) {
@@ -17,14 +17,14 @@ public class VertexIntListener extends VertexListener<Integer> {
@Override
protected Integer buildNewVertex(Graph<Integer, ?> graph) {
int counter = 0;
Integer[] vertices = graph.vertices().toArray(new Integer[graph.numberOfVertices()]);
Integer[] vertices = graph.vertices().toArray(new Integer[graph.size()]);
Arrays.sort(vertices);
for(int i = 0; i<vertices.length; i++) {
if(!vertices[i].equals(counter))
return counter;
counter++;
}
for (Integer vertex : vertices) {
if (!vertex.equals(counter))
return counter;
counter++;
}
return counter;
}
}

View File

@@ -1,9 +1,9 @@
package berack96.lib.graph.view.vertex;
import java.awt.*;
import berack96.lib.graph.view.GraphicalView;
import java.awt.*;
public class VertexView<V> implements GraphicalView<VertexComponent<V>> {
private static final Font FONT = new Font("Comic Sans MS", Font.BOLD, 17);
@@ -23,7 +23,7 @@ public class VertexView<V> implements GraphicalView<VertexComponent<V>> {
boolean discovered = obj.vertex.getMarks().contains("discovered");
boolean visited = obj.vertex.getMarks().contains("visited");
boolean selected = obj.vertex.getMarks().contains("selected");
FontMetrics metrics = obj.getFontMetrics(FONT);
int stringPixels = metrics.stringWidth(obj.vertex.getValue().toString());
int size = Math.max(stringPixels, metrics.getHeight()) + 2 * PADDING;

View File

@@ -1,11 +1,11 @@
package berack96.lib.graph.visit.impl;
import java.util.LinkedList;
import java.util.function.Consumer;
import berack96.lib.graph.Graph;
import berack96.lib.graph.visit.VisitStrategy;
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.
@@ -29,7 +29,7 @@ public class BFS<V, W extends Number> implements VisitStrategy<V, W> {
while (!toVisitChildren.isEmpty()) {
V current = toVisitChildren.removeFirst();
for (V child : graph.getChildren(current))
for (V child : graph.getChildrens(current))
if (!info.isDiscovered(child)) {
toVisitChildren.addLast(child);

View File

@@ -1,12 +1,12 @@
package berack96.lib.graph.visit.impl;
import berack96.lib.graph.Graph;
import berack96.lib.graph.visit.VisitStrategy;
import java.util.Iterator;
import java.util.Stack;
import java.util.function.Consumer;
import berack96.lib.graph.Graph;
import berack96.lib.graph.visit.VisitStrategy;
/**
* Depth-first search<br>
* The algorithm starts at the root node and explores as far as possible along each branch before backtracking.
@@ -27,7 +27,7 @@ public class DFS<V, W extends Number> implements VisitStrategy<V, W> {
while (!toVisit.isEmpty()) {
V current = toVisit.peek();
boolean hasChildToVisit = false;
Iterator<V> iter = graph.getChildren(current).iterator();
Iterator<V> iter = graph.getChildrens(current).iterator();
while (iter.hasNext() && !hasChildToVisit) {
V child = iter.next();

View File

@@ -0,0 +1,53 @@
package berack96.lib.graph.visit.impl;
import berack96.lib.graph.Graph;
import berack96.lib.graph.visit.VisitStrategy;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
public class Depth<V, W extends Number> implements VisitStrategy<V, W> {
private long finalDepth;
public Depth(long depth) {
this.finalDepth = depth;
}
public void setDepth(long depth) {
this.finalDepth = depth;
}
@Override
public VisitInfo<V> visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
VisitInfo<V> info = new VisitInfo<>(source);
long currentDepth = info.getDepth(source);
if(visit != null)
visit.accept(source);
info.setVisited(source);
List<V> toVisit = new LinkedList<>();
toVisit.add(source);
while (!toVisit.isEmpty() && currentDepth < finalDepth) {
V current = toVisit.remove(0);
currentDepth = info.getDepth(current) + 1;
for (V child : graph.getChildrens(current))
if (!info.isDiscovered(child)) {
if(visit != null)
visit.accept(child);
info.setVisited(child);
info.setParent(current, child);
toVisit.add(child);
}
}
return info;
}
}

View File

@@ -1,12 +1,12 @@
package berack96.lib.graph.visit.impl;
import java.util.*;
import java.util.function.Consumer;
import berack96.lib.graph.Graph;
import berack96.lib.graph.visit.VisitSCC;
import berack96.lib.graph.visit.VisitTopological;
import java.util.*;
import java.util.function.Consumer;
/**
* Class that implements the Tarjan algorithm and uses it for getting the SCC and the topological sort
*
@@ -61,7 +61,7 @@ public class Tarjan<V, W extends Number> implements VisitSCC<V, W>, VisitTopolog
strongConnect(graph, vertex, index, visit);
}
topologicalSort = (graph.numberOfVertices() == SCC.size()) ? new ArrayList<>(topologicalSort) : null;
topologicalSort = (graph.size() == SCC.size()) ? new ArrayList<>(topologicalSort) : null;
return info;
}
@@ -74,7 +74,7 @@ public class Tarjan<V, W extends Number> implements VisitSCC<V, W>, VisitTopolog
info.setDiscovered(vertex);
// Consider successors of v
for (V child : graph.getChildren(vertex)) {
for (V child : graph.getChildrens(vertex)) {
if (!indices.containsKey(child)) {
info.setParent(vertex, child);
strongConnect(graph, child, index, visit);

View File

@@ -1,10 +1,10 @@
package berack96.lib.graph.visit.impl;
import berack96.lib.graph.visit.VisitStrategy;
import java.util.*;
import java.util.function.Consumer;
import berack96.lib.graph.visit.VisitStrategy;
/**
* 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.
@@ -13,9 +13,9 @@ import berack96.lib.graph.visit.VisitStrategy;
* @author Berack96
*/
public class VisitInfo<V> {
private final Map<V, Long> discovered;
private final Map<V, Long> visited;
private final Map<V, V> parent;
private static final int NOT_SET = -1;
private final Map<V, VertexInfo> vertices;
private final V source;
private long time;
@@ -29,118 +29,12 @@ public class VisitInfo<V> {
if (source == null)
throw new NullPointerException();
discovered = new Hashtable<>();
visited = new Hashtable<>();
parent = new Hashtable<>();
this.vertices = 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
*/
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
*/
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
*/
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.
*
@@ -157,13 +51,148 @@ public class VisitInfo<V> {
*
* @param vertex the child vertex
* @return the parent of the child
* @throws IllegalArgumentException if the vertex has not been discovered yet
* @throws IllegalArgumentException if the vertex has not been discovered yet or is null
*/
public V getParentOf(V vertex) throws IllegalArgumentException {
if (isDiscovered(vertex))
return parent.get(vertex);
VertexInfo info = vertices.get(vertex);
if (!isDiscovered(vertex))
throw new IllegalArgumentException();
return info.parent;
}
/**
* 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 {
VertexInfo info = vertices.get(vertex);
long time = (info == null) ? NOT_SET : info.timeDiscovered;
if(time == NOT_SET)
throw new IllegalArgumentException();
return time;
}
throw new IllegalArgumentException();
/**
* 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 {
VertexInfo info = vertices.get(vertex);
long time = (info == null) ? NOT_SET : info.timeVisited;
if(time == NOT_SET)
throw new IllegalArgumentException();
return time;
}
/**
* The depth of the vertex when it was first discovered.
*
* @param vertex the vertex needed
* @return the depth of it's discovery
* @throws IllegalArgumentException if the vertex is not discovered
* @throws NullPointerException if the vertex is null
*/
public long getDepth(V vertex) throws IllegalArgumentException, NullPointerException {
VertexInfo info = vertices.get(vertex);
long depth = (info == null) ? NOT_SET : info.depth;
if(depth == NOT_SET)
throw new IllegalArgumentException();
return depth;
}
/**
* 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 vertices.get(vertex).timeDiscovered != NOT_SET;
} 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 vertices.get(vertex).timeVisited != NOT_SET;
} 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 has already been visited.
*
* @param vertex the vertex that has been visited
*/
synchronized void setVisited(V vertex) {
setDiscovered(vertex);
VertexInfo info = vertices.get(vertex);
if(info.timeVisited != NOT_SET)
return;
info.timeVisited = time;
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 has already been discovered.
*
* @param vertex the vertex that has been discovered
*/
synchronized void setDiscovered(V vertex) {
VertexInfo info = vertices.computeIfAbsent(vertex, (v) -> new VertexInfo(vertex));
if(info.timeDiscovered != NOT_SET)
return;
info.timeDiscovered = time;
info.depth = 0;
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
*/
synchronized void setParent(V parent, V child) throws IllegalArgumentException {
if (!isDiscovered(parent))
throw new IllegalArgumentException(parent.toString());
setDiscovered(child);
VertexInfo info = vertices.get(child);
info.parent = parent;
info.depth = vertices.get(parent).depth + 1;
}
/**
@@ -172,7 +201,12 @@ public class VisitInfo<V> {
* @return the visited vertices
*/
public Set<V> getVisited() {
return visited.keySet();
Set<V> visited = new HashSet<>(vertices.size());
vertices.forEach((vert, info) -> {
if(info.timeVisited != NOT_SET)
visited.add(vert);
});
return visited;
}
/**
@@ -181,7 +215,12 @@ public class VisitInfo<V> {
* @return the discovered vertices
*/
public Set<V> getDiscovered() {
return discovered.keySet();
Set<V> discovered = new HashSet<>(vertices.size());
vertices.forEach((vert, info) -> {
if(info.timeDiscovered != NOT_SET)
discovered.add(vert);
});
return discovered;
}
/**
@@ -191,10 +230,11 @@ public class VisitInfo<V> {
* @param consumer the function to apply to each
*/
public void forEachDiscovered(Consumer<VertexInfo> consumer) {
Set<V> vertices = getDiscovered();
Queue<VertexInfo> queue = new PriorityQueue<>();
vertices.forEach((vertex) -> queue.offer(new VertexInfo(vertex, getParentOf(vertex), getTimeDiscover(vertex), isVisited(vertex) ? getTimeVisit(vertex) : -1, false)));
vertices.forEach((v, info) -> {
if(info.timeDiscovered != NOT_SET)
queue.offer(new VertexInfo(info, false));
});
while (!queue.isEmpty())
consumer.accept(queue.poll());
@@ -207,10 +247,11 @@ public class VisitInfo<V> {
* @param consumer the function to apply to each
*/
public void forEachVisited(Consumer<VertexInfo> consumer) {
Set<V> vertices = getVisited();
Queue<VertexInfo> queue = new PriorityQueue<>();
vertices.forEach((vertex) -> queue.offer(new VertexInfo(vertex, getParentOf(vertex), getTimeDiscover(vertex), getTimeVisit(vertex), true)));
vertices.forEach((v, info) -> {
if(info.timeVisited != NOT_SET)
queue.offer(new VertexInfo(info, true));
});
while (!queue.isEmpty())
consumer.accept(queue.poll());
@@ -223,46 +264,70 @@ public class VisitInfo<V> {
* @param consumer the function to apply at each vertex
*/
public void forEach(Consumer<VertexInfo> consumer) {
Set<V> discovered = getDiscovered();
Set<V> visited = getVisited();
Queue<VertexInfo> queue = new PriorityQueue<>();
discovered.forEach((vertex) -> queue.offer(new VertexInfo(vertex, getParentOf(vertex), getTimeDiscover(vertex), getTimeVisit(vertex), false)));
visited.forEach((vertex) -> queue.offer(new VertexInfo(vertex, getParentOf(vertex), getTimeDiscover(vertex), getTimeVisit(vertex), true)));
vertices.forEach((v, info) -> {
if(info.timeDiscovered != NOT_SET)
queue.offer(new VertexInfo(info, false));
if(info.timeVisited != NOT_SET)
queue.offer(new VertexInfo(info, true));
});
while (!queue.isEmpty())
consumer.accept(queue.remove());
}
/**
* Class used mainly for storing the data of the visit
*/
public class VertexInfo implements Comparable<VertexInfo> {
public final V vertex;
public final V parent;
public final long timeDiscovered;
public final long timeVisited;
public V vertex;
public V parent;
public long timeDiscovered;
public long timeVisited;
public long depth;
private final boolean compareVisited;
private VertexInfo(V vertex, V parent, long timeDiscovered, long timeVisited, boolean compareVisited) {
this.vertex = vertex;
this.parent = parent;
this.timeDiscovered = timeDiscovered;
this.timeVisited = timeVisited;
this.compareVisited = compareVisited;
private VertexInfo(V vertex) {
this.vertex = vertex;
this.timeDiscovered = NOT_SET;
this.timeVisited = NOT_SET;
this.depth = NOT_SET;
this.compareVisited = false;
}
private VertexInfo(VertexInfo info, boolean compare) {
this.vertex = info.vertex;
this.parent = info.parent;
this.timeDiscovered = info.timeDiscovered;
this.timeVisited = info.timeVisited;
this.depth = info.depth;
this.compareVisited = compare;
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public boolean equals(Object obj) {
try {
return obj instanceof VisitInfo.VertexInfo && obj.toString().equals(toString());
} catch (Exception e) {
return false;
}
}
@Override
public int compareTo(VertexInfo other) {
long compareThis = compareVisited ? timeVisited : timeDiscovered;
long compareOther = other.compareVisited ? other.timeVisited : other.timeDiscovered;
return (int) (compareThis - compareOther);
}
@Override
public String toString() {
return String.format("%s -> %s [D:%3d, V:%3d]", parent, vertex, timeDiscovered, timeVisited);
return String.format("%s -> %s (%3d) [D:%3d, V:%3d]", parent, vertex, depth, timeDiscovered, timeVisited);
}
}
}

View File

@@ -1,46 +1,31 @@
package berack96.test.lib;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.Vertex;
import berack96.lib.graph.models.GraphSaveStructure;
import berack96.lib.graph.visit.impl.BFS;
import berack96.lib.graph.visit.impl.DFS;
import berack96.lib.graph.visit.impl.VisitInfo;
import com.google.gson.JsonSyntaxException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.jupiter.api.Assertions.*;
import com.google.gson.JsonSyntaxException;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.Vertex;
import berack96.lib.graph.impl.AdjGraph;
import berack96.lib.graph.impl.MapGraph;
import berack96.lib.graph.impl.MatrixGraph;
import berack96.lib.graph.visit.impl.BFS;
import berack96.lib.graph.visit.impl.DFS;
import berack96.lib.graph.visit.impl.VisitInfo;
@SuppressWarnings("deprecation")
@Timeout(value = 2)
public class TestGraph {
/* We only try this for sake of simplicity */
/* I decided to only try this for sake of simplicity */
private Graph<String, Integer> graph;
private final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
@@ -48,17 +33,16 @@ public class TestGraph {
private final String encoding = "UTF-8";
private final Exception nullException = new NullPointerException(Graph.PARAM_NULL);
private final Exception notException = new IllegalArgumentException(Graph.VERTEX_NOT_CONTAINED);
private final Exception unsuppException = new UnsupportedOperationException(Vertex.REMOVED);
private final Exception unSuppException = new UnsupportedOperationException(Vertex.REMOVED);
@Before
@BeforeEach
public void before() {
// Change here the instance for changing all the test for that particular class
graph = new MapGraph<>();
// graph = new MatrixGraph<>();
// graph = new AdjGraph<>();
//graph = new berack96.lib.graph.impl.MapGraph<>();
//graph = new berack96.lib.graph.impl.MatrixGraph<>();
graph = new berack96.lib.graph.impl.ListGraph<>();
PrintStream p = null;
PrintStream p;
try {
p = new PrintStream(bytes, true, encoding);
System.setErr(p);
@@ -68,7 +52,7 @@ public class TestGraph {
}
}
@After
@AfterEach
public void after() {
try {
String printed = bytes.toString(encoding);
@@ -82,48 +66,48 @@ public class TestGraph {
@Test
public void basicVertex() {
assertEquals(0, graph.numberOfVertices());
assertEquals(0, graph.size());
graph.addVertex("1");
graph.addVertex("2");
shouldThrow(nullException, () -> graph.addVertex(null));
graph.add("1");
graph.add("2");
shouldThrow(nullException, () -> graph.add(null));
assertTrue(graph.contains("1"));
assertFalse(graph.contains("0"));
assertTrue(graph.contains("2"));
assertFalse(graph.contains("3"));
assertEquals(2, graph.numberOfVertices());
assertEquals(2, graph.size());
graph.removeVertex("1");
graph.remove("1");
assertFalse(graph.contains("1"));
assertTrue(graph.contains("2"));
assertEquals(1, graph.numberOfVertices());
assertEquals(1, graph.size());
graph.addVertex("3");
graph.add("3");
assertTrue(graph.contains("3"));
shouldThrow(nullException, () -> graph.contains(null));
shouldThrow(nullException, () -> graph.addVertexIfAbsent(null));
shouldThrow(nullException, () -> graph.addIfAbsent(null));
assertTrue(graph.addVertexIfAbsent("4"));
assertFalse(graph.addVertexIfAbsent("4"));
assertFalse(graph.addVertexIfAbsent("2"));
assertTrue(graph.addIfAbsent("4"));
assertFalse(graph.addIfAbsent("4"));
assertFalse(graph.addIfAbsent("2"));
assertEquals(3, graph.numberOfVertices());
assertEquals(3, graph.size());
shouldContain(graph.vertices(), "2", "3", "4");
graph.removeAllVertex();
graph.removeAll();
shouldContain(graph.vertices());
Set<String> vertices = new HashSet<>(Arrays.asList("1", "5", "24", "2", "3"));
graph.addAllVertices(vertices);
graph.addAll(vertices);
shouldContain(graph.vertices(), vertices.toArray());
graph.removeVertex("1");
graph.removeVertex("24");
graph.remove("1");
graph.remove("24");
shouldContain(graph.vertices(), "5", "2", "3");
graph.addAllVertices(vertices);
graph.addAll(vertices);
shouldContain(graph.vertices(), vertices.toArray());
shouldThrow(nullException, () -> graph.addAllVertices(null));
shouldThrow(nullException, () -> graph.addAll(null));
}
@Test
@@ -136,16 +120,16 @@ public class TestGraph {
* v v
* 3 <-> 5 -> 4
*/
graph.addVertexIfAbsent("1");
graph.addVertexIfAbsent("2");
graph.addVertexIfAbsent("3");
graph.addVertexIfAbsent("4");
graph.addVertexIfAbsent("5");
graph.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
shouldThrow(nullException, () -> graph.addEdge(null, "2", 1));
shouldThrow(nullException, () -> graph.addEdge(null, null, 1));
shouldThrow(nullException, () -> graph.addEdge("1", null, 1));
shouldThrow(new NullPointerException(), () -> graph.addEdge(null));
shouldThrow(nullException, () -> graph.addEdge(null));
shouldThrow(nullException, () -> graph.addEdge(new Edge<>("1", null, 1)));
shouldThrow(nullException, () -> graph.addEdge(new Edge<>(null, null, 1)));
shouldThrow(nullException, () -> graph.addEdge(new Edge<>(null, "2", 1)));
@@ -193,21 +177,21 @@ public class TestGraph {
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"));
assertEquals(Integer.valueOf(1), graph.getWeight("1", "2"));
assertEquals(Integer.valueOf(1), graph.getWeight("1", "3"));
assertEquals(Integer.valueOf(4), graph.getWeight("2", "5"));
assertEquals(Integer.valueOf(2), graph.getWeight("3", "5"));
assertEquals(Integer.valueOf(2), graph.getWeight("5", "3"));
assertEquals(Integer.valueOf(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(new Integer(1), graph.addEdge(new Edge<>("1", "2", 102)));
assertEquals(new Integer(102), graph.addEdge(new Edge<>("1", "2", 3)));
assertEquals(new Integer(3), graph.addEdge(new Edge<>("1", "2", 1)));
assertEquals(Integer.valueOf(1), graph.addEdge("1", "2", 102));
assertEquals(Integer.valueOf(102), graph.addEdge("1", "2", 3));
assertEquals(Integer.valueOf(3), graph.addEdge("1", "2", 1));
assertEquals(Integer.valueOf(1), graph.addEdge(new Edge<>("1", "2", 102)));
assertEquals(Integer.valueOf(102), graph.addEdge(new Edge<>("1", "2", 3)));
assertEquals(Integer.valueOf(3), graph.addEdge(new Edge<>("1", "2", 1)));
assertEquals(6, graph.numberOfEdges());
assertTrue(graph.containsEdge("1", "2"));
@@ -298,10 +282,10 @@ public class TestGraph {
assertEquals(35, graph.addEdgeAndVertices(new Edge<>("2aa", "323", 5)).intValue());
assertEquals(50, graph.addEdgeAndVertices(new Edge<>("2", "323", 500)).intValue());
graph.removeAllVertex();
graph.addVertex("aaa");
graph.addVertex("1");
graph.addVertex("2");
graph.removeAll();
graph.add("aaa");
graph.add("1");
graph.add("2");
shouldContain(graph.vertices(), "1", "2", "aaa");
shouldContain(graph.edges());
@@ -333,12 +317,12 @@ public class TestGraph {
* 3 <-> 5 -> 4
*/
graph.addVertexIfAbsent("1");
graph.addVertexIfAbsent("2");
graph.addVertexIfAbsent("3");
graph.addVertexIfAbsent("4");
graph.addVertexIfAbsent("5");
graph.addVertexIfAbsent("6");
graph.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
shouldContain(graph.edges());
@@ -351,12 +335,12 @@ public class TestGraph {
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.getChildrens("1"), "2", "3");
shouldContain(graph.getChildrens("2"), "5", "6");
shouldContain(graph.getChildrens("3"), "5");
shouldContain(graph.getChildrens("4"), "6");
shouldContain(graph.getChildrens("5"), "3", "4");
shouldContain(graph.getChildrens("6"));
shouldContain(graph.getAncestors("1"));
shouldContain(graph.getAncestors("2"), "1");
@@ -417,6 +401,25 @@ public class TestGraph {
new Edge<>("3", "5", 2),
new Edge<>("5", "3", 9),
new Edge<>("5", "4", 5));
/* Weird case in the add */
graph.addIfAbsent("2");
shouldContain(graph.edges(),
new Edge<>("1", "2", 1),
new Edge<>("1", "3", 1),
new Edge<>("2", "5", 4),
new Edge<>("2", "6", 5),
new Edge<>("3", "5", 2),
new Edge<>("4", "6", 6),
new Edge<>("5", "3", 9),
new Edge<>("5", "4", 5));
graph.add("2");
shouldContain(graph.edges(),
new Edge<>("1", "3", 1),
new Edge<>("3", "5", 2),
new Edge<>("4", "6", 6),
new Edge<>("5", "3", 9),
new Edge<>("5", "4", 5));
}
@Test
@@ -424,8 +427,9 @@ public class TestGraph {
VisitInfo<Integer> info = new VisitInfo<>(0);
assertTrue(info.isDiscovered(0));
assertFalse(info.isVisited(0));
assertEquals(0, info.getDepth(0));
assertEquals(0, info.getTimeDiscover(0));
assertEquals(new Integer(0), info.getSource());
assertEquals(Integer.valueOf(0), info.getSource());
assertNull(info.getParentOf(0));
assertFalse(info.isVisited(null));
@@ -434,10 +438,12 @@ public class TestGraph {
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 IllegalArgumentException(), () -> info.getDepth(2));
shouldThrow(new NullPointerException(), () -> info.getTimeDiscover(null));
shouldThrow(new NullPointerException(), () -> info.getTimeVisit(null));
shouldThrow(new NullPointerException(), () -> info.getParentOf(null));
shouldThrow(new NullPointerException(), () -> info.getDepth(null));
}
@Test
@@ -452,14 +458,14 @@ public class TestGraph {
* 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.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addIfAbsent("7");
graph.addIfAbsent("8");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 1);
@@ -503,6 +509,7 @@ public class TestGraph {
assertEquals(verticesDiscovered[integer.get()], vertexInfo.vertex);
integer.incrementAndGet();
});
integer.set(0);
int[] visitTime = {4, 7, 8, 9, 10, 11};
String[] verticesVisited = {"3", "6", "4", "5", "2", "1"};
@@ -511,6 +518,24 @@ public class TestGraph {
assertEquals(verticesVisited[integer.get()], vertexInfo.vertex);
integer.incrementAndGet();
});
String[] vertices = {"1", "2", "5", "3", "3", "4", "6", "6", "4", "5", "2", "1"};
boolean[] found = new boolean[graph.size()];
integer.set(0);
visitDFS.forEach(vertexInfo -> {
int i = integer.get();
assertEquals(vertices[i], vertexInfo.vertex, "Iter " + i);
int vert = Integer.parseInt(vertexInfo.vertex);
if(found[vert])
assertEquals(i, vertexInfo.timeVisited, "Iter " + i);
else {
assertEquals(i, vertexInfo.timeDiscovered, "Iter " + i);
found[vert] = true;
}
integer.incrementAndGet();
});
BFS<String, Integer> bfs = new BFS<>();
VisitInfo<String> visitBFS = graph.visit("1", bfs, null);
@@ -542,14 +567,14 @@ public class TestGraph {
* 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.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addIfAbsent("7");
graph.addIfAbsent("8");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 1);
@@ -564,7 +589,7 @@ public class TestGraph {
Set<String> vertices = new HashSet<>();
Iterator<String> iter = graph.iterator();
assertTrue("This should not be null!", iter != null);
assertNotNull(iter, "This should not be null!");
while (iter.hasNext())
vertices.add(iter.next());
shouldContain(vertices, "1", "2", "3", "4", "5", "6", "7", "8");
@@ -591,12 +616,12 @@ public class TestGraph {
* 3 <-> 5 -> 4
*/
graph.addVertexIfAbsent("1");
graph.addVertexIfAbsent("2");
graph.addVertexIfAbsent("3");
graph.addVertexIfAbsent("4");
graph.addVertexIfAbsent("5");
graph.addVertexIfAbsent("6");
graph.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 1);
@@ -619,14 +644,14 @@ public class TestGraph {
* 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.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addIfAbsent("7");
graph.addIfAbsent("8");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 1);
@@ -656,12 +681,12 @@ public class TestGraph {
assertFalse(graph.isCyclic());
assertTrue(graph.isDAG());
graph.addVertexIfAbsent("1");
graph.addVertexIfAbsent("2");
graph.addVertexIfAbsent("3");
graph.addVertexIfAbsent("4");
graph.addVertexIfAbsent("5");
graph.addVertexIfAbsent("6");
graph.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
assertFalse(graph.isCyclic());
assertTrue(graph.isDAG());
@@ -687,12 +712,12 @@ public class TestGraph {
* 3 <- 5 -> 4
*/
before();
graph.addVertexIfAbsent("1");
graph.addVertexIfAbsent("2");
graph.addVertexIfAbsent("3");
graph.addVertexIfAbsent("4");
graph.addVertexIfAbsent("5");
graph.addVertexIfAbsent("6");
graph.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
assertFalse(graph.isCyclic());
assertTrue(graph.isDAG());
@@ -733,14 +758,14 @@ public class TestGraph {
* 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.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addIfAbsent("7");
graph.addIfAbsent("8");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 1);
@@ -752,7 +777,7 @@ public class TestGraph {
graph.addEdge("7", "8", 8);
Graph<String, Integer> transposed = graph.transpose();
assertTrue("This should not be null!", transposed != null);
assertNotNull(transposed, "This should not be null!");
DFS<String, Integer> dfs = new DFS<>();
VisitInfo<String> visitDFS = transposed.visit("6", dfs, null);
@@ -795,12 +820,12 @@ public class TestGraph {
* 3 -> 5 -> 4
*/
graph.addVertexIfAbsent("1");
graph.addVertexIfAbsent("2");
graph.addVertexIfAbsent("3");
graph.addVertexIfAbsent("4");
graph.addVertexIfAbsent("5");
graph.addVertexIfAbsent("6");
graph.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 1);
@@ -826,14 +851,14 @@ public class TestGraph {
* 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.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addIfAbsent("7");
graph.addIfAbsent("8");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 10);
@@ -845,7 +870,7 @@ public class TestGraph {
graph.addEdge("7", "8", 8);
List<Edge<String, Integer>> distance = graph.distance("1", "6");
assertTrue("This should not be null!", distance != null);
assertNotNull(distance, "This should not be null!");
int sum = distance.stream().mapToInt(Edge::getWeight).sum();
assertEquals(13, sum);
shouldContainInOrder(distance,
@@ -885,14 +910,14 @@ public class TestGraph {
* 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.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addIfAbsent("7");
graph.addIfAbsent("8");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 10);
@@ -905,7 +930,7 @@ public class TestGraph {
graph.addEdge("7", "8", 8);
Map<String, List<Edge<String, Integer>>> distance = graph.distance("1");
assertTrue("This should not be null!", distance != null);
assertNotNull(distance, "This should not be null!");
assertNull(distance.get("1"));
shouldContainInOrder(distance.get("2"),
new Edge<>("1", "2", 1));
@@ -945,14 +970,14 @@ public class TestGraph {
* 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.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addIfAbsent("7");
graph.addIfAbsent("8");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 1);
@@ -1094,7 +1119,7 @@ public class TestGraph {
@Test
public void subGraph() {
/*
* This graph should be like this
* This graph should look like this
*
* 1 -> 2 <- 6 7
* ^ ^
@@ -1103,14 +1128,14 @@ public class TestGraph {
* 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.addIfAbsent("1");
graph.addIfAbsent("2");
graph.addIfAbsent("3");
graph.addIfAbsent("4");
graph.addIfAbsent("5");
graph.addIfAbsent("6");
graph.addIfAbsent("7");
graph.addIfAbsent("8");
graph.addEdge("1", "2", 1);
graph.addEdge("1", "3", 1);
@@ -1140,7 +1165,7 @@ public class TestGraph {
graph.mark("4", "z");
Graph<String, Integer> sub = graph.subGraph("1", -541);
assertTrue("This should not be null!", sub != null);
assertNotNull(sub, "This should not be null!");
shouldContain(sub.vertices(), "1");
shouldContain(sub.edges());
@@ -1222,7 +1247,8 @@ public class TestGraph {
sub = graph.subGraph();
shouldContain(sub.vertices(), "7", "8");
shouldContain(sub.edges(), new Edge<>("8", "7", 9));
//noinspection ConfusingArgumentToVarargsMethod
sub = graph.subGraph(null);
shouldContain(sub.vertices(), "7", "8");
shouldContain(sub.edges(), new Edge<>("8", "7", 9));
@@ -1233,31 +1259,31 @@ public class TestGraph {
Vertex<String> vertex = new Vertex<>(graph, "stronzo");
assertEquals("stronzo", vertex.getValue());
assertEquals(0, graph.numberOfVertices());
assertEquals(0, graph.size());
shouldThrow(unsuppException, () -> vertex.addChild(null, null));
shouldThrow(unsuppException, () -> vertex.mark(null));
shouldThrow(unsuppException, () -> vertex.removeChild(null));
shouldThrow(unsuppException, () -> vertex.visit(null, null));
shouldThrow(unsuppException, vertex::unMark);
shouldThrow(unsuppException, vertex::getAncestors);
shouldThrow(unsuppException, vertex::getChildren);
shouldThrow(unsuppException, vertex::getEdgesOut);
shouldThrow(unsuppException, vertex::getEdgesIn);
shouldThrow(unsuppException, vertex::getChildrenAsVertex);
shouldThrow(unsuppException, vertex::getAncestorsAsVertex);
shouldThrow(unsuppException, vertex::getMarks);
shouldThrow(unSuppException, () -> vertex.addChild(null, null));
shouldThrow(unSuppException, () -> vertex.mark(null));
shouldThrow(unSuppException, () -> vertex.removeChild(null));
shouldThrow(unSuppException, () -> vertex.visit(null, null));
shouldThrow(unSuppException, vertex::unMark);
shouldThrow(unSuppException, vertex::getAncestors);
shouldThrow(unSuppException, vertex::getChildren);
shouldThrow(unSuppException, vertex::getEdgesOut);
shouldThrow(unSuppException, vertex::getEdgesIn);
shouldThrow(unSuppException, vertex::getChildrenAsVertex);
shouldThrow(unSuppException, vertex::getAncestorsAsVertex);
shouldThrow(unSuppException, vertex::getMarks);
vertex.addIfAbsent();
assertEquals(1, graph.numberOfVertices());
assertEquals(1, graph.size());
vertex.addIfAbsent();
assertEquals(1, graph.numberOfVertices());
assertEquals(1, graph.size());
vertex.addIfAbsent();
assertEquals(1, graph.numberOfVertices());
assertEquals(1, graph.size());
assertEquals(vertex, graph.getVertex("stronzo"));
shouldThrow(nullException, () -> graph.getVertex(null));
shouldThrow(notException, () -> graph.getVertex("stronzo1"));
assertEquals(vertex, graph.get("stronzo"));
shouldThrow(nullException, () -> graph.get(null));
shouldThrow(notException, () -> graph.get("stronzo1"));
shouldThrow(nullException, () -> vertex.addChild(null, 3));
shouldThrow(nullException, () -> vertex.addChild(null, null));
@@ -1277,9 +1303,9 @@ public class TestGraph {
shouldContain(vertex.getEdgesIn());
shouldContain(vertex.getEdgesOut());
graph.addVertex("1");
graph.addVertex("2");
graph.addVertex("3");
graph.add("1");
graph.add("2");
graph.add("3");
graph.addEdge("1", "2", 2);
graph.addEdge("3", "stronzo", 6);
@@ -1330,23 +1356,23 @@ public class TestGraph {
vertex.remove();
assertFalse(vertex.isStillContained());
assertFalse(graph.contains(vertex.getValue()));
assertEquals(3, graph.numberOfVertices());
assertEquals(3, graph.size());
shouldThrow(unsuppException, () -> vertex.addChild(null, null));
shouldThrow(unsuppException, () -> vertex.mark(null));
shouldThrow(unsuppException, () -> vertex.removeChild(null));
shouldThrow(unsuppException, () -> vertex.visit(null, null));
shouldThrow(unsuppException, vertex::unMark);
shouldThrow(unsuppException, vertex::getAncestors);
shouldThrow(unsuppException, vertex::getChildren);
shouldThrow(unsuppException, vertex::getEdgesOut);
shouldThrow(unsuppException, vertex::getEdgesIn);
shouldThrow(unsuppException, vertex::getChildrenAsVertex);
shouldThrow(unsuppException, vertex::getAncestorsAsVertex);
shouldThrow(unsuppException, vertex::getMarks);
shouldThrow(unSuppException, () -> vertex.addChild(null, null));
shouldThrow(unSuppException, () -> vertex.mark(null));
shouldThrow(unSuppException, () -> vertex.removeChild(null));
shouldThrow(unSuppException, () -> vertex.visit(null, null));
shouldThrow(unSuppException, vertex::unMark);
shouldThrow(unSuppException, vertex::getAncestors);
shouldThrow(unSuppException, vertex::getChildren);
shouldThrow(unSuppException, vertex::getEdgesOut);
shouldThrow(unSuppException, vertex::getEdgesIn);
shouldThrow(unSuppException, vertex::getChildrenAsVertex);
shouldThrow(unSuppException, vertex::getAncestorsAsVertex);
shouldThrow(unSuppException, vertex::getMarks);
vertex.addIfAbsent();
assertEquals(4, graph.numberOfVertices());
assertEquals(4, graph.size());
}
@Test
@@ -1401,33 +1427,35 @@ public class TestGraph {
marks.put("6", new HashSet<>(temp));
temp.clear();
graph.addAllVertices(vertices);
graph.addAll(vertices);
graph.addAllEdges(edges);
marks.forEach((v, m) -> m.forEach(mk -> graph.mark(v, mk)));
GraphSaveStructure<String, Integer> struct = new GraphSaveStructure<>();
try {
Graph.save(graph, fileName);
Graph.load(graph, fileName, String.class, Integer.class);
struct.save(graph, fileName);
struct.load(graph, fileName, String.class, Integer.class);
shouldContain(graph.vertices(), vertices.toArray());
shouldContain(graph.edges(), edges.toArray());
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
graph.removeAllVertex();
Graph.load(graph, fileName, String.class, Integer.class);
graph.removeAll();
struct.load(graph, fileName, String.class, Integer.class);
shouldContain(graph.vertices(), vertices.toArray());
shouldContain(graph.edges(), edges.toArray());
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
} catch (Exception e) {
e.printStackTrace(System.err);
fail(e.getMessage());
}
try {
Graph.load(graph, "sadadafacensi", String.class, Integer.class);
struct.load(graph, "sadadafacensi", String.class, Integer.class);
fail("Should have been thrown IOException");
} catch (Exception ignore) {
if (!(ignore instanceof IOException))
fail("Should have been thrown IOException " + ignore.getMessage());
} catch (Exception e) {
if (!(e instanceof IOException))
fail("Should have been thrown IOException " + e.getMessage());
}
shouldContain(graph.vertices(), vertices.toArray());
@@ -1435,16 +1463,16 @@ public class TestGraph {
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
try {
Graph.load(graph, fileName + ".fail", String.class, Integer.class);
struct.load(graph, fileName + ".fail", String.class, Integer.class);
fail("Should have been thrown JsonSyntaxException");
} catch (Exception ignore) {
if (!(ignore instanceof JsonSyntaxException))
fail("Should have been thrown JsonSyntaxException " + ignore.getMessage());
} catch (Exception e) {
if (!(e instanceof JsonSyntaxException))
fail("Should have been thrown JsonSyntaxException " + e.getMessage());
}
graph = null;
shouldThrow(new NullPointerException(), () -> { try {
Graph.load(graph, fileName, String.class, Integer.class);
struct.load(graph, fileName, String.class, Integer.class);
} catch (IOException e) {
fail();
e.printStackTrace();
@@ -1454,28 +1482,29 @@ public class TestGraph {
private void shouldContain(Collection<?> actual, Object... expected) {
assertTrue("You should pass me a collection!", actual != null);
assertEquals("They have not the same number of elements\nActual: " + actual, expected.length, actual.size());
assertNotNull(actual, "You should pass me a collection!");
assertEquals(expected.length, actual.size(), "They have not the same number of elements\nActual: " + actual);
for (Object obj : expected)
assertTrue("Not containing: [" + obj + "]\nBut has: " + actual, actual.contains(obj));
assertTrue(actual.contains(obj), "Not containing: [" + obj + "]\nBut has: " + actual);
}
private void shouldContainInOrder(List<?> actual, Object... expected) {
assertTrue("You should pass me a list!", actual != null);
assertEquals("They have not the same number of elements\nActual: " + actual, expected.length, actual.size());
assertNotNull(actual, "You should pass me a list!");
assertEquals(expected.length, actual.size(), "They have not the same number of elements\nActual: " + actual);
for (int i = 0; i < actual.size(); i++)
assertEquals("Index: " + i, expected[i], actual.get(i));
assertEquals(expected[i], actual.get(i), "Index: " + i);
}
private void shouldThrow(Exception expected, Runnable runnable) {
try {
runnable.run();
fail("It has't thrown: " + expected.getClass().getSimpleName());
fail("It hasn't thrown: " + expected.getClass().getSimpleName());
} catch (Exception actual) {
assertEquals(expected.getClass(), actual.getClass());
assertEquals(expected.getMessage(), actual.getMessage());
if(expected.getMessage()!=null)
assertEquals(expected.getMessage(), actual.getMessage());
}
}
}

View File

@@ -1 +1 @@
{"vertices":["\"1\"","\"2\"","\"3\"","\"4\"","\"5\"","\"6\"","\"7\"","\"8\""],"edges":[{"src":"\"1\"","dest":"\"2\"","weight":"1"},{"src":"\"1\"","dest":"\"3\"","weight":"1"},{"src":"\"5\"","dest":"\"4\"","weight":"5"},{"src":"\"6\"","dest":"\"2\"","weight":"2"},{"src":"\"5\"","dest":"\"3\"","weight":"2"},{"src":"\"8\"","dest":"\"7\"","weight":"9"},{"src":"\"4\"","dest":"\"6\"","weight":"6"},{"src":"\"2\"","dest":"\"5\"","weight":"4"}],"other":""}
{"gson":{"calls":{"threadLocalHashCode":865977613},"typeTokenCache":{"com.google.gson.reflect.TypeToken\u003c?\u003e":{},"com.google.gson.InstanceCreator\u003c?\u003e":{},"java.util.Map\u003ccom.google.gson.reflect.TypeToken\u003c?\u003e, com.google.gson.TypeAdapter\u003c?\u003e\u003e":{},"java.lang.Class\u003c?\u003e":{},"com.google.gson.internal.reflect.ReflectionAccessor":{},"com.google.gson.internal.ConstructorConstructor":{},"java.util.List\u003ccom.google.gson.ExclusionStrategy\u003e":{},"com.google.gson.internal.Excluder":{},"java.util.Map\u003cjava.lang.reflect.Type, com.google.gson.InstanceCreator\u003c?\u003e\u003e":{},"com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory":{},"berack96.lib.graph.models.EdgeSaveStructure":{},"berack96.lib.graph.models.EdgeSaveStructure[]":{},"java.util.List\u003ccom.google.gson.TypeAdapterFactory\u003e":{},"com.google.gson.FieldNamingStrategy":{},"com.google.gson.Gson":{},"double":{},"java.lang.String":{},"java.lang.String[]":{},"java.lang.reflect.Type":{},"int":{},"com.google.gson.ExclusionStrategy":{},"com.google.gson.TypeAdapter\u003c?\u003e":{},"java.lang.Integer":{},"com.google.gson.TypeAdapterFactory":{},"java.lang.ThreadLocal\u003cjava.util.Map\u003ccom.google.gson.reflect.TypeToken\u003c?\u003e, com.google.gson.Gson$FutureTypeAdapter\u003c?\u003e\u003e\u003e":{},"boolean":{},"com.google.gson.LongSerializationPolicy":{},"berack96.lib.graph.models.GraphSaveStructure":{}},"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}},"jsonAdapterFactory":{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}}},"factories":[null,null,{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}}},{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}},"complexMapKeySerialization":false},{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}}},null,{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}},"fieldNamingPolicy":"IDENTITY","excluder":{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]},"jsonAdapterFactory":{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}}},"accessor":{"theUnsafe":{}}}],"excluder":{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]},"fieldNamingStrategy":"IDENTITY","instanceCreators":{},"serializeNulls":false,"complexMapKeySerialization":false,"generateNonExecutableJson":false,"htmlSafe":true,"prettyPrinting":false,"lenient":false,"serializeSpecialFloatingPointValues":false,"dateStyle":2,"timeStyle":2,"longSerializationPolicy":"DEFAULT","builderFactories":[],"builderHierarchyFactories":[]},"vertices":["\"1\"","\"2\"","\"3\"","\"4\"","\"5\"","\"6\"","\"7\"","\"8\""],"edges":[{"src":"\"1\"","dest":"\"2\"","weight":"1"},{"src":"\"1\"","dest":"\"3\"","weight":"1"},{"src":"\"5\"","dest":"\"4\"","weight":"5"},{"src":"\"6\"","dest":"\"2\"","weight":"2"},{"src":"\"5\"","dest":"\"3\"","weight":"2"},{"src":"\"8\"","dest":"\"7\"","weight":"9"},{"src":"\"4\"","dest":"\"6\"","weight":"6"},{"src":"\"2\"","dest":"\"5\"","weight":"4"}]}