Add Path, ShortestPath, etc. without implementation.

This commit is contained in:
Mikael Capelle
2018-03-13 14:09:40 +01:00
parent 251dbbb074
commit 2624681499
11 changed files with 803 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
package org.insa.algo.shortestpath;
public class AStarAlgorithm extends DijkstraAlgorithm {
public AStarAlgorithm(ShortestPathData data) {
super(data);
}
}

View File

@@ -0,0 +1,102 @@
package org.insa.algo.shortestpath;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import org.insa.algo.AbstractInputData;
import org.insa.algo.AbstractSolution.Status;
import org.insa.graph.Arc;
import org.insa.graph.Graph;
import org.insa.graph.Node;
import org.insa.graph.Path;
public class BellmanFordAlgorithm extends ShortestPathAlgorithm {
public BellmanFordAlgorithm(ShortestPathData data) {
super(data);
}
@Override
protected ShortestPathSolution doRun() {
// Retrieve the graph.
ShortestPathData data = getInputData();
Graph graph = data.getGraph();
final int nbNodes = graph.getNodes().size();
// Initialize array of distances.
double[] distances = new double[nbNodes];
Arrays.fill(distances, Double.POSITIVE_INFINITY);
distances[data.getOrigin().getId()] = 0;
// Notify observers about the first event (origin processed).
notifyOriginProcessed(data.getOrigin());
// Initialize array of predecessors.
Arc[] predecessorArcs = new Arc[nbNodes];
// Actual algorithm, we will assume the graph does not contain negative cycle...
boolean found = false;
for (int i = 0; !found && i < nbNodes; ++i) {
found = true;
for (Node node: graph.getNodes()) {
for (Arc arc: node.getSuccessors()) {
// Small test to check allowed roads...
if (!data.isAllowed(arc)) {
continue;
}
// Retrieve weight of the arc.
double w = data.getMode() == AbstractInputData.Mode.LENGTH ? arc.getLength()
: arc.getMinimumTravelTime();
double oldDistance = distances[arc.getDestination().getId()];
double newDistance = distances[node.getId()] + w;
if (Double.isInfinite(oldDistance) && Double.isFinite(newDistance)) {
notifyNodeReached(arc.getDestination());
}
// Check if new distances would be better, if so update...
if (newDistance < oldDistance) {
found = false;
distances[arc.getDestination().getId()] = distances[node.getId()] + w;
predecessorArcs[arc.getDestination().getId()] = arc;
}
}
}
}
ShortestPathSolution solution = null;
// Destination has no predecessor, the solution is infeasible...
if (predecessorArcs[data.getDestination().getId()] == null) {
solution = new ShortestPathSolution(data, Status.INFEASIBLE);
}
else {
// The destination has been found, notify the observers.
notifyDestinationReached(data.getDestination());
// Create the path from the array of predecessors...
ArrayList<Arc> arcs = new ArrayList<>();
Arc arc = predecessorArcs[data.getDestination().getId()];
while (arc != null) {
arcs.add(arc);
arc = predecessorArcs[arc.getOrigin().getId()];
}
// Reverse the path...
Collections.reverse(arcs);
// Create the final solution.
solution = new ShortestPathSolution(data, Status.OPTIMAL, new Path(graph, arcs));
}
return solution;
}
}

View File

@@ -0,0 +1,17 @@
package org.insa.algo.shortestpath;
public class DijkstraAlgorithm extends ShortestPathAlgorithm {
public DijkstraAlgorithm(ShortestPathData data) {
super(data);
}
@Override
protected ShortestPathSolution doRun() {
ShortestPathData data = getInputData();
ShortestPathSolution solution = null;
// TODO:
return solution;
}
}

View File

@@ -0,0 +1,69 @@
package org.insa.algo.shortestpath;
import org.insa.algo.AbstractAlgorithm;
import org.insa.graph.Node;
public abstract class ShortestPathAlgorithm extends AbstractAlgorithm<ShortestPathObserver> {
protected ShortestPathAlgorithm(ShortestPathData data) {
super(data);
}
@Override
public ShortestPathSolution run() {
return (ShortestPathSolution) super.run();
}
@Override
protected abstract ShortestPathSolution doRun();
@Override
public ShortestPathData getInputData() {
return (ShortestPathData) super.getInputData();
}
/**
* Notify all observers that the origin has been processed.
*
* @param node Origin.
*/
public void notifyOriginProcessed(Node node) {
for (ShortestPathObserver obs: getObservers()) {
obs.notifyOriginProcessed(node);
}
}
/**
* Notify all observers that a node has been reached for the first time.
*
* @param node Node that has been reached.
*/
public void notifyNodeReached(Node node) {
for (ShortestPathObserver obs: getObservers()) {
obs.notifyNodeReached(node);
}
}
/**
* Notify all observers that a node has been marked, i.e. its final value has
* been set.
*
* @param node Node that has been marked.
*/
public void notifyNodeMarked(Node node) {
for (ShortestPathObserver obs: getObservers()) {
obs.notifyNodeMarked(node);
}
}
/**
* Notify all observers that the destination has been reached.
*
* @param node Destination.
*/
public void notifyDestinationReached(Node node) {
for (ShortestPathObserver obs: getObservers()) {
obs.notifyDestinationReached(node);
}
}
}

View File

@@ -0,0 +1,63 @@
package org.insa.algo.shortestpath;
import org.insa.algo.AbstractInputData;
import org.insa.graph.Graph;
import org.insa.graph.Node;
public class ShortestPathData extends AbstractInputData {
// Origin and destination nodes.
private final Node origin, destination;
/**
* Construct a new instance of ShortestPathData with the given parameters and
* for which all arcs are allowed.
*
* @param graph Graph in which the path should be looked for.
* @param origin Origin node of the path.
* @param destination Destination node of the path.
* @param mode Cost mode for the path.
*/
public ShortestPathData(Graph graph, Node origin, Node destination, Mode mode) {
super(graph, mode);
this.origin = origin;
this.destination = destination;
}
/**
* Construct a new instance of ShortestPathInputData with the given parameters.
*
* @param graph Graph in which the path should be looked for.
* @param origin Origin node of the path.
* @param destination Destination node of the path.
* @param mode Cost mode for the path.
* @param arcFilter Filter for arcs (used to allow only a specific set of arcs
* in the graph to be used).
*/
public ShortestPathData(Graph graph, Node origin, Node destination, Mode mode,
AbstractInputData.ArcFilter arcFilter) {
super(graph, mode, arcFilter);
this.origin = origin;
this.destination = destination;
}
/**
* @return Origin node for the path.
*/
public Node getOrigin() {
return origin;
}
/**
* @return Destination node for the path.
*/
public Node getDestination() {
return destination;
}
@Override
public String toString() {
return "Shortest-path from #" + origin.getId() + " to #" + destination.getId() + " ["
+ getMode().toString().toLowerCase() + "]";
}
}

View File

@@ -0,0 +1,41 @@
package org.insa.algo.shortestpath;
import java.awt.Color;
import org.insa.graph.Node;
import org.insa.graphics.drawing.Drawing;
import org.insa.graphics.drawing.overlays.PointSetOverlay;
public class ShortestPathGraphicObserver implements ShortestPathObserver {
// Drawing and Graph drawing
protected Drawing drawing;
protected PointSetOverlay psOverlay1, psOverlay2;
public ShortestPathGraphicObserver(Drawing drawing) {
this.drawing = drawing;
psOverlay1 = drawing.createPointSetOverlay(1, Color.CYAN);
psOverlay2 = drawing.createPointSetOverlay(1, Color.BLUE);
}
@Override
public void notifyOriginProcessed(Node node) {
// drawing.drawMarker(node.getPoint(), Color.RED);
}
@Override
public void notifyNodeReached(Node node) {
psOverlay1.addPoint(node.getPoint());
}
@Override
public void notifyNodeMarked(Node node) {
psOverlay2.addPoint(node.getPoint());
}
@Override
public void notifyDestinationReached(Node node) {
// drawing.drawMarker(node.getPoint(), Color.RED);
}
}

View File

@@ -0,0 +1,37 @@
package org.insa.algo.shortestpath;
import org.insa.graph.Node;
public interface ShortestPathObserver {
/**
* Notify the observer that the origin has been processed.
*
* @param node Origin.
*/
public void notifyOriginProcessed(Node node);
/**
* Notify the observer that a node has been reached for the first
* time.
*
* @param node Node that has been reached.
*/
public void notifyNodeReached(Node node);
/**
* Notify the observer that a node has been marked, i.e. its final
* value has been set.
*
* @param node Node that has been marked.
*/
public void notifyNodeMarked(Node node);
/**
* Notify the observer that the destination has been reached.
*
* @param node Destination.
*/
public void notifyDestinationReached(Node node);
}

View File

@@ -0,0 +1,76 @@
package org.insa.algo.shortestpath;
import org.insa.algo.AbstractInputData;
import org.insa.algo.AbstractSolution;
import org.insa.graph.Path;
public class ShortestPathSolution extends AbstractSolution {
// Optimal solution.
private Path path;
/**
* {@inheritDoc}
*/
public ShortestPathSolution(ShortestPathData data) {
super(data);
}
/**
* Create a new infeasible shortest-path solution for the given input and
* status.
*
* @param data Original input data for this solution.
* @param status Status of the solution (UNKNOWN / INFEASIBLE).
*/
public ShortestPathSolution(ShortestPathData data, Status status) {
super(data, status);
}
/**
* Create a new shortest-path solution.
*
* @param data Original input data for this solution.
* @param status Status of the solution (FEASIBLE / OPTIMAL).
* @param path Path corresponding to the solution.
*/
public ShortestPathSolution(ShortestPathData data, Status status, Path path) {
super(data, status);
this.path = path;
}
@Override
public ShortestPathData getInputData() {
return (ShortestPathData) super.getInputData();
}
/**
* @return The path of this solution, if any.
*/
public Path getPath() {
return path;
}
@Override
public String toString() {
String info = null;
if (!isFeasible()) {
info = String.format("No path found from node #%d to node #%d",
getInputData().getOrigin().getId(), getInputData().getDestination().getId());
}
else {
info = String.format("Found a path from node #%d to node #%d",
getInputData().getOrigin().getId(), getInputData().getDestination().getId());
if (getInputData().getMode() == AbstractInputData.Mode.LENGTH) {
info = String.format("%s, %.4f kilometers", info, (getPath().getLength() / 1000.0));
}
else {
info = String.format("%s, %.4f minutes", info,
(getPath().getMinimumTravelTime() / 60.0));
}
}
info += " in " + getSolvingTime().getSeconds() + " seconds.";
return info;
}
}

View File

@@ -0,0 +1,37 @@
package org.insa.algo.shortestpath;
import java.io.PrintStream;
import org.insa.graph.Node;
public class ShortestPathTextObserver implements ShortestPathObserver {
private final PrintStream stream;
public ShortestPathTextObserver(PrintStream stream) {
this.stream = stream;
}
@Override
public void notifyOriginProcessed(Node node) {
// TODO Auto-generated method stub
}
@Override
public void notifyNodeReached(Node node) {
stream.println("Node " + node.getId() + " reached.");
}
@Override
public void notifyNodeMarked(Node node) {
stream.println("Node " + node.getId() + " marked.");
}
@Override
public void notifyDestinationReached(Node node) {
// TODO Auto-generated method stub
}
}