This commit is contained in:
Mikael Capelle
2018-02-16 15:29:11 +01:00
parent 65c81b9921
commit cfb59ac0f1
37 changed files with 1511 additions and 473 deletions

View File

@@ -1,22 +1,40 @@
package org.insa.algo ;
import java.io.* ;
import java.util.ArrayList;
public abstract class AbstractAlgorithm {
public abstract class AbstractAlgorithm implements Runnable {
protected PrintStream output;
protected AbstractInstance instance;
protected AbstractSolution solution;
protected ArrayList<AbstractObserver> observers;
protected AbstractAlgorithm(AbstractInstance instance) {
this.instance = instance;
this.observers = new ArrayList<AbstractObserver>();
this.solution = null;
}
protected AbstractAlgorithm(AbstractInstance instance, ArrayList<AbstractObserver> observers) {
this.instance = instance;
this.observers = observers;;
this.solution = null;
}
/**
* Add an observer to this algorithm.
*
* @param instance
* @param logOutput
* @param observer
*/
protected AbstractAlgorithm(AbstractInstance instance, PrintStream logOutput) {
this.instance = instance;
this.output = logOutput;
this.solution = null;
public void addObserver(AbstractObserver observer) {
observers.add(observer);
}
/**
* @return The list of observers for this algorithm.
*/
public ArrayList<AbstractObserver> getObservers() {
return observers;
}
/**
@@ -44,9 +62,8 @@ public abstract class AbstractAlgorithm {
*
* @return true if a feasible solution was found (even non-optimal).
*/
public boolean run() {
public void run() {
this.solution = this.doRun();
return this.solution != null && this.solution.isFeasible();
}
/**

View File

@@ -0,0 +1,20 @@
package org.insa.algo;
public abstract class AbstractObserver {
// Specify if the observer is graphic or not.
private final boolean isgraphic;
protected AbstractObserver(boolean isGraphic) {
this.isgraphic = isGraphic;
}
/**
* @return true if this observer is graphic (use drawing to display
* information).
*/
public boolean isGraphic() {
return isgraphic;
}
}

View File

@@ -1,30 +0,0 @@
package org.insa.algo.connectivity ;
import java.io.* ;
import org.insa.algo.AbstractAlgorithm;
import org.insa.algo.AbstractSolution;
public class ConnectivityAlgorithm extends AbstractAlgorithm {
/**
*
* @param instance
* @param logOutput
*/
public ConnectivityAlgorithm(ConnectivityInstance instance, PrintStream logOutput) {
super(instance, logOutput);
}
/**
* {@inheritDoc}
*/
@Override
protected AbstractSolution doRun() {
ConnectivityInstance instance = (ConnectivityInstance)getInstance();
ConnectivitySolution solution = null;
// TODO:
return solution;
}
}

View File

@@ -1,16 +0,0 @@
package org.insa.algo.connectivity;
import org.insa.algo.AbstractInstance;
import org.insa.graph.Graph;
public class ConnectivityInstance extends AbstractInstance {
/**
*
* @param graph
*/
public ConnectivityInstance(Graph graph) {
super(graph);
}
}

View File

@@ -1,20 +0,0 @@
package org.insa.algo.connectivity;
import java.time.Duration;
import org.insa.algo.AbstractSolution;
public class ConnectivitySolution extends AbstractSolution {
protected ConnectivitySolution(ConnectivityInstance instance) {
super(instance);
}
protected ConnectivitySolution(ConnectivityInstance instance,
Duration solvingTime, Status status) {
super(instance, solvingTime, status);
// TODO:
}
}

View File

@@ -0,0 +1,16 @@
package org.insa.algo.strongconnectivity ;
import org.insa.algo.AbstractAlgorithm;
public abstract class StronglyConnectedComponentsAlgorithm extends AbstractAlgorithm {
/**
*
* @param instance
* @param logOutput
*/
public StronglyConnectedComponentsAlgorithm(StronglyConnectedComponentsInstance instance) {
super(instance);
}
}

View File

@@ -0,0 +1,16 @@
package org.insa.algo.strongconnectivity;
import org.insa.algo.AbstractInstance;
import org.insa.graph.Graph;
public class StronglyConnectedComponentsInstance extends AbstractInstance {
/**
*
* @param graph
*/
public StronglyConnectedComponentsInstance(Graph graph) {
super(graph);
}
}

View File

@@ -0,0 +1,29 @@
package org.insa.algo.strongconnectivity;
import java.time.Duration;
import java.util.ArrayList;
import org.insa.algo.AbstractSolution;
import org.insa.graph.Node;
public class StronglyConnectedComponentsSolution extends AbstractSolution {
// Components
private ArrayList<ArrayList<Node>> components;
protected StronglyConnectedComponentsSolution(StronglyConnectedComponentsInstance instance) {
super(instance);
}
protected StronglyConnectedComponentsSolution(StronglyConnectedComponentsInstance instance,
Duration solvingTime, Status status, ArrayList<ArrayList<Node>> components) {
super(instance, solvingTime, status);
this.components = components;
}
/**
* @return Components of the solution, if any.
*/
public ArrayList<ArrayList<Node>> getComponents() { return components; }
}

View File

@@ -0,0 +1,155 @@
package org.insa.algo.strongconnectivity;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;
import org.insa.algo.AbstractSolution;
import org.insa.algo.AbstractSolution.Status;
import org.insa.graph.Arc;
import org.insa.graph.Graph;
import org.insa.graph.Node;
public class TarjanAlgorithm extends StronglyConnectedComponentsAlgorithm {
private final static int UNDEFINED = -1;
// Stack of nodes and flags.
private Stack<Node> stack;
private boolean[] inStack;
// Current index.
private int index;
// Information of nodes
private int[] indexes;
private int[] lowlink;
// Array of strongly connected components
ArrayList<ArrayList<Node>> components;
public TarjanAlgorithm(StronglyConnectedComponentsInstance instance) {
super(instance);
}
/**
* Push the given node to the stack.
*
* @param node
*/
protected void pushNode(Node node) {
stack.push(node);
inStack[node.getId()] = true;
}
/**
* Pop and return a node from the stack.
*
* @return Node popped from the stack
*/
protected Node popNode() {
Node top = stack.pop();
inStack[top.getId()] = false;
return top;
}
/**
* Check if the given node is in the stack.
*
* @param node
*
* @return true if the given node is in the stack, false otherwize.
*/
protected boolean isInStack(Node node) {
return inStack[node.getId()];
}
/**
* Find the strong component containing the given node.
*
* @param node
*
* @return The strong component containing the given node.
*/
protected void findAndAddStrongComponent(Node v) {
Graph graph = getInstance().getGraph();
// Update node info, index and push the node.
indexes[v.getId()] = index;
lowlink[v.getId()] = index;
index += 1;
pushNode(v);
for (Arc a: v.getSuccessors()) {
Node w = a.getDestination();
if (!hasBeenVisited(w)) {
findAndAddStrongComponent(w);
lowlink[v.getId()] = Math.min(lowlink[v.getId()], lowlink[w.getId()]);
}
else if (isInStack(w)) {
lowlink[v.getId()] = Math.min(lowlink[v.getId()], indexes[w.getId()]);
}
}
// Compute the component (if any)
if (lowlink[v.getId()] == indexes[v.getId()]) {
ArrayList<Node> component = new ArrayList<Node>();
Node w;
do {
w = popNode();
component.add(w);
} while (!w.equals(v));
components.add(component);
System.out.println("Size of the stack: " + stack.size());
}
}
/**
* Check if the given node has not been visited yet.
*
* @return true if the node has been visited.
*/
protected boolean hasBeenVisited(Node node) {
return this.indexes[node.getId()] != UNDEFINED;
}
@Override
protected AbstractSolution doRun() {
Graph graph = getInstance().getGraph();
components = new ArrayList<ArrayList<Node>>();
// Starting time...
Instant start = Instant.now();
// Initialize everything
final int nbNodes = graph.getNodes().size();
stack = new Stack<Node>();
inStack = new boolean[nbNodes];
// Current index.
index = 0;
// Information of nodes
indexes = new int[nbNodes];
Arrays.fill(indexes, UNDEFINED);
lowlink = new int[nbNodes];
// Find components
for (Node node: graph.getNodes()) {
if (!hasBeenVisited(node)) {
findAndAddStrongComponent(node);
}
}
// Duration...
Duration solvingTime = Duration.between(start, Instant.now());
return new StronglyConnectedComponentsSolution((StronglyConnectedComponentsInstance)getInstance(),
solvingTime, Status.OPTIMAL, components);
}
}

View File

@@ -0,0 +1,46 @@
package org.insa.algo.weakconnectivity;
import java.awt.Color;
import java.util.ArrayList;
import org.insa.drawing.Drawing;
import org.insa.drawing.graph.GraphDrawing;
import org.insa.graph.Node;
public class WeaklyConnectedComponentGraphicObserver extends WeaklyConnectedComponentObserver {
private static final Color[] COLORS = {
Color.BLUE, Color.ORANGE, Color.GREEN, Color.YELLOW, Color.RED
};
// Drawing + Graph drawing
private Drawing drawing;
private GraphDrawing gdrawing;
// Current index color
private int cindex = 0;
public WeaklyConnectedComponentGraphicObserver(Drawing drawing) {
super(true);
this.drawing = drawing;
this.gdrawing = new GraphDrawing(drawing);
this.drawing.setAutoRepaint(true);
}
@Override
public void notifyStartComponent(Node curNode) {
this.drawing.setColor(COLORS[cindex]);
cindex = (cindex + 1) % COLORS.length;
}
@Override
public void notifyNewNodeInComponent(Node node) {
this.gdrawing.drawPoint(node.getPoint(), 5);
this.drawing.repaint();
}
@Override
public void notifyEndComponent(ArrayList<Node> nodes) {
}
}

View File

@@ -0,0 +1,38 @@
package org.insa.algo.weakconnectivity;
import java.util.ArrayList;
import org.insa.algo.AbstractObserver;
import org.insa.graph.Node;
public abstract class WeaklyConnectedComponentObserver extends AbstractObserver {
/**
* {@inheritDoc}
*/
protected WeaklyConnectedComponentObserver(boolean isGraphic) {
super(isGraphic);
}
/**
* Notify that the algorithm is entering a new component.
*
* @param curNode Starting node for the component.
*/
public abstract void notifyStartComponent(Node curNode);
/**
* Notify that a new node has been found for the current component.
*
* @param node New node found for the current component.
*/
public abstract void notifyNewNodeInComponent(Node node);
/**
* Notify that the algorithm has computed a new component.
*
* @param nodes List of nodes in the component.
*/
public abstract void notifyEndComponent(ArrayList<Node> nodes);
}

View File

@@ -0,0 +1,37 @@
package org.insa.algo.weakconnectivity;
import java.io.PrintStream;
import java.util.ArrayList;
import org.insa.graph.Node;
public class WeaklyConnectedComponentTextObserver extends WeaklyConnectedComponentObserver {
// Number of the current component.
private int numComponent = 1;
// Output stream
PrintStream stream;
public WeaklyConnectedComponentTextObserver(PrintStream stream) {
super(false);
this.stream = stream;
}
@Override
public void notifyStartComponent(Node curNode) {
stream.print("Entering component #" + numComponent + " from node #" + curNode.getId() + "... ");
}
@Override
public void notifyNewNodeInComponent(Node node) {
}
@Override
public void notifyEndComponent(ArrayList<Node> nodes) {
stream.println(nodes.size() + " nodes found.");
stream.flush();
numComponent += 1;
}
}

View File

@@ -0,0 +1,127 @@
package org.insa.algo.weakconnectivity;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;
import java.util.HashSet;
import org.insa.algo.AbstractAlgorithm;
import org.insa.algo.AbstractObserver;
import org.insa.algo.AbstractSolution;
import org.insa.algo.AbstractSolution.Status;
import org.insa.graph.Arc;
import org.insa.graph.Graph;
import org.insa.graph.Node;
public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm {
/**
*
* @param instance
* @param logOutput
*/
public WeaklyConnectedComponentsAlgorithm(WeaklyConnectedComponentsInstance instance) {
super(instance);
}
/**
* @return An adjacency list for the undirected graph equivalent to the stored graph.
*/
protected ArrayList<HashSet<Integer>> createUndirectedGraph() {
int nNodes = getInstance().getGraph().getNodes().size();
ArrayList<HashSet<Integer>> res = new ArrayList<HashSet<Integer>>(nNodes);
for (int i = 0; i < nNodes; ++i) {
res.add(new HashSet<Integer>());
}
for (Node node: getInstance().getGraph().getNodes()) {
for (Arc arc: node.getSuccessors()) {
res.get(node.getId()).add(arc.getDestination().getId());
if (arc.getInfo().isOneWay()) {
res.get(arc.getDestination().getId()).add(node.getId());
}
}
}
return res;
}
/**
* Apply a breadth first search algorithm on the given undirected graph (adjacency list),
* starting at node cur, and marking nodes in marked.
*
* @param marked
* @param cur
*
* @return
*/
protected ArrayList<Node> bfs(ArrayList<HashSet<Integer>> ugraph, boolean[] marked, int cur) {
ArrayList<Node> nodes = getInstance().getGraph().getNodes();
ArrayList<Node> component = new ArrayList<Node>();
// Using a queue because we are doing a BFS
Queue<Integer> queue = new LinkedList<Integer>();
for (AbstractObserver obs: getObservers()) {
((WeaklyConnectedComponentObserver)obs).notifyStartComponent(nodes.get(cur));
}
// Add original node and loop until the queue is empty.
queue.add(cur);
marked[cur] = true;
while (!queue.isEmpty()) {
Node node = nodes.get(queue.remove());
component.add(node);
// notify observers
for (AbstractObserver obs: getObservers()) ((WeaklyConnectedComponentObserver)obs).notifyNewNodeInComponent(node);
for (Integer destId: ugraph.get(node.getId())) {
Node dest = nodes.get(destId);
if (!marked[dest.getId()]) {
queue.add(destId);
marked[destId] = true;
}
}
}
for (AbstractObserver obs: getObservers()) {
((WeaklyConnectedComponentObserver)obs).notifyEndComponent(component);
}
return component;
}
@Override
protected AbstractSolution doRun() {
Instant start = Instant.now();
Graph graph = getInstance().getGraph();
ArrayList<HashSet<Integer>> ugraph = createUndirectedGraph();
boolean[] marked = new boolean[graph.getNodes().size()];
Arrays.fill(marked, false);
ArrayList<ArrayList<Node>> components = new ArrayList<ArrayList<Node>>();
// perform algorithm
int cur = 0;
while (cur < marked.length) {
// Apply BFS
components.add(this.bfs(ugraph, marked, cur));
// Find next non-marked
for (; cur < marked.length && marked[cur]; ++cur);
}
Duration solvingTime = Duration.between(start, Instant.now());
return new WeaklyConnectedComponentsSolution((WeaklyConnectedComponentsInstance)getInstance(),
solvingTime, Status.OPTIMAL, components);
}
}

View File

@@ -0,0 +1,16 @@
package org.insa.algo.weakconnectivity;
import org.insa.algo.AbstractInstance;
import org.insa.graph.Graph;
public class WeaklyConnectedComponentsInstance extends AbstractInstance {
/**
*
* @param graph
*/
public WeaklyConnectedComponentsInstance(Graph graph) {
super(graph);
}
}

View File

@@ -0,0 +1,29 @@
package org.insa.algo.weakconnectivity;
import java.time.Duration;
import java.util.ArrayList;
import org.insa.algo.AbstractSolution;
import org.insa.graph.Node;
public class WeaklyConnectedComponentsSolution extends AbstractSolution {
// Components
private ArrayList<ArrayList<Node>> components;
protected WeaklyConnectedComponentsSolution(WeaklyConnectedComponentsInstance instance) {
super(instance);
}
protected WeaklyConnectedComponentsSolution(WeaklyConnectedComponentsInstance instance,
Duration solvingTime, Status status, ArrayList<ArrayList<Node>> components) {
super(instance, solvingTime, status);
this.components = components;
}
/**
* @return Components of the solution, if any.
*/
public ArrayList<ArrayList<Node>> getComponents() { return components; }
}