New updates.

This commit is contained in:
Holt59
2018-03-25 14:35:15 +02:00
parent 5b733e25c7
commit aab8743d3c
24 changed files with 893 additions and 388 deletions

View File

@@ -2,6 +2,7 @@ package org.insa.algo;
import org.insa.graph.Arc;
import org.insa.graph.Graph;
import org.insa.graph.GraphStatistics;
/**
* Base class for algorithm input data classes. This class contains the basic
@@ -12,77 +13,29 @@ import org.insa.graph.Graph;
public abstract class AbstractInputData {
/**
* Mode for computing costs on the arc (time or length).
*
* Enum specifying the top mode of the algorithms.
*
* @see ArcInspector
*/
public enum Mode {
TIME, LENGTH
}
/**
* Filtering interface for arcs - This class can be used to indicate to an
* algorithm which arc can be used.
*
*/
public interface ArcFilter {
/**
* Check if the given arc can be used (is allowed).
*
* @param arc Arc to check.
*
* @return true if the given arc is allowed.
*/
public boolean isAllowed(Arc arc);
}
// Graph
private final Graph graph;
// Mode for the computation of the costs.
private final Mode mode;
// Arc filter.
private final ArcFilter arcFilter;
protected final ArcInspector arcInspector;
/**
* Create a new AbstractInputData instance for the given graph, mode and filter.
*
* @param graph
* @parma mode
* @param arcFilter
* @param graph Graph for this input data.
* @param arcInspector Arc inspector for this input data.
*/
protected AbstractInputData(Graph graph, Mode mode, ArcFilter arcFilter) {
protected AbstractInputData(Graph graph, ArcInspector arcInspector) {
this.graph = graph;
this.mode = mode;
this.arcFilter = arcFilter;
}
/**
* Create a new AbstractInputData instance for the given graph and mode, with no
* filtering on the arc.
*
* @param graph
* @param mode
*/
protected AbstractInputData(Graph graph, Mode mode) {
this(graph, mode, new AbstractInputData.ArcFilter() {
@Override
public boolean isAllowed(Arc arc) {
return true;
}
});
}
/**
* Create a new AbstractInputData instance for the given graph, with default
* mode (LENGHT), with no filtering on the arc.
*
* @param graph
*/
protected AbstractInputData(Graph graph) {
this(graph, Mode.LENGTH);
this.arcInspector = arcInspector;
}
/**
@@ -93,12 +46,39 @@ public abstract class AbstractInputData {
}
/**
* @return Mode of the algorithm (time or length).
* Retrieve the cost associated with the given arc according to the underlying
* arc inspector.
*
* @param arc Arc for which cost should be retrieved.
*
* @return Cost for the given arc.
*
* @see ArcInspector
*/
public double getCost(Arc arc) {
return this.arcInspector.getCost(arc);
}
/**
* @return Mode associated with this input data.
*
* @see Mode
*/
public Mode getMode() {
return mode;
return this.arcInspector.getMode();
}
/**
* Retrieve the maximum speed associated with this input data, or
* {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is associated. The maximum
* speed associated with input data is different from the maximum speed
* associated with graph (accessible via {@link Graph#getGraphInformation()}).
*
* @return The maximum speed for this inspector, or
* {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is set.
*/
public int getMaximumSpeed() {
return this.arcInspector.getMaximumSpeed();
}
/**
@@ -108,10 +88,10 @@ public abstract class AbstractInputData {
*
* @return true if the given arc is allowed.
*
* @see ArcFilter
* @see ArcInspector
*/
public boolean isAllowed(Arc arc) {
return this.arcFilter.isAllowed(arc);
return this.arcInspector.isAllowed(arc);
}
}

View File

@@ -1,71 +0,0 @@
package org.insa.algo;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import org.insa.algo.AbstractInputData.ArcFilter;
import org.insa.graph.AccessRestrictions.AccessMode;
import org.insa.graph.AccessRestrictions.AccessRestriction;
import org.insa.graph.Arc;
public class ArcFilterFactory {
/**
* @return List of all arc filters in this factory.
*/
public static List<ArcFilter> getAllFilters() {
List<ArcFilter> filters = new ArrayList<>();
// Common filters:
// 1. No filter (all arcs allowed):
filters.add(new ArcFilter() {
@Override
public boolean isAllowed(Arc arc) {
return true;
}
@Override
public String toString() {
return "All roads are allowed.";
}
});
// 2. Only road allowed for cars:
filters.add(new ArcFilter() {
@Override
public boolean isAllowed(Arc arc) {
return arc.getRoadInformation().getAccessRestrictions()
.isAllowedForAny(AccessMode.MOTORCAR, EnumSet.complementOf(EnumSet
.of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
}
@Override
public String toString() {
return "Only roads open for cars.";
}
});
// 3. Non-private roads for pedestrian and bicycle:
filters.add(new ArcFilter() {
@Override
public boolean isAllowed(Arc arc) {
return arc.getRoadInformation().getAccessRestrictions()
.isAllowedForAny(AccessMode.FOOT, EnumSet.complementOf(EnumSet
.of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
}
@Override
public String toString() {
return "Non-private roads for pedestrian.";
}
});
// 3. Add your own filters here (do not forget to implement toString() to get an
// understandable output!):
return filters;
}
}

View File

@@ -0,0 +1,43 @@
package org.insa.algo;
import org.insa.algo.AbstractInputData.Mode;
import org.insa.graph.Arc;
import org.insa.graph.GraphStatistics;
/**
* This class can be used to indicate to an algorithm which arcs can be used and
* the costs of the usable arcs..
*
*/
public interface ArcInspector {
/**
* Check if the given arc can be used (is allowed).
*
* @param arc Arc to check.
*
* @return true if the given arc is allowed.
*/
public boolean isAllowed(Arc arc);
/**
* Find the cost of the given arc.
*
* @param arc Arc for which the cost should be returned.
*
* @return Cost of the arc.
*/
public double getCost(Arc arc);
/**
* @return The maximum speed for this inspector, or
* {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is set.
*/
public int getMaximumSpeed();
/**
* @return Mode for this arc inspector.
*/
public Mode getMode();
}

View File

@@ -0,0 +1,149 @@
package org.insa.algo;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import org.insa.algo.AbstractInputData.Mode;
import org.insa.graph.AccessRestrictions.AccessMode;
import org.insa.graph.AccessRestrictions.AccessRestriction;
import org.insa.graph.Arc;
import org.insa.graph.GraphStatistics;
public class ArcInspectorFactory {
/**
* @return List of all arc filters in this factory.
*/
public static List<ArcInspector> getAllFilters() {
List<ArcInspector> filters = new ArrayList<>();
// Common filters:
// No filter (all arcs allowed):
filters.add(new ArcInspector() {
@Override
public boolean isAllowed(Arc arc) {
return true;
}
@Override
public double getCost(Arc arc) {
return arc.getLength();
}
@Override
public int getMaximumSpeed() {
return GraphStatistics.NO_MAXIMUM_SPEED;
}
@Override
public Mode getMode() {
return Mode.LENGTH;
}
@Override
public String toString() {
return "Shortest path, all roads allowed";
}
});
// Only road allowed for cars and length:
filters.add(new ArcInspector() {
@Override
public boolean isAllowed(Arc arc) {
return arc.getRoadInformation().getAccessRestrictions()
.isAllowedForAny(AccessMode.MOTORCAR, EnumSet.complementOf(EnumSet
.of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
}
@Override
public double getCost(Arc arc) {
return arc.getLength();
}
@Override
public int getMaximumSpeed() {
return GraphStatistics.NO_MAXIMUM_SPEED;
}
@Override
public Mode getMode() {
return Mode.LENGTH;
}
@Override
public String toString() {
return "Shortest path, only roads open for cars";
}
});
// Only road allowed for cars and time:
filters.add(new ArcInspector() {
@Override
public boolean isAllowed(Arc arc) {
return arc.getRoadInformation().getAccessRestrictions()
.isAllowedForAny(AccessMode.MOTORCAR, EnumSet.complementOf(EnumSet
.of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
}
@Override
public double getCost(Arc arc) {
return arc.getMinimumTravelTime();
}
@Override
public int getMaximumSpeed() {
return GraphStatistics.NO_MAXIMUM_SPEED;
}
@Override
public Mode getMode() {
return Mode.TIME;
}
@Override
public String toString() {
return "Fastest path, only roads open for cars";
}
});
// Non-private roads for pedestrian and bicycle:
filters.add(new ArcInspector() {
@Override
public boolean isAllowed(Arc arc) {
return arc.getRoadInformation().getAccessRestrictions()
.isAllowedForAny(AccessMode.FOOT, EnumSet.complementOf(EnumSet
.of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
}
@Override
public double getCost(Arc arc) {
return arc.getTravelTime(
Math.min(getMaximumSpeed(), arc.getRoadInformation().getMaximumSpeed()));
}
@Override
public String toString() {
return "Fastest path for pedestrian";
}
@Override
public int getMaximumSpeed() {
return 5;
}
@Override
public Mode getMode() {
return Mode.TIME;
}
});
// Add your own filters here (do not forget to implement toString()
// to get an understandable output!):
return filters;
}
}

View File

@@ -1,12 +1,13 @@
package org.insa.algo.carpooling;
import org.insa.algo.AbstractInputData;
import org.insa.algo.ArcInspector;
import org.insa.graph.Graph;
public class CarPoolingData extends AbstractInputData {
protected CarPoolingData(Graph graph, Mode mode, ArcFilter arcFilter) {
super(graph, mode, arcFilter);
protected CarPoolingData(Graph graph, ArcInspector arcFilter) {
super(graph, arcFilter);
}
}

View File

@@ -1,12 +1,13 @@
package org.insa.algo.packageswitch;
import org.insa.algo.AbstractInputData;
import org.insa.algo.ArcInspector;
import org.insa.graph.Graph;
public class PackageSwitchData extends AbstractInputData {
protected PackageSwitchData(Graph graph, Mode mode, ArcFilter arcFilter) {
super(graph, mode, arcFilter);
protected PackageSwitchData(Graph graph, ArcInspector arcFilter) {
super(graph, arcFilter);
}
}

View File

@@ -4,7 +4,6 @@ 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;
@@ -13,90 +12,88 @@ import org.insa.graph.Path;
public class BellmanFordAlgorithm extends ShortestPathAlgorithm {
public BellmanFordAlgorithm(ShortestPathData data) {
super(data);
}
public BellmanFordAlgorithm(ShortestPathData data) {
super(data);
}
@Override
protected ShortestPathSolution doRun() {
@Override
protected ShortestPathSolution doRun() {
// Retrieve the graph.
ShortestPathData data = getInputData();
Graph graph = data.getGraph();
// Retrieve the graph.
ShortestPathData data = getInputData();
Graph graph = data.getGraph();
final int nbNodes = graph.size();
final int nbNodes = graph.size();
// Initialize array of distances.
double[] distances = new double[nbNodes];
Arrays.fill(distances, Double.POSITIVE_INFINITY);
distances[data.getOrigin().getId()] = 0;
// 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());
// Notify observers about the first event (origin processed).
notifyOriginProcessed(data.getOrigin());
// Initialize array of predecessors.
Arc[] predecessorArcs = new Arc[nbNodes];
// 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) {
for (Arc arc: node) {
// 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) {
for (Arc arc : node) {
// Small test to check allowed roads...
if (!data.isAllowed(arc)) {
continue;
}
// 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();
// Retrieve weight of the arc.
double w = data.getCost(arc);
double oldDistance = distances[arc.getDestination().getId()];
double newDistance = distances[node.getId()] + w;
double oldDistance = distances[arc.getDestination().getId()];
double newDistance = distances[node.getId()] + w;
if (Double.isInfinite(oldDistance) && Double.isFinite(newDistance)) {
notifyNodeReached(arc.getDestination());
}
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;
}
}
}
}
// 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;
ShortestPathSolution solution = null;
// Destination has no predecessor, the solution is infeasible...
if (predecessorArcs[data.getDestination().getId()] == null) {
solution = new ShortestPathSolution(data, Status.INFEASIBLE);
} else {
// 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());
// 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()];
}
// 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);
// Reverse the path...
Collections.reverse(arcs);
// Create the final solution.
solution = new ShortestPathSolution(data, Status.OPTIMAL, new Path(graph, arcs));
}
// Create the final solution.
solution = new ShortestPathSolution(data, Status.OPTIMAL, new Path(graph, arcs));
}
return solution;
}
return solution;
}
}

View File

@@ -1,6 +1,7 @@
package org.insa.algo.shortestpath;
import org.insa.algo.AbstractInputData;
import org.insa.algo.ArcInspector;
import org.insa.graph.Graph;
import org.insa.graph.Node;
@@ -9,34 +10,17 @@ 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).
* @param arcInspector 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);
public ShortestPathData(Graph graph, Node origin, Node destination, ArcInspector arcInspector) {
super(graph, arcInspector);
this.origin = origin;
this.destination = destination;
}
@@ -58,6 +42,6 @@ public class ShortestPathData extends AbstractInputData {
@Override
public String toString() {
return "Shortest-path from #" + origin.getId() + " to #" + destination.getId() + " ["
+ getMode().toString().toLowerCase() + "]";
+ this.arcInspector.toString().toLowerCase() + "]";
}
}

View File

@@ -1,7 +1,8 @@
package org.insa.algo.shortestpath;
import org.insa.algo.AbstractInputData;
import org.insa.algo.AbstractInputData.Mode;
import org.insa.algo.AbstractSolution;
import org.insa.graph.Arc;
import org.insa.graph.Path;
public class ShortestPathSolution extends AbstractSolution {
@@ -59,14 +60,17 @@ public class ShortestPathSolution extends AbstractSolution {
getInputData().getOrigin().getId(), getInputData().getDestination().getId());
}
else {
double cost = 0;
for (Arc arc: getPath().getArcs()) {
cost += getInputData().getCost(arc);
}
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));
if (getInputData().getMode() == Mode.LENGTH) {
info = String.format("%s, %.4f kilometers", info, cost / 1000.0);
}
else {
info = String.format("%s, %.4f minutes", info,
(getPath().getMinimumTravelTime() / 60.0));
info = String.format("%s, %.4f minutes", info, cost / 60.0);
}
}
info += " in " + getSolvingTime().getSeconds() + " seconds.";

View File

@@ -18,14 +18,13 @@ import java.util.ArrayList;
* @author Mark Allen Weiss
* @author DLB
*/
public class BinaryHeap<E extends Comparable<E>> {
public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
// Number of elements in heap.
private int currentSize;
// The heap array. Java genericity does not work with arrays so we have to use
// an ArrayList.
private ArrayList<E> array;
// The heap array.
private final ArrayList<E> array;
/**
* Construct a new empty binary heap.
@@ -126,62 +125,37 @@ public class BinaryHeap<E extends Comparable<E>> {
}
}
/**
* @return true if the heap is empty, false otherwise.
*/
@Override
public boolean isEmpty() {
return this.currentSize == 0;
}
/**
* @return Current size (number of elements) of this heap.
*/
@Override
public int size() {
return this.currentSize;
}
/**
* Insert the given element into the heap.
*
* @param x Item to insert.
*/
public void add(E x) {
@Override
public void insert(E x) {
int index = this.currentSize++;
this.arraySet(index, x);
this.percolateUp(index);
}
/**
* Tell the binary heap that the given element has been modified and should be
* re-positioned inside the heap.
*
* @param x Item to update.
*/
public void update(E x) {
@Override
public void remove(E x) throws ElementNotFoundException {
// TODO:
}
/**
* Find the smallest item in the heap.
*
* @return The smallest item in the heap.
*
* @throws RuntimeException if this heap is empty.
*/
public E findMin() throws RuntimeException {
@Override
public E findMin() throws EmptyPriorityQueueException {
if (isEmpty())
throw new RuntimeException("Empty binary heap.");
return this.array.get(0);
}
/**
* Remove the smallest item from the heap.
*
* @return The smallest item in the heap.
*
* @throws RuntimeException if this heap is empty.
*/
public E deleteMin() throws RuntimeException {
@Override
public E deleteMin() throws EmptyPriorityQueueException {
E minItem = findMin();
E lastItem = this.array.get(--this.currentSize);
this.arraySet(0, lastItem);

View File

@@ -0,0 +1,64 @@
package org.insa.algo.utils;
import java.util.SortedSet;
import java.util.TreeSet;
public class BinarySearchTree<E extends Comparable<E>> implements PriorityQueue<E> {
// Underlying implementation
private final SortedSet<E> sortedSet;
/**
* Create a new empty binary search tree.
*/
public BinarySearchTree() {
this.sortedSet = new TreeSet<>();
}
/**
* Create a copy of the given binary search tree.
*
* @param bst Binary search tree to copy.
*/
public BinarySearchTree(BinarySearchTree<E> bst) {
this.sortedSet = new TreeSet<>(bst.sortedSet);
}
@Override
public boolean isEmpty() {
return sortedSet.isEmpty();
}
@Override
public int size() {
return sortedSet.size();
}
@Override
public void insert(E x) {
sortedSet.add(x);
}
@Override
public void remove(E x) throws ElementNotFoundException {
if (!sortedSet.remove(x)) {
throw new ElementNotFoundException(x);
}
}
@Override
public E findMin() throws EmptyPriorityQueueException {
if (isEmpty()) {
throw new EmptyPriorityQueueException();
}
return sortedSet.first();
}
@Override
public E deleteMin() throws EmptyPriorityQueueException {
E min = findMin();
remove(min);
return min;
}
}

View File

@@ -0,0 +1,32 @@
package org.insa.algo.utils;
public class ElementNotFoundException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
// Element not found
private final Object element;
/**
* @param element Element that was not found.
*/
public ElementNotFoundException(Object element) {
this.element = element;
}
/**
* @return The element that was not found.
*/
public Object getElement() {
return this.element;
}
@Override
public String toString() {
return "element not found: " + element;
}
}

View File

@@ -0,0 +1,16 @@
package org.insa.algo.utils;
public class EmptyPriorityQueueException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
*
*/
public EmptyPriorityQueueException() {
}
}

View File

@@ -0,0 +1,54 @@
package org.insa.algo.utils;
/**
* Interface representing a basic priority queue.
*
* @see https://en.wikipedia.org/wiki/Priority_queue
*/
public interface PriorityQueue<E extends Comparable<E>> {
/**
* Check if the priority queue is empty.
*
* @return true if the queue is empty, false otherwise.
*/
public boolean isEmpty();
/**
* @return Current size (number of elements) of this queue.
*/
public int size();
/**
* Insert the given element into the queue.
*
* @param x Item to insert.
*/
public void insert(E x);
/**
* Remove the given element from the priority queue.
*
* @param x Item to remove.
*/
public void remove(E x) throws ElementNotFoundException;
/**
* Retrieve (but not remove) the smallest item in the queue.
*
* @return The smallest item in the queue.
*
* @throws EmptyPriorityQueueException if this queue is empty.
*/
public E findMin() throws EmptyPriorityQueueException;
/**
* Remove and return the smallest item from the priority queue.
*
* @return The smallest item in the queue.
*
* @throws EmptyPriorityQueueException if this queue is empty.
*/
public E deleteMin() throws EmptyPriorityQueueException;
}

View File

@@ -9,7 +9,7 @@ public class WeaklyConnectedComponentsData extends AbstractInputData {
* @param graph Graph for which components should be retrieved.
*/
public WeaklyConnectedComponentsData(Graph graph) {
super(graph);
super(graph, null);
}
@Override