org.chocosolver.graphsolver.util.StrongConnectivityFinder Maven / Gradle / Ivy
Show all versions of choco-graph Show documentation
/**
* Copyright (c) 1999-2011, Ecole des Mines de Nantes
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Ecole des Mines de Nantes nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Created by IntelliJ IDEA.
* User: Jean-Guillaume Fages
* Date: 17/04/2016
* Time: 13:11
*/
/**
* Created by IntelliJ IDEA.
* User: Jean-Guillaume Fages
* Date: 17/04/2016
* Time: 13:11
*/
package org.chocosolver.graphsolver.util;
import org.chocosolver.util.objects.graphs.DirectedGraph;
import org.chocosolver.util.objects.setDataStructures.ISet;
import java.util.BitSet;
import java.util.Iterator;
public class StrongConnectivityFinder {
// input
private DirectedGraph graph;
private BitSet restriction;
private int n;
// output
private int[] sccFirstNode, nextNode, nodeSCC;
private int nbSCC;
// util
private int[] stack, p, inf, nodeOfDfsNum, dfsNumOfNode;
private Iterator[] iterator;
private BitSet inStack;
public StrongConnectivityFinder(DirectedGraph graph) {
this.graph = graph;
this.n = graph.getNbMaxNodes();
//
stack = new int[n];
p = new int[n];
inf = new int[n];
nodeOfDfsNum = new int[n];
dfsNumOfNode = new int[n];
inStack = new BitSet(n);
restriction = new BitSet(n);
sccFirstNode = new int[n];
nextNode = new int[n];
nodeSCC = new int[n];
nbSCC = 0;
iterator = new Iterator[n];
}
public void findAllSCC() {
ISet nodes = graph.getNodes();
for (int i = 0; i < n; i++) {
restriction.set(i, nodes.contains(i));
}
findAllSCCOf(restriction);
}
public void findAllSCCOf(BitSet restriction) {
inStack.clear();
for (int i = 0; i < n; i++) {
dfsNumOfNode[i] = 0;
inf[i] = n + 2;
nextNode[i] = -1;
sccFirstNode[i] = -1;
nodeSCC[i] = -1;
}
nbSCC = 0;
findSingletons(restriction);
int first = restriction.nextSetBit(0);
while (first >= 0) {
findSCC(first, restriction, stack, p, inf, nodeOfDfsNum, dfsNumOfNode, inStack);
first = restriction.nextSetBit(first);
}
}
private void findSingletons(BitSet restriction) {
ISet nodes = graph.getNodes();
for (int i = restriction.nextSetBit(0); i >= 0; i = restriction.nextSetBit(i + 1)) {
if (nodes.contains(i) && graph.getPredOf(i).size() * graph.getSuccOf(i).size() == 0) {
nodeSCC[i] = nbSCC;
sccFirstNode[nbSCC++] = i;
restriction.clear(i);
}
}
}
private void findSCC(int start, BitSet restriction, int[] stack, int[] p, int[] inf, int[] nodeOfDfsNum, int[] dfsNumOfNode, BitSet inStack) {
int nb = restriction.cardinality();
// trivial case
if (nb == 1) {
nodeSCC[start] = nbSCC;
sccFirstNode[nbSCC++] = start;
restriction.clear(start);
return;
}
//initialization
int stackIdx = 0;
int k = 0;
int i = k;
dfsNumOfNode[start] = k;
nodeOfDfsNum[k] = start;
stack[stackIdx++] = i;
inStack.set(i);
p[k] = k;
iterator[k] = graph.getSuccOf(start).iterator();
int j;
// algo
while (true) {
if (iterator[i].hasNext()) {
j = iterator[i].next();
if (restriction.get(j)) {
if (dfsNumOfNode[j] == 0 && j != start) {
k++;
nodeOfDfsNum[k] = j;
dfsNumOfNode[j] = k;
p[k] = i;
i = k;
iterator[i] = graph.getSuccOf(j).iterator();
stack[stackIdx++] = i;
inStack.set(i);
inf[i] = i;
} else if (inStack.get(dfsNumOfNode[j])) {
inf[i] = Math.min(inf[i], dfsNumOfNode[j]);
}
}
} else {
if (i == 0) {
break;
}
if (inf[i] >= i) {
int y, z;
do {
z = stack[--stackIdx];
inStack.clear(z);
y = nodeOfDfsNum[z];
restriction.clear(y);
sccAdd(y);
} while (z != i);
nbSCC++;
}
inf[p[i]] = Math.min(inf[p[i]], inf[i]);
i = p[i];
}
}
if (inStack.cardinality() > 0) {
int y;
do {
y = nodeOfDfsNum[stack[--stackIdx]];
restriction.clear(y);
sccAdd(y);
} while (y != start);
nbSCC++;
}
}
private void sccAdd(int y) {
nodeSCC[y] = nbSCC;
nextNode[y] = sccFirstNode[nbSCC];
sccFirstNode[nbSCC] = y;
}
public int getNbSCC() {
return nbSCC;
}
public int[] getNodesSCC() {
return nodeSCC;
}
public int getSCCFirstNode(int i) {
return sccFirstNode[i];
}
public int getNextNode(int j) {
return nextNode[j];
}
}