Add Path, ShortestPath, etc. without implementation.
This commit is contained in:
parent
251dbbb074
commit
2624681499
128
src/main/org/insa/algo/AlgorithmFactory.java
Normal file
128
src/main/org/insa/algo/AlgorithmFactory.java
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package org.insa.algo;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import org.insa.algo.shortestpath.AStarAlgorithm;
|
||||||
|
import org.insa.algo.shortestpath.BellmanFordAlgorithm;
|
||||||
|
import org.insa.algo.shortestpath.DijkstraAlgorithm;
|
||||||
|
import org.insa.algo.shortestpath.ShortestPathAlgorithm;
|
||||||
|
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class used to register and retrieve algorithms based on their common
|
||||||
|
* ancestor and name.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AlgorithmFactory {
|
||||||
|
|
||||||
|
// Map between algorithm names and class.
|
||||||
|
private final static Map<Class<? extends AbstractAlgorithm<?>>, Map<String, Class<? extends AbstractAlgorithm<?>>>> ALGORITHMS = new IdentityHashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Register weakly-connected components algorithm:
|
||||||
|
registerAlgorithm(WeaklyConnectedComponentsAlgorithm.class, "WCC basic",
|
||||||
|
WeaklyConnectedComponentsAlgorithm.class);
|
||||||
|
|
||||||
|
// Register shortest path algorithm:
|
||||||
|
registerAlgorithm(ShortestPathAlgorithm.class, "Bellman-Ford", BellmanFordAlgorithm.class);
|
||||||
|
registerAlgorithm(ShortestPathAlgorithm.class, "Dijkstra", DijkstraAlgorithm.class);
|
||||||
|
registerAlgorithm(ShortestPathAlgorithm.class, "A*", AStarAlgorithm.class);
|
||||||
|
|
||||||
|
// Register your algorithms here:
|
||||||
|
// registerAlgorithm(CarPoolingAlgorithm.class, "My Awesome Algorithm",
|
||||||
|
// MyCarPoolingAlgorithm.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the given algorithm class with the given name as a child class of
|
||||||
|
* the given base algorithm.
|
||||||
|
*
|
||||||
|
* @param baseAlgorithm Base algorithm class that corresponds to the newly
|
||||||
|
* registered algorithm class (e.g., generic algorithm class for the
|
||||||
|
* problem).
|
||||||
|
* @param name Name for the registered algorithm class.
|
||||||
|
* @param algoClass Algorithm class to register.
|
||||||
|
*/
|
||||||
|
public static void registerAlgorithm(Class<? extends AbstractAlgorithm<?>> baseAlgorithm,
|
||||||
|
String name, Class<? extends AbstractAlgorithm<?>> algoClass) {
|
||||||
|
if (!ALGORITHMS.containsKey(baseAlgorithm)) {
|
||||||
|
ALGORITHMS.put(baseAlgorithm, new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
ALGORITHMS.get(baseAlgorithm).put(name, algoClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of the given algorithm class using the given input data.
|
||||||
|
* Assuming algorithm correspond to a class "Algorithm", this function returns
|
||||||
|
* an object equivalent to `new Algorithm(data)`.
|
||||||
|
*
|
||||||
|
* @param algorithm Class of the algorithm to create.
|
||||||
|
* @param data Input data for the algorithm.
|
||||||
|
*
|
||||||
|
* @return A new instance of the given algorithm class using the given data.
|
||||||
|
*
|
||||||
|
* @throws Exception if something wrong happens when constructing the object,
|
||||||
|
* i.e. the given input data does not correspond to the given algorithm
|
||||||
|
* and/or no constructor that takes a single parameter of type
|
||||||
|
* (data.getClass()) exists.
|
||||||
|
*/
|
||||||
|
public static AbstractAlgorithm<?> createAlgorithm(
|
||||||
|
Class<? extends AbstractAlgorithm<?>> algorithm, AbstractInputData data)
|
||||||
|
throws Exception {
|
||||||
|
// Retrieve the set of constructors for the given algorithm class.
|
||||||
|
Constructor<?>[] constructors = algorithm.getDeclaredConstructors();
|
||||||
|
|
||||||
|
// Within this set, find the constructor that can be called with "data" (only).
|
||||||
|
AbstractAlgorithm<?> constructed = null;
|
||||||
|
for (Constructor<?> c: constructors) {
|
||||||
|
Class<?>[] params = c.getParameterTypes();
|
||||||
|
if (params.length == 1 && params[0].isAssignableFrom(data.getClass())) {
|
||||||
|
c.setAccessible(true);
|
||||||
|
constructed = (AbstractAlgorithm<?>) c.newInstance(new Object[]{ data });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return constructed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the algorithm class corresponding to the given base algorithm class
|
||||||
|
* and name. The algorithm must have been previously registered using
|
||||||
|
* registerAlgorithm.
|
||||||
|
*
|
||||||
|
* @param baseAlgorithm Base algorithm class for the algorithm to retrieve.
|
||||||
|
* @param name Name of the algorithm to retrieve.
|
||||||
|
*
|
||||||
|
* @return Class corresponding to the given name.
|
||||||
|
*
|
||||||
|
* @see #registerAlgorithm
|
||||||
|
*/
|
||||||
|
public static Class<? extends AbstractAlgorithm<?>> getAlgorithmClass(
|
||||||
|
Class<? extends AbstractAlgorithm<?>> baseAlgorithm, String name) {
|
||||||
|
return ALGORITHMS.get(baseAlgorithm).get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of names corresponding to the registered algorithm classes
|
||||||
|
* for the given base algorithm class.
|
||||||
|
*
|
||||||
|
* @param baseAlgorithm Base algorithm class for the algorithm class names to
|
||||||
|
* retrieve.
|
||||||
|
*
|
||||||
|
* @return Names of the currently registered algorithms.
|
||||||
|
*
|
||||||
|
* @see #registerAlgorithm
|
||||||
|
*/
|
||||||
|
public static Set<String> getAlgorithmNames(
|
||||||
|
Class<? extends AbstractAlgorithm<?>> baseAlgorithm) {
|
||||||
|
if (!ALGORITHMS.containsKey(baseAlgorithm)) {
|
||||||
|
return new TreeSet<>();
|
||||||
|
}
|
||||||
|
return ALGORITHMS.get(baseAlgorithm).keySet();
|
||||||
|
}
|
||||||
|
}
|
9
src/main/org/insa/algo/shortestpath/AStarAlgorithm.java
Normal file
9
src/main/org/insa/algo/shortestpath/AStarAlgorithm.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package org.insa.algo.shortestpath;
|
||||||
|
|
||||||
|
public class AStarAlgorithm extends DijkstraAlgorithm {
|
||||||
|
|
||||||
|
public AStarAlgorithm(ShortestPathData data) {
|
||||||
|
super(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
102
src/main/org/insa/algo/shortestpath/BellmanFordAlgorithm.java
Normal file
102
src/main/org/insa/algo/shortestpath/BellmanFordAlgorithm.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
src/main/org/insa/algo/shortestpath/DijkstraAlgorithm.java
Normal file
17
src/main/org/insa/algo/shortestpath/DijkstraAlgorithm.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
src/main/org/insa/algo/shortestpath/ShortestPathData.java
Normal file
63
src/main/org/insa/algo/shortestpath/ShortestPathData.java
Normal 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() + "]";
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
224
src/main/org/insa/graph/Path.java
Normal file
224
src/main/org/insa/graph/Path.java
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
package org.insa.graph;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representing a path between nodes in a graph.
|
||||||
|
*
|
||||||
|
* A path is represented as a list of {@link Arc} and not a list of {@link Node}
|
||||||
|
* due to the multigraph nature of the considered graphs.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Path {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new path that goes through the given list of nodes (in order),
|
||||||
|
* choosing the fastest route if multiple are available.
|
||||||
|
*
|
||||||
|
* @param graph Graph containing the nodes in the list.
|
||||||
|
* @param nodes List of nodes to build the path.
|
||||||
|
*
|
||||||
|
* @return A path that goes through the given list of nodes.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException If the list of nodes is not valid, i.e. two
|
||||||
|
* consecutive nodes in the list are not connected in the graph.
|
||||||
|
*
|
||||||
|
* @deprecated Need to be implement.
|
||||||
|
*/
|
||||||
|
public static Path createFastestPathFromNodes(Graph graph, List<Node> nodes)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
List<Arc> arcs = new ArrayList<Arc>();
|
||||||
|
// TODO:
|
||||||
|
return new Path(graph, arcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new path that goes through the given list of nodes (in order),
|
||||||
|
* choosing the shortest route if multiple are available.
|
||||||
|
*
|
||||||
|
* @param graph Graph containing the nodes in the list.
|
||||||
|
* @param nodes List of nodes to build the path.
|
||||||
|
*
|
||||||
|
* @return A path that goes through the given list of nodes.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException If the list of nodes is not valid, i.e. two
|
||||||
|
* consecutive nodes in the list are not connected in the graph.
|
||||||
|
*
|
||||||
|
* @deprecated Need to be implement.
|
||||||
|
*/
|
||||||
|
public static Path createShortestPathFromNodes(Graph graph, List<Node> nodes)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
List<Arc> arcs = new ArrayList<Arc>();
|
||||||
|
// TODO:
|
||||||
|
return new Path(graph, arcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenate the given paths.
|
||||||
|
*
|
||||||
|
* @param paths Array of paths to concatenate.
|
||||||
|
*
|
||||||
|
* @return Concatenated path.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if the paths cannot be concatenated (IDs of
|
||||||
|
* map do not match, or the end of a path is not the beginning of the
|
||||||
|
* next).
|
||||||
|
*/
|
||||||
|
public static Path concatenate(Path... paths) throws IllegalArgumentException {
|
||||||
|
if (paths.length == 0) {
|
||||||
|
throw new IllegalArgumentException("Cannot concatenate an empty list of paths.");
|
||||||
|
}
|
||||||
|
final String mapId = paths[0].getGraph().getMapId();
|
||||||
|
for (int i = 1; i < paths.length; ++i) {
|
||||||
|
if (!paths[i].getGraph().getMapId().equals(mapId)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Cannot concatenate paths from different graphs.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ArrayList<Arc> arcs = new ArrayList<>();
|
||||||
|
for (Path path: paths) {
|
||||||
|
arcs.addAll(path.getArcs());
|
||||||
|
}
|
||||||
|
Path path = new Path(paths[0].getGraph(), arcs);
|
||||||
|
if (!path.isValid()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Cannot concatenate paths that do not form a single path.");
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graph containing this path.
|
||||||
|
private final Graph graph;
|
||||||
|
|
||||||
|
// Origin of the path
|
||||||
|
private final Node origin;
|
||||||
|
|
||||||
|
// List of arcs in this path.
|
||||||
|
private final List<Arc> arcs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an empty path corresponding to the given graph.
|
||||||
|
*
|
||||||
|
* @param graph Graph containing the path.
|
||||||
|
*/
|
||||||
|
public Path(Graph graph) {
|
||||||
|
this.graph = graph;
|
||||||
|
this.origin = null;
|
||||||
|
this.arcs = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new path containing a single node.
|
||||||
|
*
|
||||||
|
* @param graph Graph containing the path.
|
||||||
|
* @param node Single node of the path.
|
||||||
|
*/
|
||||||
|
public Path(Graph graph, Node node) {
|
||||||
|
this.graph = graph;
|
||||||
|
this.origin = node;
|
||||||
|
this.arcs = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new path with the given list of arcs.
|
||||||
|
*
|
||||||
|
* @param graph Graph containing the path.
|
||||||
|
* @param arcs Arcs to construct the path.
|
||||||
|
*/
|
||||||
|
public Path(Graph graph, List<Arc> arcs) {
|
||||||
|
this.graph = graph;
|
||||||
|
this.arcs = arcs;
|
||||||
|
this.origin = arcs.size() > 0 ? arcs.get(0).getOrigin() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Graph containing the path.
|
||||||
|
*/
|
||||||
|
public Graph getGraph() {
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return First node of the path.
|
||||||
|
*/
|
||||||
|
public Node getOrigin() {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Last node of the path.
|
||||||
|
*/
|
||||||
|
public Node getDestination() {
|
||||||
|
return arcs.get(arcs.size() - 1).getDestination();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of arcs in the path.
|
||||||
|
*/
|
||||||
|
public List<Arc> getArcs() {
|
||||||
|
return Collections.unmodifiableList(arcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this path is empty (it does not contain any node).
|
||||||
|
*
|
||||||
|
* @return true if this path is empty, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return arcs.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this path is valid.
|
||||||
|
*
|
||||||
|
* A path is valid if it is empty, contains a single node (without arcs) or if
|
||||||
|
* the first arc has for origin the origin of the path and, for two consecutive
|
||||||
|
* arcs, the destination of the first one is the origin of the second one.
|
||||||
|
*
|
||||||
|
* @return true if the path is valid, false otherwise.
|
||||||
|
*
|
||||||
|
* @deprecated Need to be implement.
|
||||||
|
*/
|
||||||
|
public boolean isValid() {
|
||||||
|
// TODO:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Total length of the path.
|
||||||
|
*
|
||||||
|
* @deprecated Need to be implement.
|
||||||
|
*/
|
||||||
|
public float getLength() {
|
||||||
|
// TODO:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the time required to travel this path if moving at the given speed.
|
||||||
|
*
|
||||||
|
* @param speed Speed to compute the travel time.
|
||||||
|
*
|
||||||
|
* @return Time (in seconds) required to travel this path at the given speed (in
|
||||||
|
* kilometers-per-hour).
|
||||||
|
*
|
||||||
|
* @deprecated Need to be implement.
|
||||||
|
*/
|
||||||
|
public double getTravelTime(double speed) {
|
||||||
|
// TODO:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Minimum travel time of the in seconds (assuming maximum speed).
|
||||||
|
*
|
||||||
|
* @deprecated Need to be implement.
|
||||||
|
*/
|
||||||
|
public double getMinimumTravelTime() {
|
||||||
|
// TODO:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user