Skip to content
Snippets Groups Projects
Commit 58683a87 authored by Ant01n3's avatar Ant01n3
Browse files

Merge branch 'master' of git+ssh://github.com/graphstream/gs-algo

parents baa360c8 5a53b838
No related merge requests found
...@@ -64,20 +64,93 @@ import org.graphstream.graph.Path; ...@@ -64,20 +64,93 @@ import org.graphstream.graph.Path;
* *
* <p> * <p>
* By default the {@link org.graphstream.algorithm.AStar.Costs} implementation * By default the {@link org.graphstream.algorithm.AStar.Costs} implementation
* used uses an heuristic that returns 0 for any heuristic. This makes A* an * 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. * equivalent of the Dijkstra algorithm, but also makes it far less efficient.
* </p> * </p>
* *
* <p>
* The basic usage of this algorithm is as follows :
* *
* <h2>Usage</h2>
*
* <p>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:
* </p>
* <pre> * <pre>
* AStart astar = new AStar(graph); * AStart astar = new AStar(graph);
* astar.compute(&quot;A&quot;, &quot;Z&quot;); // with A and Z node identifiers in the graph. * astar.compute("A", "Z"); // with A and Z node identifiers in the graph.
* Path path = astar.getShortestPath(); * Path path = astar.getShortestPath();
* </pre> * </pre>
* * <p>
* 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
* {@link #Costs} interface.
* </p> * </p>
* <p>
* You can also test the default "distance" cost function on a graph that has
* "x" and "y" values. You specify the Cost function before calling the
* {@link #compute(String,String)} method:
* </p>
* <pre>
* AStart astar = new AStar(graph);
* astar.setCosts(new DistanceCosts());
* astar.compute("A", "Z");
* Path path = astar.getShortestPath();
* </pre>
*
* <h2>Example</h2>
* import java.io.IOException;
* import java.io.StringReader;
*
* import org.graphstream.algorithm.AStar;
* import org.graphstream.algorithm.AStar.DistanceCosts;
* import org.graphstream.graph.Graph;
* import org.graphstream.graph.implementations.DefaultGraph;
* import org.graphstream.stream.file.FileSourceDGS;
*
* public class AStarTest {
*
* // B-(1)-C
* // / \
* // (1) (10)
* // / \
* // A F
* // \ /
* // (1) (1)
* // \ /
* // D-(1)-E
* static String my_graph =
* "DGS004\n"
* + "my 0 0\n"
* + "an A xy: 0,1\n"
* + "an B xy: 1,2\n"
* + "an C xy: 2,2\n"
* + "an D xy: 1,0\n"
* + "an E xy: 2,0\n"
* + "an F xy: 3,1\n"
* + "ae AB A B weight:1 \n"
* + "ae AD A D weight:1 \n"
* + "ae BC B C weight:1 \n"
* + "ae CF C F weight:10 \n"
* + "ae DE D E weight:1 \n"
* + "ae EF E F weight:1 \n"
* ;
*
* public static void main(String[] args) throws IOException {
* Graph graph = new DefaultGraph("A* Test");
* StringReader reader = new StringReader(my_graph);
*
* FileSourceDGS source = new FileSourceDGS();
* source.addSink(graph);
* source.readAll(reader);
*
* AStar astar = new AStar(graph);
* //astar.setCosts(new DistanceCosts());
* astar.compute("C", "F");
*
* System.out.println(astar.getShortestPath());
* }
* }
* </pre>
* *
* <p> * <p>
* This algorithm uses the <i>std-algo-1.0</i> algorithm's standard. * This algorithm uses the <i>std-algo-1.0</i> algorithm's standard.
......
...@@ -36,29 +36,91 @@ import java.util.List; ...@@ -36,29 +36,91 @@ import java.util.List;
import org.graphstream.graph.Edge; import org.graphstream.graph.Edge;
import org.graphstream.graph.Graph; import org.graphstream.graph.Graph;
import org.graphstream.graph.Node; import org.graphstream.graph.Node;
import org.graphstream.graph.Path; import org.graphstream.graph.Path;
/** /**
* <p> * Implementation of the Bellman-Ford algorithm that computes single-source
* The Bellman-Ford algorithm computes single-source shortest paths in a * shortest paths in a weighted digraph
* weighted digraph (where some of the edge weights may be negative). Dijkstra's * <p>
* algorithm accomplishes the same problem with a lower running time, but * The Bellman-Ford algorithm computes single-source shortest paths in a
* requires edge weights to be non-negative. Thus, Bellman-Ford is usually used * weighted digraph (where some of the edge weights may be negative). Dijkstra's
* only when there are negative edge weights (from the <a * algorithm accomplishes the same problem with a lower running time, but
* href="http://en.wikipedia.org/wiki/Bellman-Ford_algorithm">Wikipedia</a>). * requires edge weights to be non-negative. Thus, Bellman-Ford is usually used
* </p> * only when there are negative edge weights (from the <a
* * href="http://en.wikipedia.org/wiki/Bellman-Ford_algorithm">Wikipedia</a>).
* <h3>Warning</h3> * </p>
* <p> *
* For the moment only attributes located on the edges are supported. * <h2>Example</h2>
* </p> * <pre>
* * import java.io.IOException;
* @complexity O(VxE) time, where V and E are the number of vertices and edges * import java.io.StringReader;
* respectively. *
* * import org.graphstream.algorithm.BellmanFord;
* @author Antoine Dutot * import org.graphstream.graph.Graph;
* @author Yoann Pigné * import org.graphstream.graph.implementations.DefaultGraph;
* * import org.graphstream.stream.file.FileSourceDGS;
*
* public class BellmanFordTest {
*
* // B-(1)-C
* // / \
* // (1) (10)
* // / \
* // A F
* // \ /
* // (1) (1)
* // \ /
* // D-(1)-E
* static String my_graph =
* "DGS004\n"
* + "my 0 0\n"
* + "an A \n"
* + "an B \n"
* + "an C \n"
* + "an D \n"
* + "an E \n"
* + "an F \n"
* + "ae AB A B weight:1 \n"
* + "ae AD A D weight:1 \n"
* + "ae BC B C weight:1 \n"
* + "ae CF C F weight:10 \n"
* + "ae DE D E weight:1 \n"
* + "ae EF E F weight:1 \n"
* ;
*
* public static void main(String[] args) throws IOException {
* Graph graph = new DefaultGraph("Bellman-Ford Test");
* StringReader reader = new StringReader(my_graph);
*
* FileSourceDGS source = new FileSourceDGS();
* source.addSink(graph);
* source.readAll(reader);
*
* BellmanFord bf = new BellmanFord("weight","A");
* bf.init(graph);
* bf.compute();
*
* System.out.println(bf.getShortestPath(graph.getNode("F")));
* }
* }
* </pre>
* <h3>Warning</h3>
* <p>
* This Implementation is only a stub. For the moment only attributes located on
* the edges are supported. If you need more features, consider using the
* Dijkstra implementation. If you really need that algorithm, please contact
* the team members through the mailing list.
* </p>
*
* @reference Bellman, Richard "On a routing problem", Quarterly of Applied
* Mathematics 16: 87–90. 1958.
*
* @complexity O(VxE) time, where V and E are the number of vertices and edges
* respectively.
*
* @author Antoine Dutot
* @author Yoann Pigné
*
*/ */
public class BellmanFord implements Algorithm { public class BellmanFord implements Algorithm {
...@@ -70,8 +132,16 @@ public class BellmanFord implements Algorithm { ...@@ -70,8 +132,16 @@ public class BellmanFord implements Algorithm {
/** /**
* ID of the source node. * ID of the source node.
*/ */
protected String source; protected String source_id;
protected Node source;
/**
* object-level unique string that identifies tags of this instance on a
* graph.
*/
protected String identifier;
/** /**
* Name of attribute used to get weight of edges. * Name of attribute used to get weight of edges.
*/ */
...@@ -97,8 +167,9 @@ public class BellmanFord implements Algorithm { ...@@ -97,8 +167,9 @@ public class BellmanFord implements Algorithm {
* @param sourceNode * @param sourceNode
* id of the source node * id of the source node
*/ */
public BellmanFord(String attribute, String sourceNode) { public BellmanFord(String attribute, String sourceNode) {
this.source = sourceNode; this.identifier = this.toString() + "/BellmanFord";
this.source_id = sourceNode;
this.weightAttribute = attribute; this.weightAttribute = attribute;
} }
...@@ -109,7 +180,10 @@ public class BellmanFord implements Algorithm { ...@@ -109,7 +180,10 @@ public class BellmanFord implements Algorithm {
* id of the source node * id of the source node
*/ */
public void setSource(String nodeId) { public void setSource(String nodeId) {
this.source = nodeId; if((source_id == null || ! source_id.equals(nodeId)) && graph!=null){
source = graph.getNode(nodeId);
}
this.source_id = nodeId;
} }
/** /**
...@@ -118,7 +192,7 @@ public class BellmanFord implements Algorithm { ...@@ -118,7 +192,7 @@ public class BellmanFord implements Algorithm {
* @return id of the source node * @return id of the source node
*/ */
public String getSource() { public String getSource() {
return source; return source_id;
} }
/** /**
...@@ -139,19 +213,19 @@ public class BellmanFord implements Algorithm { ...@@ -139,19 +213,19 @@ public class BellmanFord implements Algorithm {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void pathSetShortestPath_facilitate(Node current, Path path, private void pathSetShortestPath_facilitate(Node current, Path path,
List<Path> paths) { List<Path> paths) {
Node source = graph.getNode(this.source); Node source = graph.getNode(this.source_id);
if (current != source) { if (current != source) {
Node next = null; Node next = null;
ArrayList<? extends Edge> predecessors = (ArrayList<? extends Edge>) current ArrayList<? extends Edge> predecessors = (ArrayList<? extends Edge>) current
.getAttribute("BellmanFord.predecessors"); .getAttribute(identifier+".predecessors");
while (current != source && predecessors.size() == 1) { while (current != source && predecessors.size() == 1) {
Edge e = predecessors.get(0); Edge e = predecessors.get(0);
next = e.getOpposite(current); next = e.getOpposite(current);
path.add(current, e); path.add(current, e);
current = next; current = next;
predecessors = (ArrayList<? extends Edge>) current predecessors = (ArrayList<? extends Edge>) current
.getAttribute("BellmanFord.predecessors"); .getAttribute(identifier+".predecessors");
} }
if (current != source) { if (current != source) {
for (Edge e : predecessors) { for (Edge e : predecessors) {
...@@ -175,9 +249,91 @@ public class BellmanFord implements Algorithm { ...@@ -175,9 +249,91 @@ public class BellmanFord implements Algorithm {
* org.graphstream.algorithm.Algorithm#init(org.graphstream.graph.Graph) * org.graphstream.algorithm.Algorithm#init(org.graphstream.graph.Graph)
*/ */
public void init(Graph graph) { public void init(Graph graph) {
this.graph = graph; this.graph = graph;
} if (getSource() != null){
source = graph.getNode(getSource());
}
}
/**
* Set the unique identifier for this instance.
*
* @see #getIdentifier()
*
* @param identifier
* the unique identifier to set
*/
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
/**
* The unique identifier of this instance. Used to tag attributes in the graph.
* @return the unique identifier of this graph.
*/
public String getIdentifier() {
return this.identifier;
}
/**
* Returns the value of the shortest path between the source node and the
* given target according to the attribute specified in the constructor. If
* <code>target</code> is not in the same connected component as the source
* node, then the method returns <code>Double.POSITIVE_INFINITY</code>
* (Infinity).
*
* @param target
* The endpoint of the path to compute from the source node given
* in the constructor.
* @return A numerical value that represent the distance of the shortest
* path.
*/
public double getShortestPathValue(Node target) {
Double d = target.getAttribute(identifier+".distance");
if (d != null)
return d;
return Double.POSITIVE_INFINITY;
}
/**
* Returns the shortest path between the source node and one given target.
* If multiple shortest paths exist, one of them is returned at random.
*
* @param target
* the target of the shortest path starting at the source node
* given in the constructor.
* @return A {@link org.graphstream.graph.Path} object that constrains the
* list of nodes and edges that constitute it.
*/
@SuppressWarnings("unchecked")
public Path getShortestPath(Node target) {
Path p = new Path();
if (target == source ) {
return p;
}
boolean noPath = false;
Node v = target;
while (v != source && !noPath) {
ArrayList<? extends Edge> list = (ArrayList<? extends Edge>) v
.getAttribute(identifier+".predecessors");
if (list == null) {
noPath = true;
} else {
Edge parentEdge = list.get(0);
p.add(v, parentEdge);
v = parentEdge.getOpposite(v);
}
}
return p;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
...@@ -185,39 +341,41 @@ public class BellmanFord implements Algorithm { ...@@ -185,39 +341,41 @@ public class BellmanFord implements Algorithm {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void compute() { public void compute() {
Node source = graph.getNode(this.source); Node source = graph.getNode(this.source_id);
// Step 1: Initialize graph // Step 1: Initialize graph
for (Node n : graph) { for (Node n : graph) {
if (n == source) if (n == source)
n.addAttribute("BellmanFord.distance", 0.0); n.addAttribute(identifier+".distance", 0.0);
else else
n.addAttribute("BellmanFord.distance"); n.addAttribute(identifier+".distance", Double.POSITIVE_INFINITY);
n.addAttribute("BellmanFord.predecessors"); //n.addAttribute(identifier+".predecessors",(Object)null);
} }
// Step 2: relax edges repeatedly // Step 2: relax edges repeatedly
for (int i = 0; i < graph.getNodeCount(); i++) { for (int i = 0; i < graph.getNodeCount(); i++) {
for (Edge e : graph.getEachEdge()) { for (Edge e : graph.getEachEdge()) {
Node n0 = e.getNode0(); Node n0 = e.getNode0();
Node n1 = e.getNode1(); Node n1 = e.getNode1();
Double d0 = (Double) n0.getAttribute("BellmanFord.distance"); Double d0 = (Double) n0.getAttribute(identifier+".distance");
Double d1 = (Double) n1.getAttribute("BellmanFord.distance"); Double d1 = (Double) n1.getAttribute(identifier+".distance");
Double we = (Double) e.getAttribute(weightAttribute); Double we = (Double) e.getAttribute(weightAttribute);
if (we == null) if (we == null)
throw new NumberFormatException( throw new NumberFormatException(
"org.miv.graphstream.algorithm.BellmanFord: Problem with attribute \"" "org.graphstream.algorithm.BellmanFord: Problem with attribute \""
+ weightAttribute + "\" on edge " + e); + weightAttribute + "\" on edge " + e);
if (d0 != null) { if (d0 != null) {
if (d1 == null || d1 >= d0 + we) { if (d1 == null || d1 >= d0 + we) {
n1.addAttribute("BellmanFord.distance", d0 + we); n1.addAttribute(identifier+".distance", d0 + we);
ArrayList<Edge> predecessors = (ArrayList<Edge>) n1 ArrayList<Edge> predecessors = (ArrayList<Edge>) n1
.getAttribute("BellmanFord.predecessors"); .getAttribute(identifier+".predecessors");
if (d1 != null && d1 == d0 + we) { if (d1 != null && d1 == d0 + we) {
if (predecessors == null) { if (predecessors == null) {
...@@ -230,7 +388,7 @@ public class BellmanFord implements Algorithm { ...@@ -230,7 +388,7 @@ public class BellmanFord implements Algorithm {
predecessors.add(e); predecessors.add(e);
} }
n1.addAttribute("BellmanFord.predecessors", n1.addAttribute(identifier+".predecessors",
predecessors); predecessors);
} }
} }
...@@ -242,8 +400,8 @@ public class BellmanFord implements Algorithm { ...@@ -242,8 +400,8 @@ public class BellmanFord implements Algorithm {
for (Edge e : graph.getEachEdge()) { for (Edge e : graph.getEachEdge()) {
Node n0 = e.getNode0(); Node n0 = e.getNode0();
Node n1 = e.getNode1(); Node n1 = e.getNode1();
Double d0 = (Double) n0.getAttribute("BellmanFord.distance"); Double d0 = (Double) n0.getAttribute(identifier+".distance");
Double d1 = (Double) n1.getAttribute("BellmanFord.distance"); Double d1 = (Double) n1.getAttribute(identifier+".distance");
Double we = (Double) e.getAttribute(weightAttribute); Double we = (Double) e.getAttribute(weightAttribute);
......
...@@ -58,8 +58,10 @@ import org.graphstream.graph.Node; ...@@ -58,8 +58,10 @@ import org.graphstream.graph.Node;
* import java.io.StringReader; * import java.io.StringReader;
* import java.io.IOException; * import java.io.IOException;
* *
* import org.graphstream.algorithm.APSP;
* import org.graphstream.algorithm.Centroid; * import org.graphstream.algorithm.Centroid;
* import org.graphstream.graph.Graph; * import org.graphstream.graph.Graph;
* import org.graphstream.graph.Node;
* import org.graphstream.graph.implementations.DefaultGraph; * import org.graphstream.graph.implementations.DefaultGraph;
* import org.graphstream.stream.file.FileSourceDGS; * import org.graphstream.stream.file.FileSourceDGS;
* *
...@@ -110,7 +112,7 @@ import org.graphstream.graph.Node; ...@@ -110,7 +112,7 @@ import org.graphstream.graph.Node;
* </pre> * </pre>
* *
* @complexity O(n2) * @complexity O(n2)
* @see org.graphstream.algorithm.APSPAlgorithm.APSPInfo * @see org.graphstream.algorithm.APSP.APSPInfo
* @reference F. Harary, Graph Theory. Westview Press, Oct. 1969. [Online]. * @reference F. Harary, Graph Theory. Westview Press, Oct. 1969. [Online].
* Available: http://www.amazon.com/exec/obidos/ * Available: http://www.amazon.com/exec/obidos/
* redirect?tag=citeulike07-20\&path=ASIN/ 0201410338 * redirect?tag=citeulike07-20\&path=ASIN/ 0201410338
......
...@@ -110,7 +110,7 @@ import org.graphstream.graph.Node; ...@@ -110,7 +110,7 @@ import org.graphstream.graph.Node;
* </pre> * </pre>
* *
* @complexity O(n2) * @complexity O(n2)
* @see org.graphstream.algorithm.APSPAlgorithm.APSPInfo * @see org.graphstream.algorithm.APSP.APSPInfo
* @reference F. Harary, Graph Theory. Westview Press, Oct. 1969. [Online]. * @reference F. Harary, Graph Theory. Westview Press, Oct. 1969. [Online].
* Available: http://www.amazon.com/exec/obidos/ * Available: http://www.amazon.com/exec/obidos/
* redirect?tag=citeulike07-20\&path=ASIN/0201410338 * redirect?tag=citeulike07-20\&path=ASIN/0201410338
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment