All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.chocosolver.util.graphOperations.connectivity.StrongConnectivityFinder Maven / Gradle / Ivy

There is a newer version: 4.10.17
Show newest version
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2023, IMT Atlantique. All rights reserved.
 *
 * Licensed under the BSD 4-clause license.
 *
 * See LICENSE file in the project root for full license information.
 */
package org.chocosolver.util.graphOperations.connectivity;

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  {

    //***********************************************************************************
    // VARIABLES
    //***********************************************************************************

    // input
    private final DirectedGraph graph;
    private final BitSet restriction;
    private final int n;
    // output
    private final int[] sccFirstNode;
    private final int[] nextNode;
    private final int[] nodeSCC;
    private int nbSCC;

    // util
    private final int[] stack;
    private final int[] p;
    private final int[] inf;
    private final int[] nodeOfDfsNum;
    private final int[] dfsNumOfNode;
    private final Iterator[] iterator;
    private final BitSet inStack;

    //***********************************************************************************
    // CONSTRUCTOR
    //***********************************************************************************

    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;
        //noinspection unchecked
        iterator = new Iterator[n];
    }

    //***********************************************************************************
    // ALGORITHM
    //***********************************************************************************

    public void findAllSCC() {
        ISet nodes = graph.getNodes();
        for (int i = 0; i < n; i++) {
            restriction.set(i, nodes.contains(i));
        }
        findAllSCCOf(restriction);
    }

    // exception is a set of nodes that do not need to be found SCC
    public void findAllSCC(BitSet exception) {
        ISet nodes = graph.getNodes();
        for (int i = exception.nextClearBit(0); i >= 0 && i < n; i = exception.nextClearBit(i + 1)) {
            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.getPredecessorsOf(i).size() * graph.getSuccessorsOf(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.getSuccessorsOf(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.getSuccessorsOf(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;
    }

    //***********************************************************************************
    // ACCESSORS
    //***********************************************************************************

    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];
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy