@ -48,11 +48,8 @@ namespace storm {
template < typename ValueType >
template < typename ValueType >
void StronglyConnectedComponentDecomposition < ValueType > : : performSccDecomposition ( storm : : models : : AbstractModel < ValueType > const & model , storm : : storage : : BitVector const & subsystem , bool dropNaiveSccs , bool onlyBottomSccs ) {
void StronglyConnectedComponentDecomposition < ValueType > : : performSccDecomposition ( storm : : models : : AbstractModel < ValueType > const & model , storm : : storage : : BitVector const & subsystem , bool dropNaiveSccs , bool onlyBottomSccs ) {
LOG4CPLUS_INFO ( logger , " Computing SCC decomposition. " ) ;
uint_fast64_t numberOfStates = model . getNumberOfStates ( ) ;
// Set up the environment of Tarjan's algorithm.
// Set up the environment of Tarjan's algorithm.
uint_fast64_t numberOfStates = model . getNumberOfStates ( ) ;
std : : vector < uint_fast64_t > tarjanStack ;
std : : vector < uint_fast64_t > tarjanStack ;
tarjanStack . reserve ( numberOfStates ) ;
tarjanStack . reserve ( numberOfStates ) ;
storm : : storage : : BitVector tarjanStackStates ( numberOfStates ) ;
storm : : storage : : BitVector tarjanStackStates ( numberOfStates ) ;
@ -60,24 +57,20 @@ namespace storm {
std : : vector < uint_fast64_t > lowlinks ( numberOfStates ) ;
std : : vector < uint_fast64_t > lowlinks ( numberOfStates ) ;
storm : : storage : : BitVector visitedStates ( numberOfStates ) ;
storm : : storage : : BitVector visitedStates ( numberOfStates ) ;
// Start the search for SCCs from every vertex in the block.
// Start the search for SCCs from every state in the block.
uint_fast64_t currentIndex = 0 ;
uint_fast64_t currentIndex = 0 ;
for ( auto state : subsystem ) {
for ( auto state : subsystem ) {
if ( ! visitedStates . get ( state ) ) {
if ( ! visitedStates . get ( state ) ) {
performSccDecompositionHelper ( model , state , subsystem , currentIndex , stateIndices , lowlinks , tarjanStack , tarjanStackStates , visitedStates , dropNaiveSccs , onlyBottomSccs ) ;
performSccDecompositionHelper ( model , state , subsystem , currentIndex , stateIndices , lowlinks , tarjanStack , tarjanStackStates , visitedStates , dropNaiveSccs , onlyBottomSccs ) ;
}
}
}
}
LOG4CPLUS_INFO ( logger , " Done computing SCC decomposition. " ) ;
}
}
template < typename ValueType >
template < typename ValueType >
void StronglyConnectedComponentDecomposition < ValueType > : : performSccDecomposition ( storm : : models : : AbstractModel < ValueType > const & model , bool dropNaiveSccs , bool onlyBottomSccs ) {
void StronglyConnectedComponentDecomposition < ValueType > : : performSccDecomposition ( storm : : models : : AbstractModel < ValueType > const & model , bool dropNaiveSccs , bool onlyBottomSccs ) {
uint_fast64_t numberOfStates = model . getNumberOfStates ( ) ;
// Prepare a block that contains all states for a call to the other overload of this function.
// Prepare a block that contains all states for a call to the other overload of this function.
storm : : storage : : BitVector fullSystem ( n umberOfStates, true ) ;
storm : : storage : : BitVector fullSystem ( model . getNumberOfStates ( ) , true ) ;
// Call the overloaded function.
// Call the overloaded function.
performSccDecomposition ( model , fullSystem , dropNaiveSccs , onlyBottomSccs ) ;
performSccDecomposition ( model , fullSystem , dropNaiveSccs , onlyBottomSccs ) ;
@ -85,17 +78,17 @@ namespace storm {
template < typename ValueType >
template < typename ValueType >
void StronglyConnectedComponentDecomposition < ValueType > : : performSccDecompositionHelper ( storm : : models : : AbstractModel < ValueType > const & model , uint_fast64_t startState , storm : : storage : : BitVector const & subsystem , uint_fast64_t & currentIndex , std : : vector < uint_fast64_t > & stateIndices , std : : vector < uint_fast64_t > & lowlinks , std : : vector < uint_fast64_t > & tarjanStack , storm : : storage : : BitVector & tarjanStackStates , storm : : storage : : BitVector & visitedStates , bool dropNaiveSccs , bool onlyBottomSccs ) {
void StronglyConnectedComponentDecomposition < ValueType > : : performSccDecompositionHelper ( storm : : models : : AbstractModel < ValueType > const & model , uint_fast64_t startState , storm : : storage : : BitVector const & subsystem , uint_fast64_t & currentIndex , std : : vector < uint_fast64_t > & stateIndices , std : : vector < uint_fast64_t > & lowlinks , std : : vector < uint_fast64_t > & tarjanStack , storm : : storage : : BitVector & tarjanStackStates , storm : : storage : : BitVector & visitedStates , bool dropNaiveSccs , bool onlyBottomSccs ) {
// Create the stacks needed for turning the recursive formulation of Tarjan's algorithm
// into an iterative version. In particular, we keep one stack for states and one stack
// for the iterators. The last one is not strictly needed, but reduces iteration work when
// all successors of a particular state are considered.
// Create the stacks needed for turning the recursive formulation of Tarjan's algorithm into an iterative
// version. In particular, we keep one stack for states and one stack for the iterators. The last one is not
// strictly needed, but reduces iteration work when all successors of a particular state are considered.
std : : vector < uint_fast64_t > recursionStateStack ;
std : : vector < uint_fast64_t > recursionStateStack ;
recursionStateStack . reserve ( lowlinks . size ( ) ) ;
recursionStateStack . reserve ( lowlinks . size ( ) ) ;
std : : vector < typename storm : : storage : : SparseMatrix < ValueType > : : const_iterator > recursionIteratorStack ;
std : : vector < typename storm : : storage : : SparseMatrix < ValueType > : : const_iterator > recursionIteratorStack ;
recursionIteratorStack . reserve ( lowlinks . size ( ) ) ;
recursionIteratorStack . reserve ( lowlinks . size ( ) ) ;
std : : vector < bool > statesInStack ( lowlinks . size ( ) ) ;
std : : vector < bool > statesInStack ( lowlinks . size ( ) ) ;
// Store a bit vector of all states with a self-loop to be able to detect non-trivial SCCs with only one state.
// Store a bit vector of all states with a self-loop to be able to detect non-trivial SCCs with only one
// state.
storm : : storage : : BitVector statesWithSelfloop ;
storm : : storage : : BitVector statesWithSelfloop ;
if ( dropNaiveSccs ) {
if ( dropNaiveSccs ) {
statesWithSelfloop = storm : : storage : : BitVector ( lowlinks . size ( ) ) ;
statesWithSelfloop = storm : : storage : : BitVector ( lowlinks . size ( ) ) ;
@ -131,9 +124,8 @@ namespace storm {
statesWithSelfloop . set ( currentState , true ) ;
statesWithSelfloop . set ( currentState , true ) ;
}
}
// If we have not visited the successor already, we need to perform the procedure
// recursively on the newly found state, but only if it belongs to the subsystem in
// which we are interested.
// If we have not visited the successor already, we need to perform the procedure recursively on the
// newly found state, but only if it belongs to the subsystem in which we are interested.
if ( subsystem . get ( successorIt - > first ) ) {
if ( subsystem . get ( successorIt - > first ) ) {
if ( ! visitedStates . get ( successorIt - > first ) ) {
if ( ! visitedStates . get ( successorIt - > first ) ) {
// Save current iterator position so we can continue where we left off later.
// Save current iterator position so we can continue where we left off later.
@ -162,14 +154,14 @@ namespace storm {
// Update the lowlink of the current state.
// Update the lowlink of the current state.
lowlinks [ currentState ] = std : : min ( lowlinks [ currentState ] , stateIndices [ successorIt - > first ] ) ;
lowlinks [ currentState ] = std : : min ( lowlinks [ currentState ] , stateIndices [ successorIt - > first ] ) ;
// Since it is known that in this case, the successor state is in the same SCC as the current state
// we don't need to update the bit vector of states that can leave their SCC.
// Since it is known that in this case, the successor state is in the same SCC as the
// current state we don't need to update the bit vector of states that can leave their SCC.
}
}
}
}
}
}
// If the current state is the root of a SCC, we need to pop all states of the SCC from
// the algorithm's stack.
// If the current state is the root of a SCC, we need to pop all states of the SCC from the algorithm's
// stack.
if ( lowlinks [ currentState ] = = stateIndices [ currentState ] ) {
if ( lowlinks [ currentState ] = = stateIndices [ currentState ] ) {
Block scc ;
Block scc ;
@ -190,7 +182,8 @@ namespace storm {
} while ( lastState ! = currentState ) ;
} while ( lastState ! = currentState ) ;
// Now determine whether we want to keep this SCC in the decomposition.
// Now determine whether we want to keep this SCC in the decomposition.
// First, we need to check whether we should drop the SCC because of the requirement to not include naive SCCs.
// First, we need to check whether we should drop the SCC because of the requirement to not include
// naive SCCs.
bool keepScc = ! dropNaiveSccs | | ( scc . size ( ) > 1 | | statesWithSelfloop . get ( * scc . begin ( ) ) ) ;
bool keepScc = ! dropNaiveSccs | | ( scc . size ( ) > 1 | | statesWithSelfloop . get ( * scc . begin ( ) ) ) ;
// Then, we also need to make sure that it is a bottom SCC if we were required to.
// Then, we also need to make sure that it is a bottom SCC if we were required to.
keepScc & = ! onlyBottomSccs | | isBottomScc ;
keepScc & = ! onlyBottomSccs | | isBottomScc ;
@ -201,14 +194,13 @@ namespace storm {
}
}
}
}
// If we reach this point, we have completed the recursive descent for the current state.
// That is, we need to pop it from the recursion stacks.
// If we reach this point, we have completed the recursive descent for the current state. That is, we
// need to pop it from the recursion stacks.
recursionStateStack . pop_back ( ) ;
recursionStateStack . pop_back ( ) ;
recursionIteratorStack . pop_back ( ) ;
recursionIteratorStack . pop_back ( ) ;
// If there is at least one state under the current one in our recursion stack, we need
// to restore the topmost state as the current state and jump to the part after the
// original recursive call.
// If there is at least one state under the current one in our recursion stack, we need to restore the
// topmost state as the current state and jump to the part after the original recursive call.
if ( recursionStateStack . size ( ) > 0 ) {
if ( recursionStateStack . size ( ) > 0 ) {
currentState = recursionStateStack . back ( ) ;
currentState = recursionStateStack . back ( ) ;
successorIt = recursionIteratorStack . back ( ) ;
successorIt = recursionIteratorStack . back ( ) ;
@ -218,6 +210,7 @@ namespace storm {
}
}
}
}
// Explicitly instantiate the SCC decomposition.
template class StronglyConnectedComponentDecomposition < double > ;
template class StronglyConnectedComponentDecomposition < double > ;
} // namespace storage
} // namespace storage
} // namespace storm
} // namespace storm