### Added edge-betweeness centrality and edge direction.

`Thanks to the contribution of Thibaut Démare.`
parent 86d05e5c
 ... ... @@ -222,6 +222,12 @@ public class TestBetweenessCentrality { assertEquals(0, (Double) graph.getNode("C").getAttribute("Cb"), 0); assertEquals(2, (Double) graph.getNode("D").getAttribute("Cb"), 0); assertEquals(4, (Double) graph.getNode("E").getAttribute("Cb"), 0); assertEquals(8, (Double) graph.getEdge("AB").getAttribute("Cb"), 0); assertEquals(8, (Double) graph.getEdge("AE").getAttribute("Cb"), 0); assertEquals(0, (Double) graph.getEdge("BE").getAttribute("Cb"), 0); assertEquals(4, (Double) graph.getEdge("BC").getAttribute("Cb"), 0); assertEquals(4, (Double) graph.getEdge("CD").getAttribute("Cb"), 0); assertEquals(8, (Double) graph.getEdge("ED").getAttribute("Cb"), 0); } @Test ... ...
 ... ... @@ -45,8 +45,10 @@ import org.graphstream.graph.Path; * An implementation of the A* algorithm. * *

* A* computes the shortest path from a node to another in a graph. It can * eventually fail if the two nodes are in two distinct connected components. * A* computes the shortest path from a node to another in a graph. It guarantees * that the path found is the shortest one, given its heuristic is admissible, * and a path exists between the two nodes. It will fail if the two nodes are in * two distinct connected components. *

* *

... ... @@ -63,15 +65,22 @@ import org.graphstream.graph.Path; * *

* By default the {@link org.graphstream.algorithm.AStar.Costs} implementation * used uses a heuristic that returns 0 for any heuristic. This makes A* an * equivalent of the Dijkstra algorithm, but also makes it far less efficient. * used uses a heuristic that always returns 0. This makes A* an * equivalent of * the Dijkstra algorithm, but also makes it less efficient. *

* *

* If there are several equivalent shortest paths between the two nodes, the returned * one is arbitrary. Therefore this AStar algorithm works with multi-graphs but if two * edges between two nodes have the same properties, the one that will be chosen will * be arbitrary. *

* *

Usage

* *

The basic usage is to create an instance of A*, then to ask it to compute * from a shortest path from one target to one destination, and finally to ask * for that path: *

The basic usage is to create an instance of A* (optionally specify a {@link Costs} * object), then to ask it to compute from a shortest path from one target to one * destination, and finally to ask for that path: *

*
* AStart astar = new AStar(graph);
...  ...  @@ -80,11 +89,11 @@ import org.graphstream.graph.Path;
*
*

* The advantage of A* is that it can consider any cost function to drive the * search. You can create your own cost functions implementing the * search. You can (and should) create your own cost functions implementing the * {@link org.graphstream.algorithm.AStar.Costs} interface. *

*

