I have a use case as below. I need to construct a graph from a set of input as below -
SimpleDirectedGraph<String, DefaultEdge> g = new SimpleDirectedGraph<>(DefaultEdge.class);
g.addVertex("APP");
g.addVertex("CHROME");
g.addVertex("MOZILLA");
g.addVertex("LAPTOP");
g.addVertex("SERVER");
g.addVertex("CHROME_DEV");
g.addVertex("MOZILLA_DEV");
g.addVertex("APP_DEV");
Add edges for Server
g.addEdge("SERVER", "APP");
g.addEdge("SERVER", "CHROME");
g.addEdge("SERVER", "MOZILLA");
Add edges for Laptop
g.addEdge("LAPTOP", "APP_DEV");
g.addEdge("LAPTOP", "CHROME_DEV");
g.addEdge("LAPTOP", "MOZILLA_DEV");
Add Connecting edges between these 2 sets
g.addEdge("CHROME", "CHROME_DEV");
g.addEdge("MOZILLA", "MOZILLA_DEV");
Now i can construct a graph like this and the structure will looks something as below -
But my use starts here. Imagine i have removed the connecting edges from the graph above
g.removeEdge("CHROME", "CHROME_DEV");
g.removeEdge("MOZILLA", "MOZILLA_DEV");
Now my graph is essentially disjoint from each other. How do I find out it is disjoint graphs and how to get both the disjoint graphs. I will have to treat these two disjoint graphs separately here after.
What you are looking for is called 'connected components'. Have a look at the ConnectivityInspector.
To test whether your graph is connected:
Graph<String, DefaultEdge> g = new SimpleDirectedGraph<>(DefaultEdge.class);
ConnectivityInspector ci = new ConnectivityInspector(g);
//Test whether the graph is connected:
ci.isConnected();
You can get the vertices of each of the connected components using:
Set<String> vertexSets = ci.connectedSets();
For each of these sets, you can then create a graph induced on these vertices:
Set<String> vertexSets = ci.connectedSets();
for(Set<String> vertexSet : vertexSets){
Graph<String, DefaultEdge> subgraph = new AsSubGraph(g,vertexSet);
//Do something with the subgraph
}
More information on graph connectivity can be found here. For the purpose of your question you could also look into the difference between 'strongly' and 'weakly' connected components.
Related
I have a graph with nodes to color, where for each node a dataset (a collection of rows / tuples) is associated.
The algorithm is explained by this example:
the uploaded figure shows an execution of Coloring over graph G with
nodes {v1, v3, v2}. Figure (a) initializes nodes as
uncolored. We first consider v1, and select Sσ1 = {{t9, t10}} (Figure (b)). We color nodes v2 and v3 by recursively calling Coloring.
Coloring one node may restrict the color choice of neighboring nodes,
e.g. after we select {{t9, t10}} for v1, we cannot select {{t6, t7,
t10}} for v3 due to the overlapping tuple t10. For node v3,
we have several choices including {{t6, t7}} and {{t7, t8}}. In Figure (c), we assume the coloring algorithm chooses {{t6, t7}} for
v3. As a result, {{t5, t6}}, which was the only choice forv2, cannot
be used due to the overlapping tuple t6. This leads the algorithm
towards an unsatisfying clustering (Figure (d)). The algorithm
backtracks its last decision for v3 by selecting a different color,
{{t7, t8}} for v3 in Figure (e). In this case, the clustering {{t5,
t6}} for v2 does not overlap with {{t7, t8}}. Since we have found a
clustering that satisfies all the constraints (i.e., a coloring of all nodes), Coloring returns true with V containing the nodes and their colors
(i.e., clusterings).
Here's my code i am trying (which i suspect it is wrong the way it colors the nodes because the algorithm runs for too long )
nodeIterator parameter contains all nodes of the graph sorted in customized way.
public Boolean coloring(graph, nodeIterator, vector){
Node nodeIt ;
if (nodeIterator.hasNext())
nodeIt = nodeIterator.next();
else {
return false;
}
// cluster is the current node associated dataset
ArrayList<Dataset<Row>> cluster = allClustersOfGraph.getNextDataset(nodeIt.name);
if (graph.getNeighbors(nodeIt) == null) {
if (!nodeIterator.hasNext()){
colorNode(vector, nodeIt);
return false;
}
else {
colorNode(vector, nodeIt);
nodeIterator.next();
}
}
Iterable<Node> adjNodes = graph.getNeighbors(nodeIt);
Iterator<Node> adjNodesIt = adjNodes.iterator();
// i suspect in the line under, while is an if so that next neighboring nodes of the current processed one, will be in turn processed in the next recursive call of this algorithm
while (adjNodesIt.hasNext()){
Node adjNode = adjNodesIt.next();
if (!checkNodeColored(vector, adjNode)) {
ArrayList<Dataset<Row>> adjCluster = allClustersOfGraph.getNextDataset(adjNode.name);
for (Dataset<Row> subCluster : cluster) {
for (Dataset<Row> subAdjCluster : adjCluster) {
// small datasets (tuples of rows) don't intersect
if (noDatasetIntersection(subCluster, subAdjCluster)) {
colorNode(vector, nodeIt, subCluster);
if (coloring(graph, nodeIterator, vector)) {
return true;
} else {
// vector is where current coloring progress is maintained
// move backwards
vector.remove(vector.size() - 1);
}
}
}
}
} else if (!adjNodesIt.hasNext()) {
// Color last node anyway
colorNode(vector, nodeIt);
return true;
}
}
return false;
}
allClustersOfGraph is of type ArrayList<ArrayList<Dataset<Row>>>
Here's also the pseudo-algorithm :
My question is : i created the loop while (adjNodesIt.hasNext()){...in my code to check for one recursive call all neighboring nodes of the current processed node, is it right to do that in a recursive method ? Also are all limit cases treated through my implementation ?
Thanks for the great help!
I'm trying to implement a class to check if two game objects intersect. Can anyone give me a better solution / more elegant to this problem?
Basically I want to addCollision and know if one object collidesWith another. A double entry matrix seemed a good idea.
private class CollisionMatrix {
private boolean[][] matrix;
private HashMap<Tag, Integer> matrixIndexes = new HashMap<Tag, Integer>();
public CollisionMatrix() {
int i = 0;
for (Tag tag : Tag.values())
matrixIndexes.put(tag, i++);
matrix = new boolean[i][i];
}
private void addCollision(Tag tag1, Tag tag2) {
int p1 = matrixIndexes.get(tag1);
int p2 = matrixIndexes.get(tag2);
matrix[p1][p2] = true;
matrix[p2][p1] = true;
}
private boolean collidesWith(Tag tag1, Tag tag2) {
int p1 = matrixIndexes.get(tag1);
int p2 = matrixIndexes.get(tag2);
return matrix[p1][p2] || matrix[p2][p1];
}
}
This is not a complete answer, but it should set you on a path to get a more complete solution.
The simplest (not efficient) way to do this is to have a list of the objects that can collide with each other and then for every frame in time, got through every object in the list and check if the object collides (Shares the same space or bounding volume) with another one in the list.
pseudo code:
L: list of objects that can potentially collide.
t: time
for each frame in t {
for each object obj in L {
P: list of objects without obj
for each object otherObj in P {
does obj collide with otherObj
}
}
}
While this technically works, it's not a good solution as it will be very slow as soon as you start having many objects, and it doesn't take that many to make it slow.
To make this possible in real time, you would need to add some acceleration techniques.
One of these acceleration techniques is using "Bounding volume hierarchy" or BVH. https://en.wikipedia.org/wiki/Bounding_volume_hierarchy
In a nutshell, BVH is technique or algorithm to enable quick lookups of which objects are likely to collide.
It typically uses some type of tree structure to keep track of the positions and volumes occupied by the said objects. Tree structures provide faster lookup times than just linearly iterating a list multiple times.
Each level of the tree provides a hierarchy of bounding volumes (space the object is likely to occupy). Top levels of the tree provide a bigger volume for the particular object (a more rough, less granular or less fitting to the object's shape), but easier to discard if the object in question is not in that same space (you would know with little calculations that the object would never collide with anything in that same bounding volume). The deeper in the tree you go, the more granular or more fitting to the objects shape the bounding volumes get, until you get the objects which collide.
Hope this helps :)
I'm working on my personal family tree in Java/Eclipse, and happily bumped into prefuse as for graphic representation.
So far the result looks adaquate in regard to my database feed, but I'm still missing key points to make it easier to browse.
Point 1: verteces represent either a person or a union, and my graph is directed from older to younger members. This is reflected by the arrows on the edges. Yet I'd love to group the arrows in 1 direction only (I'm trying to group generations together if you like), but I can't start to find how to do that. For information, I'm using the NodeLinkTreeLayout as of now.
Point 2: aside from the graph itself, my app main window contains a second JPanel where I would like to modify / insert members. So I want to add an action to each node to call the procedures in the second JPanel. My research on how to access a java class from a node are inconclusive so far, it seems that all the examples from the starter prefuse pack are only based on graph interaction.
There it is. You might already have understood that I'm very new to prefuse and not a pro in Java. So any comment / directions / advice would really be appreciated. I will add a screecap and my graph code so you can see what could be done better.
Thank you for your time, and looking forward to reading your insights.
yorran
public class ShowGraph extends Display {
public static final String EDGES = "graph.edges";
public ShowGraph() {
super(new Visualization());
Graph mG = FamGraph.getGraph();
m_vis.addGraph("graph", mG);
m_vis.setInteractive("graphe.edges", null, false);
m_vis.setValue("graph.nodes", null, VisualItem.SHAPE, new Integer(Constants.SHAPE_ELLIPSE));
EdgeRenderer edgeR = new EdgeRenderer(Constants.EDGE_TYPE_CURVE, Constants.EDGE_ARROW_FORWARD);
LabelRenderer nodeR = new LabelRenderer("name");
nodeR.setRoundedCorner(8, 8);
nodeR.setHorizontalAlignment(Constants.LEFT);
DefaultRendererFactory drf = new DefaultRendererFactory();
drf.setDefaultRenderer(nodeR);
drf.setDefaultEdgeRenderer(edgeR);
m_vis.setRendererFactory(drf);
int[] palette = new int[] {
ColorLib.rgb(255, 180, 180), ColorLib.rgb(190, 190, 255)
};
DataColorAction nFill = new DataColorAction("graph.nodes", "label", Constants.NOMINAL, VisualItem.FILLCOLOR, palette);
ColorAction edges = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.gray(230));
ColorAction arrow = new ColorAction("graph.edges", VisualItem.FILLCOLOR, ColorLib.gray(230));
ColorAction text = new ColorAction("graph.nodes", VisualItem.TEXTCOLOR, ColorLib.gray(0));
ActionList color = new ActionList();
color.add(nFill);
color.add(edges);
color.add(arrow);
color.add(text);
ActionList layout = new ActionList(Activity.INFINITY);
//layout.add(new ForceDirectedLayout("graph", true));
layout.add(new NodeLinkTreeLayout("graph"));
layout.add(new RepaintAction());
m_vis.putAction("color", color);
m_vis.putAction("layout", layout);
setSize(1200, 900); //size controlled by parent jpanel - Comment out after tests
pan(360, 250);
setHighQuality(true);
addControlListener(new DragControl());
addControlListener(new PanControl());
addControlListener(new ZoomControl());
addControlListener(new ZoomToFitControl());
m_vis.run("color");
m_vis.run("layout");
}
public static void main(String[] args) {
Fulltree.fireUp();
ShowGraph mG = new ShowGraph();
JFrame frame = new JFrame("My family chart");
JPanel thePanel = new JPanel();
frame.getContentPane().add(thePanel);
thePanel.add(mG);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
So after a lot of reseach, I'm answering to my own questions in case someone meets the same issues :
as for point 1 : ForceDirectedGraph is a lot better than NodeLinkTreeLayout, especially when your graph starts counting many members. Family branches make a lot more sense than viewing generations aligned.
as for point 2 : node related actions are the way to go, through a ControlListener:
addControlListener(new ControlAdapter() {
public void itemClicked(VisualItem item, MouseEvent e) {
// anything you need here
// even filter right and left click for a sub menu
}
});
One more thing : if you add actions to your graph (search, predicates...), make sure to stop them if you need to rebuild your graph at some point. If you don't, your actions will generate errors you will spend hours (if not days) to debug.
I have two separate questions:
How can I get the label of a vertex object.
I tried vertex.getId() .getClass() and similar but nothing is even close to the label I set to the vertex.
and, how can I get a relationship which connects any vertices of a set of vertices.
Iterable<Vertex> startNodes = getVertexList(relationshipStorage.getStartNode(), graph);
Iterable<Vertex> endNodes = getVertexList(relationshipStorage.getEndNode(), graph);
List<Edge> list = StreamSupport.stream(startNodes.spliterator(), false)
.flatMap(vertex1 -> StreamSupport.stream(vertex1.getEdges(Direction.OUT, relationshipId).spliterator(), false))
.filter(edge -> StreamSupport.stream(endNodes.spliterator(), false).anyMatch(vertex -> edge.getVertex(Direction.OUT).equals(vertex)))
.collect(Collectors.toList());
I am currently streaming through all the start vertices and looking if a relationship leaving them matches one of the end vertices.
Isn't there nothing more nicer?
You could use
vertex.getProperty("#class");
to get the name of the class of your vertex.
I use the following code to display a graph:
graph = new Graph(true);
vis = new Visualization();
vis.add(GRAPH, graph);
CustomLabelRenderer re = new CustomLabelRenderer();
re.setImageField(NODE_TYPE_IMAGE);
re.setImagePosition(Constants.TOP);
EdgeRenderer edgeRenderer = new EdgeRenderer(Constants.EDGE_TYPE_LINE, Constants.EDGE_ARROW_FORWARD);
edgeRenderer.setArrowType(Constants.EDGE_ARROW_FORWARD);
edgeRenderer.setArrowHeadSize(10, 10);
DefaultRendererFactory factory = new DefaultRendererFactory(re, edgeRenderer);
factory.add(new InGroupPredicate(EDGE_DECORATORS), new LabelRenderer(VisualItem.LABEL));
vis.setRendererFactory(factory);
As you can see instantiate the graph to use directed edges. Afterwards I set the EdgeRenderer to use arrow heads. However, I can't see any arrows on my edges, but just plain lines. What am I doing wrong?
That's how I add edges:
graph.addEdge(node1, node2);
You need to set the FILLCOLOR for edges:
filter.add(new ColorAction(edges, VisualItem.FILLCOLOR,
ColorLib.rgb(100,100,100));
I reproduce the problem with the RadialGraphView demo and I did not need any changes to the source code except for this line. (Though, I had to change the data file.)