Save/Load
* improved Tests * fixed subGraph of markers * added support for save/load graphically * not all pass... must continue coding
This commit is contained in:
@@ -27,7 +27,7 @@ public class Edge<V, W extends Number> {
|
||||
*
|
||||
* @param source the source of the edge
|
||||
* @param destination the destination of the edge
|
||||
* @param weight the weight od the edge
|
||||
* @param weight the weight of the edge
|
||||
*/
|
||||
public Edge(V source, V destination, W weight) {
|
||||
this.source = source;
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
@@ -24,11 +25,12 @@ import berack96.sim.util.graph.visit.VisitStrategy;
|
||||
*/
|
||||
public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
|
||||
String NOT_DAG = "The graph is not a DAG";
|
||||
String NOT_CONNECTED = "The source vertex doesn't have a path that reach the destination";
|
||||
String PARAM_NULL = "The parameter must not be null";
|
||||
String VERTEX_NOT_CONTAINED = "The vertex must be contained in the graph";
|
||||
|
||||
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();
|
||||
|
||||
/**
|
||||
* Tells if the graph has some cycle.<br>
|
||||
* A cycle is detected if visiting the graph G starting from V1 (that is any of the vertex of G),
|
||||
@@ -515,7 +517,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
/**
|
||||
* Get a sub-graph of the current one with only the vertex marked with the selected markers.<br>
|
||||
* Each vertex will have all his edges, but only the ones with the destination marked with the same marker.<br>
|
||||
* If the marker is null then the returning graph will have all the vertices that are not marked by any marker.<br>
|
||||
* If the marker is not specified or is null then the returning graph will have all the vertices that are not marked by any marker.<br>
|
||||
* If the graph doesn't contain any vertex with that marker then an empty graph is returned.
|
||||
*
|
||||
* @param marker one or more markers
|
||||
@@ -547,19 +549,21 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
static void save(Graph<?, ?> graph, String file) throws IOException {
|
||||
GraphSaveStructure<?, ?> save = new GraphSaveStructure<>(graph);
|
||||
Gson gson = new Gson();
|
||||
save(graph, "", file);
|
||||
}
|
||||
|
||||
static <V, W extends Number> void save(Graph<V, W> graph, String other, String file) throws IOException {
|
||||
GraphSaveStructure<V, W> save = new GraphSaveStructure<>(graph, other);
|
||||
FileWriter writer = new FileWriter(file);
|
||||
|
||||
writer.write(gson.toJson(save));
|
||||
GSON.toJson(save, writer);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <V, W extends Number> void load(Graph<V, W> graph, String file) throws IOException {
|
||||
static <V, W extends Number> String load(Graph<V, W> graph, String file, Class<V> classV, Class<W> classW) throws IOException {
|
||||
graph.removeAllVertex();
|
||||
|
||||
Gson gson = new Gson();
|
||||
FileReader reader = new FileReader(file);
|
||||
StringBuilder fileContent = new StringBuilder();
|
||||
int c;
|
||||
@@ -567,21 +571,53 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
while((c = reader.read()) != -1)
|
||||
fileContent.append((char)c);
|
||||
reader.close();
|
||||
GraphSaveStructure<V, W> save = gson.fromJson(fileContent.toString(), GraphSaveStructure.class);
|
||||
GraphSaveStructure<V, W> save = GSON.fromJson(fileContent.toString(), GraphSaveStructure.class);
|
||||
|
||||
graph.addAllVertices(save.vertices);
|
||||
graph.addAllEdges(save.edges);
|
||||
for(String str : save.vertices)
|
||||
graph.addVertex(GSON.fromJson(str, classV));
|
||||
|
||||
for(int i = 0; i<save.edges.src.size(); i++) {
|
||||
V s = GSON.fromJson(save.edges.src.get(i), classV);
|
||||
V d = GSON.fromJson(save.edges.dest.get(i), classV);
|
||||
W w = GSON.fromJson(save.edges.weight.get(i), classW);
|
||||
graph.addEdge(s, d, w);
|
||||
}
|
||||
return save.other;
|
||||
}
|
||||
|
||||
class GraphSaveStructure<V, W extends Number> {
|
||||
public GraphSaveStructure() {}
|
||||
protected GraphSaveStructure(Graph<V, W> graph) {
|
||||
vertices = graph.vertices();
|
||||
edges = graph.edges();
|
||||
protected GraphSaveStructure(Graph<V, W> graph, String other) {
|
||||
vertices = new LinkedList<>();
|
||||
|
||||
for(V v: graph.vertices())
|
||||
vertices.add(GSON.toJson(v));
|
||||
edges = new EdgeSaveStructure<>(graph.edges());
|
||||
this.other = other;
|
||||
}
|
||||
|
||||
public Collection<V> vertices;
|
||||
public Collection<Edge<V, W>> edges;
|
||||
public List<String> vertices;
|
||||
public EdgeSaveStructure<V, W> edges;
|
||||
public String other;
|
||||
}
|
||||
|
||||
class EdgeSaveStructure<V, W extends Number> {
|
||||
public EdgeSaveStructure() {}
|
||||
protected EdgeSaveStructure(Collection<Edge<V, W>> edges) {
|
||||
src = new LinkedList<>();
|
||||
dest = new LinkedList<>();
|
||||
weight = new LinkedList<>();
|
||||
|
||||
for(Edge<V, W> ed : edges) {
|
||||
src.add(GSON.toJson(ed.getSource()));
|
||||
dest.add(GSON.toJson(ed.getDestination()));
|
||||
weight.add(GSON.toJson(ed.getWeight()));
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> src;
|
||||
public List<String> dest;
|
||||
public List<String> weight;
|
||||
}
|
||||
|
||||
// TODO maybe -> STATIC saveOnFile(orString) INSTANCE loadFromFile(orString), but need JSON parser
|
||||
|
||||
@@ -416,17 +416,18 @@ public class MapGraph<V, W extends Number> implements Graph<V, W> {
|
||||
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 (marker != null)
|
||||
if (!isEmpty)
|
||||
for (Object mark: marker)
|
||||
allMarkers.add(mark);
|
||||
|
||||
markers.forEach( (mark, set) -> {
|
||||
if (marker == null || allMarkers.contains(mark))
|
||||
if (isEmpty || allMarkers.contains(mark))
|
||||
allVertices.addAll(set);
|
||||
});
|
||||
|
||||
if (marker == null) {
|
||||
|
||||
if (isEmpty) {
|
||||
Collection<V> toAdd = vertices();
|
||||
toAdd.removeAll(allVertices);
|
||||
allVertices.clear();
|
||||
|
||||
@@ -4,8 +4,6 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
@@ -22,8 +20,6 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.border.BevelBorder;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import berack96.sim.util.graph.Graph;
|
||||
import berack96.sim.util.graph.view.edge.EdgeListener;
|
||||
import berack96.sim.util.graph.view.vertex.VertexListener;
|
||||
@@ -141,24 +137,34 @@ public class GraphInfo<V, W extends Number> extends JPanel {
|
||||
components.forEach(panelVertex::add);
|
||||
components.clear();
|
||||
|
||||
/* SAVE/LOAD errors */
|
||||
JLabel textResult = new JLabel();
|
||||
textResult.setForeground(Color.RED);
|
||||
|
||||
JPanel panelErrors = new JPanel();
|
||||
panelErrors.setOpaque(false);
|
||||
panelErrors.add(textResult);
|
||||
|
||||
/* SAVE/LOAD */
|
||||
/*
|
||||
JTextField fileText = new JTextField();
|
||||
JButton saveB = new JButton("Save");
|
||||
saveB.addActionListener(a -> {
|
||||
try {
|
||||
Graph.save(graphPanel.getGraph(), fileText.getText());
|
||||
graphPanel.save(fileText.getText());
|
||||
textResult.setText("");
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
textResult.setText(e1.getMessage());
|
||||
}
|
||||
});
|
||||
JButton loadB = new JButton("Load");
|
||||
loadB.addActionListener(a -> {
|
||||
try {
|
||||
Graph<V, W> graph = graphPanel.getGraph();
|
||||
Graph.load((Graph<Object, Number>) graph, fileText.getText());
|
||||
graphPanel.load(fileText.getText());
|
||||
textResult.setText("");
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
textResult.setText(e1.getMessage());
|
||||
}
|
||||
});
|
||||
components.add(new JLabel("File to save/load: "));
|
||||
@@ -172,7 +178,6 @@ public class GraphInfo<V, W extends Number> extends JPanel {
|
||||
panelSave.setLayout(new GridLayout(components.size()/2, 2, 2*2, 2*2));
|
||||
components.forEach(panelSave::add);
|
||||
components.clear();
|
||||
*/
|
||||
|
||||
/* ADDING COMPONENTS */
|
||||
this.setBackground(Color.LIGHT_GRAY);
|
||||
@@ -182,6 +187,8 @@ public class GraphInfo<V, W extends Number> extends JPanel {
|
||||
this.add(panelDescription);
|
||||
this.add(panelInfo);
|
||||
this.add(panelVertex);
|
||||
this.add(panelErrors);
|
||||
this.add(panelSave);
|
||||
/*this.add(panelSave);*/
|
||||
|
||||
modVertex.doClick();
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
package berack96.sim.util.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.sim.util.graph.Edge;
|
||||
import berack96.sim.util.graph.Graph;
|
||||
import berack96.sim.util.graph.MapGraph;
|
||||
import berack96.sim.util.graph.Vertex;
|
||||
import berack96.sim.util.graph.view.edge.EdgeComponent;
|
||||
import berack96.sim.util.graph.view.vertex.VertexComponent;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({"unchecked", "deprecation"})
|
||||
public class GraphPanel<V, W extends Number> extends Component {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -60,8 +70,14 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
|
||||
if (component == null) {
|
||||
VertexComponent<V> v = new VertexComponent<>(new Vertex<>(graph, vertex));
|
||||
if (!graph.contains(vertex)) {
|
||||
v.vertex.addIfAbsent();
|
||||
v.vertex.addIfAbsent();
|
||||
boolean isContained = false;
|
||||
|
||||
for(Component comp : vertices.getComponents())
|
||||
if (comp.equals(v))
|
||||
isContained = true;
|
||||
|
||||
if (!isContained) {
|
||||
v.setBounds(vertexRender.getBox(v, center));
|
||||
vertices.add(v);
|
||||
}
|
||||
@@ -81,6 +97,20 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
vertex.setLocation(rectangle.x, rectangle.y);
|
||||
}
|
||||
|
||||
public void addEdge(Edge<V, W> edge) {
|
||||
VertexComponent<V> vSource = null;
|
||||
VertexComponent<V> vDest = null;
|
||||
for (Component comp : vertices.getComponents()) {
|
||||
VertexComponent<V> temp = (VertexComponent<V>) comp;
|
||||
V vTemp = temp.vertex.getValue();
|
||||
if (vSource == null && vTemp.equals(edge.getSource()))
|
||||
vSource = temp;
|
||||
if (vDest == null && vTemp.equals(edge.getDestination()))
|
||||
vDest = temp;
|
||||
}
|
||||
addEdge(vSource, vDest, edge.getWeight());
|
||||
}
|
||||
|
||||
public void addEdge(VertexComponent<V> source, VertexComponent<V> dest, W weight) {
|
||||
try {
|
||||
Point center = new Point(Math.abs(source.getX() - dest.getY()), Math.abs(source.getY() - dest.getY()));
|
||||
@@ -88,7 +118,9 @@ 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) {}
|
||||
} catch (Exception ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEdge(VertexComponent<V> source, VertexComponent<V> dest) {
|
||||
@@ -128,6 +160,26 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
observers.remove(observer);
|
||||
}
|
||||
|
||||
public void save(String fileName) throws IOException {
|
||||
GraphGraphicalSave save = new GraphGraphicalSave(vertices);
|
||||
Graph.save(graph, Graph.GSON.toJson(save), fileName);
|
||||
}
|
||||
|
||||
public void load(String fileName) throws IOException {
|
||||
String saveContent = Graph.load(graph, fileName);
|
||||
GraphGraphicalSave save = Graph.GSON.fromJson(saveContent, GraphGraphicalSave.class);
|
||||
vertices.removeAll();
|
||||
edges.removeAll();
|
||||
|
||||
for(int i = 0; i<save.vertices.size(); i++) {
|
||||
V v = save.vertices.get(i);
|
||||
Point p = save.points.get(i);
|
||||
addVertex(p, v);
|
||||
}
|
||||
save.vertices.forEach(v -> graph.getEdgesOut(v).forEach(e -> addEdge(e)));
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBounds(int x, int y, int width, int height) {
|
||||
@@ -170,5 +222,20 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
private void updateObservers() {
|
||||
observers.forEach(observer -> observer.update(null, this.graph));
|
||||
}
|
||||
|
||||
|
||||
class GraphGraphicalSave {
|
||||
public GraphGraphicalSave() {}
|
||||
protected GraphGraphicalSave(Container vertices) {
|
||||
this.vertices = new LinkedList<>();
|
||||
this.points = new LinkedList<>();
|
||||
|
||||
for(Component vertex : vertices.getComponents()) {
|
||||
this.points.add(new Point(vertex.getX(), vertex.getY()));
|
||||
this.vertices.add(((VertexComponent<V>) vertex).vertex.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public List<V> vertices;
|
||||
public List<Point> points;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,19 @@ public class VertexComponent<V> extends Component {
|
||||
public VertexComponent(Vertex<V> vertex) {
|
||||
this.vertex = vertex;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + vertex + " {" + getX() + "," + getY() + "}]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
try {
|
||||
return obj.getClass().equals(getClass()) && obj.toString().equals(toString());
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ public class TestGraph {
|
||||
public void after() {
|
||||
try {
|
||||
String printed = bytes.toString(encoding);
|
||||
bytes.reset();
|
||||
if (!printed.isEmpty())
|
||||
fail("Remove the printed string in the methods: " + printed);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
@@ -1186,6 +1187,10 @@ public class TestGraph {
|
||||
new Edge<>("5", "4", 5),
|
||||
new Edge<>("6", "2", 2));
|
||||
|
||||
sub = graph.subGraph();
|
||||
shouldContain(sub.vertices(), "7", "8");
|
||||
shouldContain(sub.edges(), new Edge<>("8", "7", 9));
|
||||
|
||||
sub = graph.subGraph(null);
|
||||
shouldContain(sub.vertices(), "7", "8");
|
||||
shouldContain(sub.edges(), new Edge<>("8", "7", 9));
|
||||
@@ -1325,37 +1330,54 @@ public class TestGraph {
|
||||
*/
|
||||
|
||||
String fileName = "test/resources/test.json";
|
||||
Set<String> vertices = new HashSet<>();
|
||||
Set<Edge<String, Integer>> edges = new HashSet<>();
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
vertices.add("1");
|
||||
vertices.add("2");
|
||||
vertices.add("3");
|
||||
vertices.add("4");
|
||||
vertices.add("5");
|
||||
vertices.add("6");
|
||||
vertices.add("7");
|
||||
vertices.add("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
graph.addEdge("2", "5", 4);
|
||||
graph.addEdge("4", "6", 6);
|
||||
graph.addEdge("5", "3", 2);
|
||||
graph.addEdge("5", "4", 5);
|
||||
graph.addEdge("6", "2", 2);
|
||||
graph.addEdge("8", "7", 9);
|
||||
edges.add(new Edge<>("1", "2", 1));
|
||||
edges.add(new Edge<>("1", "3", 1));
|
||||
edges.add(new Edge<>("2", "5", 4));
|
||||
edges.add(new Edge<>("4", "6", 6));
|
||||
edges.add(new Edge<>("5", "3", 2));
|
||||
edges.add(new Edge<>("5", "4", 5));
|
||||
edges.add(new Edge<>("6", "2", 2));
|
||||
edges.add(new Edge<>("8", "7", 9));
|
||||
|
||||
graph.addAllVertices(vertices);
|
||||
graph.addAllEdges(edges);
|
||||
|
||||
/* because GSON convert to double */
|
||||
/*
|
||||
Set<Edge<String, Double>> edgesD = new HashSet<>();
|
||||
edges.forEach((e) -> edgesD.add(new Edge<String, Double>(e.getSource(), e.getDestination(), e.getWeight().doubleValue())));
|
||||
*/
|
||||
Set<Edge<String, Integer>> edgesD = edges;
|
||||
|
||||
try {
|
||||
Graph.save(graph, fileName);
|
||||
Graph.load(graph, fileName);
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
shouldContain(graph.edges(), edgesD.toArray());
|
||||
|
||||
graph.removeAllVertex();
|
||||
Graph.load(graph, fileName);
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
shouldContain(graph.edges(), edgesD.toArray());
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
graph = null;
|
||||
shouldThrow(new NullPointerException(), () -> { try {
|
||||
Graph.load(graph, fileName);
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"vertices":["1","2","3","4","5","6","7","8"],"edges":[{"source":"1","destination":"2","weight":1},{"source":"1","destination":"3","weight":1},{"source":"5","destination":"4","weight":5},{"source":"6","destination":"2","weight":2},{"source":"5","destination":"3","weight":2},{"source":"8","destination":"7","weight":9},{"source":"4","destination":"6","weight":6},{"source":"2","destination":"5","weight":4}]}
|
||||
{"vertices":["1","2","3","4","5","6","7","8"],"edges":[{"source":"1","destination":"2","weight":1},{"source":"1","destination":"3","weight":1},{"source":"5","destination":"4","weight":5},{"source":"6","destination":"2","weight":2},{"source":"5","destination":"3","weight":2},{"source":"8","destination":"7","weight":9},{"source":"4","destination":"6","weight":6},{"source":"2","destination":"5","weight":4}],"other":""}
|
||||
Reference in New Issue
Block a user