* You can also test the default "distance" cost function on a graph that has * You can also test the default euclidean "distance" cost function on a graph that has * "x" and "y" values. You specify the {@link Costs} function before calling the * {@link #compute(String,String)} method: *

... ... @@ -152,7 +161,6 @@ import org.graphstream.graph.Path; * } * * * * @complexity The complexity of A* depends on the heuristic. */ public class AStar implements Algorithm { ... ... @@ -482,7 +490,6 @@ public class AStar implements Algorithm { // Nested classes /** * The definition of an heuristic. The heuristic is in charge of evaluating * the distance between the current position and the target. */ public interface Costs { ... ... @@ -496,7 +503,7 @@ public class AStar implements Algorithm { * @return The estimated cost between a node and a target node. */ double heuristic(Node node, Node target); /** * Cost of displacement from parent to next. The next node must be * directly connected to parent, or -1 is returned. ... ... @@ -504,6 +511,7 @@ public class AStar implements Algorithm { * @param parent * The node we come from. * @param from * The definition of an heuristic. The heuristic is in charge of evaluating * The edge used between the two nodes (in case this is a * multi-graph). * @param next ... ...
 ... ... @@ -37,6 +37,7 @@ import java.util.PriorityQueue; import java.util.Set; import org.graphstream.graph.Edge; import org.graphstream.graph.Element; import org.graphstream.graph.Graph; import org.graphstream.graph.Node; ... ... @@ -52,12 +53,12 @@ import org.graphstream.graph.Node; *

Usage

* *

* This algorithm, by default, stores the centrality values for each edge inside * This algorithm, by default, stores the centrality values for each node inside * the "Cb" attribute. You can change this attribute name at construction time. *

* *

* This algorithm does not accept multi-graphs (p-graphs with p>1) yet. * This algorithm does not accept multi-graphs (p-graphs with p>1) yet. *

* *

... ... @@ -159,30 +160,39 @@ import org.graphstream.graph.Node; * issn 0378-8733, "DOI: 10.1016/j.socnet.2007.11.001". */ public class BetweennessCentrality implements Algorithm { // Attribute protected static double INFINITY = 1000000.0; /** Store the centrality value in this attribute on nodes and edges. */ protected String centralityAttributeName = "Cb"; /** The predecessors. */ protected String predAttributeName = "brandes.P"; /** The sigma value. */ protected String sigmaAttributeName = "brandes.sigma"; /** The distance value. */ protected String distAttributeName = "brandes.d"; /** The delta value. */ protected String deltaAttributeName = "brandes.delta"; /** Name of the attribute used to retrieve weights on edges. */ protected String weightAttributeName = "weight"; /** Do not use weights ? */ protected boolean unweighted = true; /** The graph to modify. */ protected Graph graph; /** The progress call-back method. */ protected Progress progress = null; // Construction /** Compute the centrality of edges. */ protected boolean doEdges = true; /** * New centrality algorithm that will perform as if the graph was * unweighted. By default the centrality will be stored in a "Cb" attribute ... ... @@ -226,8 +236,6 @@ public class BetweennessCentrality implements Algorithm { this.unweighted = false; } // Access /** * Name of the attribute used to retrieve weights on edges. */ ... ... @@ -242,8 +250,6 @@ public class BetweennessCentrality implements Algorithm { return centralityAttributeName; } // Command /** * Specify the name of the weight attribute to retrieve edge attributes. * This automatically set the algorithm to perform on the graph as if it was ... ... @@ -270,6 +276,17 @@ public class BetweennessCentrality implements Algorithm { public void setUnweighted() { unweighted = true; } /** * Activate or deactivate the centrality computation on edges. By default it is * activated. Notice that this does not change the complexity of the algorithm. * Only one more access on the edges is done to store the centrality in addition * to the node access. * @param on If true, the edges centrality is also computed. */ public void computeEdgeCentrality(boolean on) { doEdges = on; } /** * Specify the name of the attribute used to store the computed centrality ... ... @@ -306,13 +323,14 @@ public class BetweennessCentrality implements Algorithm { } /** * Compute the betweenness centrality on the given graph for each node. This * method is equivalent to a call in sequence to the two methods * {@link #init(Graph)} then {@link #compute()}. * Compute the betweenness centrality on the given graph for each node and * eventually edges. This method is equivalent to a call in sequence to the * two methods {@link #init(Graph)} then {@link #compute()}. */ public void betweennessCentrality(Graph graph) { init(graph); initAllNodes(graph); initAllEdges(graph); float n = graph.getNodeCount(); float i = 0; ... ... @@ -326,13 +344,18 @@ public class BetweennessCentrality implements Algorithm { S = dijkstraExplore2(s, graph); // The really new things in the Brandes algorithm are here: // Accumulation phase: while (!S.isEmpty()) { Node w = S.poll(); for (Node v : predecessorsOf(w)) { setDelta(v, delta(v) + ((sigma(v) / sigma(w)) * (1.0 + delta(w)))); double c = ((sigma(v) / sigma(w)) * (1.0 + delta(w))); if(doEdges) { Edge e = w.getEdgeBetween(v); setCentrality(e, centrality(e) + c); } setDelta(v, delta(v) + c); } if (w != s) { setCentrality(w, centrality(w) + delta(w)); ... ... @@ -371,10 +394,11 @@ public class BetweennessCentrality implements Algorithm { Node v = Q.removeFirst(); S.add(v); Iterator ww = v.getNeighborNodeIterator(); Iterator ww = v.getLeavingEdgeIterator(); while (ww.hasNext()) { Node w = ww.next(); Edge l = ww.next(); Node w = l.getOpposite(v);//ww.next(); if (distance(w) == INFINITY) { setDistance(w, distance(v) + 1); ... ... @@ -422,10 +446,14 @@ public class BetweennessCentrality implements Algorithm { } else { S.add(u); Iterator k = u.getNeighborNodeIterator(); // Iterator k = u.getNeighborNodeIterator(); Iterator k = u.getLeavingEdgeIterator(); while (k.hasNext()) { Node v = k.next(); // Node v = k.next(); Edge l = k.next(); Node v = l.getOpposite(u); double alt = distance(u) + weight(u, v); if (alt < distance(v)) { ... ... @@ -488,10 +516,14 @@ public class BetweennessCentrality implements Algorithm { S.add(v); Iterator k = v.getNeighborNodeIterator(); //Iterator k = v.getNeighborNodeIterator(); Iterator k = v.getLeavingEdgeIterator(); while (k.hasNext()) { Node w = k.next(); //Node w = k.next(); Edge l = k.next(); Node w = l.getOpposite(v); double alt = distance(v) + weight(v, w); double dw = distance(w); ... ... @@ -565,16 +597,16 @@ public class BetweennessCentrality implements Algorithm { } /** * The centrality value of the given node. * The centrality value of the given node or edge. * * @param node * Extract the centrality of this node. * @param elt * Extract the centrality of this node or edge. * @return The centrality value. */ public double centrality(Node node) { return node.getNumber(centralityAttributeName); public double centrality(Element elt) { return elt.getNumber(centralityAttributeName); } /** * List of predecessors of the given node. * ... ... @@ -624,17 +656,17 @@ public class BetweennessCentrality implements Algorithm { } /** * Set the centrality of the given node. * Set the centrality of the given node or edge. * * @param node * The node to modify. * @param elt * The node or edge to modify. * @param centrality * The centrality to store on the node. */ public void setCentrality(Node node, double centrality) { node.setAttribute(centralityAttributeName, centrality); public void setCentrality(Element elt, double centrality) { elt.setAttribute(centralityAttributeName, centrality); } /** * Set the weight of the edge between 'from' and 'to'. * ... ... @@ -727,6 +759,20 @@ public class BetweennessCentrality implements Algorithm { setCentrality(node, 0.0); } } /** * Set a default centrality of 0 to all edges. * * @param graph * The graph to modify. */ protected void initAllEdges(Graph graph) { if(doEdges) { for(Edge edge : graph.getEachEdge()) { setCentrality(edge, 0.0); } } } /** * Add a default value for attributes used during computation. ... ...

 ... ... @@ -266,8 +266,8 @@ public class Eades84Layout extends PipeBase implements Layout { } public void particleMoved(Object id, double x, double y, double z) { for (LayoutListener listener : listeners) listener.nodeMoved((String) id, x, y, z); //for (LayoutListener listener : listeners) // listener.nodeMoved((String) id, x, y, z); Object xyz[] = new Object; xyz = x; ... ...
 ... ... @@ -207,8 +207,8 @@ public class HierarchicalLayout extends PipeBase implements Layout { sendNodeAttributeChanged(sourceId, n.getId(), "xyz", null, new double[] { p.x, p.y, 0 }); for (int i = 0; i < listeners.size(); i++) listeners.get(i).nodeMoved(n.getId(), p.x, p.y, 0); // for (int i = 0; i < listeners.size(); i++) // listeners.get(i).nodeMoved(n.getId(), p.x, p.y, 0); } } } ... ...
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!