Add Path, ShortestPath, etc. without implementation.
This commit is contained in:
		
							
								
								
									
										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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user