package org.bundlemaker.core.analysis.algorithms;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
/**
* <p>
* http://dl.acm.org/citation.cfm?id=595057
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class FastFAS {
/** the set of vertices */
private Set<Integer> _vertices;
/** the adjacency matrix */
int[][] _adjacencyMatrix;
/** the result list 's1' */
private List<Integer> _s1;
/** the result list 's2' */
private List<Integer> _s2;
/**
* <p>
* Creates a new instance of type {@link FastFAS}.
* </p>
*
* @param adjacencyMatrix
* the adjacency matrix
*/
public FastFAS(int[][] adjacencyMatrix) {
// Assert
//
_adjacencyMatrix = adjacencyMatrix;
}
/**
* <p>
* Returns the ordered sequence.
* </p>
*
* @return the ordered sequence.
*/
public int[] getOrderedSequence() {
// create the vertices set
_vertices = new HashSet<Integer>();
for (int i = 0; i < _adjacencyMatrix.length; i++) {
_vertices.add(i);
}
// create the internal result lists
_s1 = new ArrayList<Integer>();
_s2 = new ArrayList<Integer>();
// the main loop
while (!_vertices.isEmpty()) {
if (findSink()) {
continue;
} else if (findSource()) {
continue;
} else if (findVertexToRemove()) {
continue;
}
}
// convert to result array
return convertToArray(_s1, _s2);
}
/**
* <p>
* </p>
*
* @param sequence
* @return
*/
public static int[] reverse(int[] sequence) {
//
Assert.isNotNull(sequence);
//
int[] result = new int[sequence.length];
for (int i = 0; i < sequence.length; i++) {
result[sequence.length - (1 + i)] = sequence[i];
}
//
return result;
}
/**
* <p>
* Tries to find and remove a sink.
* </p>
*
* @return <code>true</code> if a sink was found and removed.
*/
private boolean findSink() {
// initialize the sink
int sink = -1;
// try to find a sink...
for (Integer i : _vertices) {
sink = i;
for (Integer j : _vertices) {
if (i != j && _adjacencyMatrix[i][j] != 0) {
sink = -1;
break;
}
}
if (sink != -1) {
break;
}
}
// if a sink was found, remove it and return true...
if (sink != -1) {
_vertices.remove(sink);
_s2.add(0, sink);
return true;
}
// ...otherwise return false
else {
return false;
}
}
/**
* <p>
* Tries to find and remove a source.
* </p>
*
* @return <code>true</code> if a source was found and removed.
*/
private boolean findSource() {
// initialize the source
int source = -1;
// try to find a source...
for (Integer i : _vertices) {
source = i;
for (Integer j : _vertices) {
if (i != j && _adjacencyMatrix[j][i] != 0) {
source = -1;
break;
}
}
if (source != -1) {
break;
}
}
// if a source was found, remove it and return true...
if (source != -1) {
_vertices.remove(source);
_s1.add(source);
return true;
}
// ...otherwise return false
else {
return false;
}
}
/**
* <p>
* </p>
*
* @return
*/
private boolean findVertexToRemove() {
// initialize current maximum and vertex
int currentMaximum = Integer.MIN_VALUE;
int currentVertex = Integer.MIN_VALUE;
// find the vertex with the highest maximum
for (Integer vertex : _vertices) {
int delta = getDelta(vertex);
if (currentVertex == Integer.MIN_VALUE || currentMaximum < delta) {
currentMaximum = delta;
currentVertex = vertex;
}
}
// remove vertex and return true...
_vertices.remove(currentVertex);
_s1.add(currentVertex);
return false;
}
/**
* <p>
* </p>
*
* @param vertex
* @return
*/
private int getDelta(int vertex) {
int in = 0;
int out = 0;
for (Integer j : _vertices) {
if (vertex != j) {
in = in + _adjacencyMatrix[j][vertex];
out = out + _adjacencyMatrix[vertex][j];
}
}
//
return out - in;
}
/**
* <p>
* Helper method. Concatenates the given lists and returns them as one array.
* </p>
*
* @param s1
* the list s1
* @param s2
* the list s2
* @return the result array.
*/
private int[] convertToArray(List<Integer> s1, List<Integer> s2) {
int[] result = new int[s1.size() + s2.size()];
int index = 0;
for (int i : s1) {
result[index] = i;
index++;
}
for (int i : s2) {
result[index] = i;
index++;
}
return result;
}
/**
* <p>
* </p>
*
* @param args
*/
public static void main(String[] args) {
// int[][] testMatrix = new int[][] { { 1, 3, 5 }, { 5, 9, 12 }, { 0, 0, 0 } };
// int[][] testMatrix = new int[][] { { 0, 3, 5 }, { 5, 0, 12 }, { 5, 0, 0 } };
int[][] testMatrix = new int[][] { { 1, 3, 5 }, { 0, 9, 2 }, { 0, 12, 33 } };
// int[][] testMatrix = new int[][] { { 5, 0, 3, 5 }, { 5, 11, 0, 12 }, { 5, 40, 12, 3 },
// { 5, 40, 12, 3 } };
// //
// FastFAS fastFAS = new FastFAS(testMatrix);
// fastFAS.createVertices();
// fastFAS.findSink();
// fastFAS.findSource();
//
FastFAS fas = new FastFAS(testMatrix);
int[] result = fas.getOrderedSequence();
System.out.println("Beziehungen abw�rts:");
for (int i = 0; i < result.length; i++) {
System.out.println(result[i]);
for (int j = i; j < result.length; j++) {
if (i != j && fas._adjacencyMatrix[result[i]][result[j]] > 0) {
System.out.println(" - " + result[i] + ":" + result[j] + " -> "
+ fas._adjacencyMatrix[result[i]][result[j]]);
}
}
}
System.out.println("Beziehungen aufw�rts:");
int[] reverseResult = new int[result.length];
for (int i = 0; i < result.length; i++) {
reverseResult[result.length - (1 + i)] = result[i];
}
for (int i = 0; i < reverseResult.length; i++) {
System.out.println(reverseResult[i]);
for (int j = i; j < reverseResult.length; j++) {
if (i != j && fas._adjacencyMatrix[reverseResult[i]][reverseResult[j]] > 0) {
System.out.println(" - " + reverseResult[i] + ":" + reverseResult[j] + " -> "
+ fas._adjacencyMatrix[reverseResult[i]][reverseResult[j]]);
}
}
}
}
}