@ -1,6 +1,7 @@
# include "src/modelchecker/reachability/SparseDtmcEliminationModelChecker.h"
# include <algorithm>
# include <random>
# include <chrono>
# include "src/adapters/CarlAdapter.h"
@ -27,6 +28,25 @@
namespace storm {
namespace modelchecker {
template < typename ValueType >
uint_fast64_t estimateComplexity ( ValueType const & value ) {
return 1 ;
}
# ifdef STORM_HAVE_CARL
template < >
uint_fast64_t estimateComplexity ( storm : : RationalFunction const & value ) {
if ( storm : : utility : : isConstant ( value ) ) {
return 1 ;
}
if ( value . denominator ( ) . isConstant ( ) ) {
return value . nominator ( ) . complexity ( ) ;
} else {
return value . denominator ( ) . complexity ( ) * value . nominator ( ) . complexity ( ) ;
}
}
# endif
bool eliminationOrderNeedsDistances ( storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder const & order ) {
return order = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder : : Forward | |
order = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder : : ForwardReversed | |
@ -46,7 +66,8 @@ namespace storm {
bool eliminationOrderIsPenaltyBased ( storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder const & order ) {
return order = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder : : StaticPenalty | |
order = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder : : DynamicPenalty ;
order = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder : : DynamicPenalty | |
order = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder : : RegularExpression ;
}
bool eliminationOrderIsStatic ( storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder const & order ) {
@ -283,27 +304,24 @@ namespace storm {
eliminationOrderNeedsReversedDistances ( order ) ) ;
}
std : : vector < storm : : storage : : sparse : : state_type > states ( statesToEliminate . begin ( ) , statesToEliminate . end ( ) ) ;
// Sort the states according to the priorities.
std : : sort ( states . begin ( ) , states . end ( ) , [ & distanceBasedPriorities ] ( storm : : storage : : sparse : : state_type const & a , storm : : storage : : sparse : : state_type const & b ) { return distanceBasedPriorities . get ( ) [ a ] < distanceBasedPriorities . get ( ) [ b ] ; } ) ;
STORM_LOG_INFO ( " Computing conditional probilities. " < < std : : endl ) ;
STORM_LOG_INFO ( " Eliminating " < < states . size ( ) < < " states using the state elimination technique. " < < std : : endl ) ;
boost : : optional < std : : vector < ValueType > > missingStateRewards ;
std : : chrono : : high_resolution_clock : : time_point conversionStart = std : : chrono : : high_resolution_clock : : now ( ) ;
FlexibleSparseMatrix flexibleMatrix = getFlexibleSparseMatrix ( submatrix ) ;
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix ( submatrixTransposed , true ) ;
std : : chrono : : high_resolution_clock : : time_point conversionEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : unique_ptr < StatePriorityQueue > statePriorities = createStatePriorityQueue ( distanceBasedPriorities , flexibleMatrix , flexibleBackwardTransitions , oneStepProbabilities , statesToEliminate ) ;
STORM_LOG_INFO ( " Computing conditional probilities. " < < std : : endl ) ;
boost : : optional < std : : vector < ValueType > > missingStateRewards ;
std : : chrono : : high_resolution_clock : : time_point modelCheckingStart = std : : chrono : : high_resolution_clock : : now ( ) ;
for ( auto const & state : states ) {
eliminateState ( flexibleMatrix , oneStepProbabilities , state , flexibleBackwardTransitions , missingStateRewards ) ;
}
STORM_LOG_INFO ( " Eliminated " < < states . size ( ) < < " states. " < < std : : endl ) ;
uint_fast64_t numberOfStatesToEliminate = statePriorities - > size ( ) ;
STORM_LOG_INFO ( " Eliminating " < < numberOfStatesToEliminate < < " states using the state elimination technique. " < < std : : endl ) ;
performPrioritizedStateElimination ( statePriorities , flexibleMatrix , flexibleBackwardTransitions , oneStepProbabilities , missingStateRewards ) ;
STORM_LOG_INFO ( " Eliminated " < < numberOfStatesToEliminate < < " states. " < < std : : endl ) ;
// Eliminate the transitions going into the initial state (if there are any).
if ( ! flexibleBackwardTransitions . getRow ( * newInitialStates . begin ( ) ) . empty ( ) ) {
eliminateState ( flexibleMatrix , oneStepProbabilities , * newInitialStates . begin ( ) , flexibleBackwardTransitions , missingStateRewards , false ) ;
eliminateState ( flexibleMatrix , oneStepProbabilities , * newInitialStates . begin ( ) , flexibleBackwardTransitions , missingStateRewards , statePriorities . get ( ) , false ) ;
}
// Now we need to basically eliminate all chains of not-psi states after phi states and chains of not-phi
@ -338,7 +356,7 @@ namespace storm {
// Eliminate the successor only if there possibly is a psi state reachable through it.
if ( successorRow . size ( ) > 1 | | ( ! successorRow . empty ( ) & & successorRow . front ( ) . getColumn ( ) ! = element . getColumn ( ) ) ) {
STORM_LOG_TRACE ( " Found non-psi successor " < < element . getColumn ( ) < < " that needs to be eliminated. " ) ;
eliminateState ( flexibleMatrix , oneStepProbabilities , element . getColumn ( ) , flexibleBackwardTransitions , missingStateRewards , false , true , phiStates ) ;
eliminateState ( flexibleMatrix , oneStepProbabilities , element . getColumn ( ) , flexibleBackwardTransitions , missingStateRewards , nullptr , false , true , phiStates ) ;
hasNonPsiSuccessor = true ;
}
}
@ -367,7 +385,7 @@ namespace storm {
typename FlexibleSparseMatrix : : row_type const & successorRow = flexibleMatrix . getRow ( element . getColumn ( ) ) ;
if ( successorRow . size ( ) > 1 | | ( ! successorRow . empty ( ) & & successorRow . front ( ) . getColumn ( ) ! = element . getColumn ( ) ) ) {
STORM_LOG_TRACE ( " Found non-phi successor " < < element . getColumn ( ) < < " that needs to be eliminated. " ) ;
eliminateState ( flexibleMatrix , oneStepProbabilities , element . getColumn ( ) , flexibleBackwardTransitions , missingStateRewards , false , true , psiStates ) ;
eliminateState ( flexibleMatrix , oneStepProbabilities , element . getColumn ( ) , flexibleBackwardTransitions , missingStateRewards , nullptr , false , true , psiStates ) ;
hasNonPhiSuccessor = true ;
}
}
@ -433,17 +451,19 @@ namespace storm {
}
template < typename SparseDtmcModelType >
std : : unique_ptr < typename SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : StatePriorityQueue > SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : createStatePriorityQueue ( boost : : optional < std : : vector < uint_fast64_t > > const & distanceBasedStatePriorities , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions , std : : vector < typename SparseDtmcModelType : : ValueType > & oneStepProbabilities , std : : vector < storm : : storage : : sparse : : state_type > const & states ) {
std : : unique_ptr < typename SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : StatePriorityQueue > SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : createStatePriorityQueue ( boost : : optional < std : : vector < uint_fast64_t > > const & distanceBasedStatePriorities , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions , std : : vector < typename SparseDtmcModelType : : ValueType > & oneStepProbabilities , storm : : storage : : BitVector const & states ) {
STORM_LOG_TRACE ( " Creating state priority queue for states " < < states ) ;
// Get the settings to customize the priority queue.
storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder order = storm : : settings : : sparseDtmcEliminationModelCheckerSettings ( ) . getEliminationOrder ( ) ;
std : : vector < storm : : storage : : sparse : : state_type > sortedStates ( states ) ;
for ( storm : : storage : : sparse : : state_type index = 0 ; index < states . size ( ) ; + + index ) {
sortedStates [ index ] = index ;
}
std : : vector < storm : : storage : : sparse : : state_type > sortedStates ( states . begin ( ) , states . end ( ) ) ;
if ( order = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder : : Random ) {
std : : random_shuffle ( sortedStates . begin ( ) , sortedStates . end ( ) ) ;
std : : random_device randomDevice ;
std : : mt19937 generator ( randomDevice ( ) ) ;
std : : shuffle ( sortedStates . begin ( ) , sortedStates . end ( ) , generator ) ;
return std : : make_unique < StaticStatePriorityQueue > ( sortedStates ) ;
} else {
if ( eliminationOrderNeedsDistances ( order ) ) {
@ -451,9 +471,10 @@ namespace storm {
std : : sort ( sortedStates . begin ( ) , sortedStates . end ( ) , [ & distanceBasedStatePriorities ] ( storm : : storage : : sparse : : state_type const & state1 , storm : : storage : : sparse : : state_type const & state2 ) { return distanceBasedStatePriorities . get ( ) [ state1 ] < distanceBasedStatePriorities . get ( ) [ state2 ] ; } ) ;
return std : : make_unique < StaticStatePriorityQueue > ( sortedStates ) ;
} else if ( eliminationOrderIsPenaltyBased ( order ) ) {
std : : vector < std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > > statePenalties ( states . size ( ) ) ;
std : : vector < std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > > statePenalties ( sortedStates . size ( ) ) ;
PenaltyFunctionType penaltyFunction = order = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationOrder : : RegularExpression ? computeStatePenaltyRegularExpression : computeStatePenalty ;
for ( uint_fast64_t index = 0 ; index < sortedStates . size ( ) ; + + index ) {
statePenalties [ index ] = std : : make_pair ( sortedStates [ index ] , com puteStateP enalty( sortedStates [ index ] , transitionMatrix , backwardTransitions , oneStepProbabilities ) ) ;
statePenalties [ index ] = std : : make_pair ( sortedStates [ index ] , penaltyFunction ( sortedStates [ index ] , transitionMatrix , backwardTransitions , oneStepProbabilities ) ) ;
}
std : : sort ( statePenalties . begin ( ) , statePenalties . end ( ) , [ ] ( std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > const & statePenalty1 , std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > const & statePenalty2 ) { return statePenalty1 . second < statePenalty2 . second ; } ) ;
@ -466,7 +487,7 @@ namespace storm {
return std : : make_unique < StaticStatePriorityQueue > ( sortedStates ) ;
} else {
// For the dynamic penalty version, we need to give the full state-penalty pairs.
return std : : make_unique < DynamicPenaltyStatePriorityQueue > ( statePenalties ) ;
return std : : make_unique < DynamicPenaltyStatePriorityQueue > ( statePenalties , penaltyFunction ) ;
}
}
}
@ -474,25 +495,42 @@ namespace storm {
}
template < typename SparseDtmcModelType >
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : performOrdinaryStateElimination ( FlexibleSparseMatrix & transitionMatrix , FlexibleSparseMatrix & backwardTransitions , uint_fast64_t initialState , std : : vector < typename SparseDtmcModelType : : ValueType > & oneStepProbabilities , boost : : optional < std : : vector < ValueType > > & stateRewards , boost : : optional < std : : vector < uint_fast64_t > > const & distanceBasedPriorities ) {
// Create a vector of all states that need to be eliminated.
std : : vector < storm : : storage : : sparse : : state_type > states ;
states . reserve ( transitionMatrix . getNumberOfRows ( ) - 1 ) ;
for ( uint_fast64_t index = 0 ; index < transitionMatrix . getNumberOfRows ( ) ; + + index ) {
if ( index ! = initialState ) {
states . push_back ( index ) ;
}
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : performPrioritizedStateElimination ( std : : unique_ptr < StatePriorityQueue > & priorityQueue , FlexibleSparseMatrix & transitionMatrix , FlexibleSparseMatrix & backwardTransitions , std : : vector < typename SparseDtmcModelType : : ValueType > & oneStepProbabilities , boost : : optional < std : : vector < ValueType > > & stateRewards ) {
while ( priorityQueue - > hasNextState ( ) ) {
storm : : storage : : sparse : : state_type state = priorityQueue - > popNextState ( ) ;
// std::cout << "Eliminating state with custom penalty " << computeStatePenalty(state, transitionMatrix, backwardTransitions, oneStepProbabilities) << " and regular expression penalty " << computeStatePenaltyRegularExpression(state, transitionMatrix, backwardTransitions, oneStepProbabilities) << "." << std::endl;
eliminateState ( transitionMatrix , oneStepProbabilities , state , backwardTransitions , stateRewards , priorityQueue . get ( ) ) ;
oneStepProbabilities [ state ] = storm : : utility : : zero < ValueType > ( ) ;
STORM_LOG_ASSERT ( checkConsistent ( transitionMatrix , backwardTransitions ) , " The forward and backward transition matrices became inconsistent. " ) ;
}
std : : unique_ptr < StatePriorityQueue > statePriorities = createStatePriorityQueue ( distanceBasedPriorities , transitionMatrix , backwardTransitions , oneStepProbabilities , states ) ;
}
template < typename SparseDtmcModelType >
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : performOrdinaryStateElimination ( FlexibleSparseMatrix & transitionMatrix , FlexibleSparseMatrix & backwardTransitions , storm : : storage : : BitVector const & subsystem , storm : : storage : : BitVector const & initialStates , std : : vector < typename SparseDtmcModelType : : ValueType > & oneStepProbabilities , boost : : optional < std : : vector < ValueType > > & stateRewards , boost : : optional < std : : vector < uint_fast64_t > > const & distanceBasedPriorities ) {
std : : unique_ptr < StatePriorityQueue > statePriorities = createStatePriorityQueue ( distanceBasedPriorities , transitionMatrix , backwardTransitions , oneStepProbabilities , subsystem & ~ initialStates ) ;
std : : size_t numberOfStatesToEliminate = statePriorities - > size ( ) ;
STORM_LOG_DEBUG ( " Eliminating " < < numberOfStatesToEliminate < < " states using the state elimination technique. " < < std : : endl ) ;
for ( auto const & state : states ) {
eliminateState ( transitionMatrix , oneStepProbabilities , state , backwardTransitions , stateRewards ) ;
}
performPrioritizedStateElimination ( statePriorities , transitionMatrix , backwardTransitions , oneStepProbabilities , stateRewards ) ;
STORM_LOG_DEBUG ( " Eliminated " < < numberOfStatesToEliminate < < " states. " < < std : : endl ) ;
}
template < typename SparseDtmcModelType >
uint_fast64_t SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : performHybridStateElimination ( storm : : storage : : SparseMatrix < ValueType > const & forwardTransitions , FlexibleSparseMatrix & transitionMatrix , FlexibleSparseMatrix & backwardTransitions , storm : : storage : : BitVector const & subsystem , storm : : storage : : BitVector const & initialStates , std : : vector < typename SparseDtmcModelType : : ValueType > & oneStepProbabilities , boost : : optional < std : : vector < ValueType > > & stateRewards , boost : : optional < std : : vector < uint_fast64_t > > const & distanceBasedPriorities ) {
// When using the hybrid technique, we recursively treat the SCCs up to some size.
std : : vector < storm : : storage : : sparse : : state_type > entryStateQueue ;
STORM_LOG_DEBUG ( " Eliminating " < < subsystem . size ( ) < < " states using the hybrid elimination technique. " < < std : : endl ) ;
uint_fast64_t maximalDepth = treatScc ( transitionMatrix , oneStepProbabilities , initialStates , subsystem , forwardTransitions , backwardTransitions , false , 0 , storm : : settings : : sparseDtmcEliminationModelCheckerSettings ( ) . getMaximalSccSize ( ) , entryStateQueue , stateRewards , distanceBasedPriorities ) ;
// If the entry states were to be eliminated last, we need to do so now.
STORM_LOG_DEBUG ( " Eliminating " < < entryStateQueue . size ( ) < < " entry states as a last step. " ) ;
if ( storm : : settings : : sparseDtmcEliminationModelCheckerSettings ( ) . isEliminateEntryStatesLastSet ( ) ) {
for ( auto const & state : entryStateQueue ) {
eliminateState ( transitionMatrix , oneStepProbabilities , state , backwardTransitions , stateRewards ) ;
}
}
STORM_LOG_DEBUG ( " Eliminated " < < subsystem . size ( ) < < " states. " < < std : : endl ) ;
return maximalDepth ;
}
template < typename SparseDtmcModelType >
@ -502,7 +540,7 @@ namespace storm {
std : : chrono : : high_resolution_clock : : time_point conversionStart = std : : chrono : : high_resolution_clock : : now ( ) ;
// Then, we convert the reduced matrix to a more flexible format to be able to perform state elimination more easily.
FlexibleSparseMatrix flexibleMatrix = getFlexibleSparseMatrix ( transitionMatrix ) ;
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix ( backwardTransitions , true ) ;
FlexibleSparseMatrix flexibleBackwardTransitions = getFlexibleSparseMatrix ( backwardTransitions ) ;
auto conversionEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : chrono : : high_resolution_clock : : time_point modelCheckingStart = std : : chrono : : high_resolution_clock : : now ( ) ;
@ -514,26 +552,21 @@ namespace storm {
eliminationOrderNeedsForwardDistances ( order ) , eliminationOrderNeedsReversedDistances ( order ) ) ;
}
// Create a bit vector that represents the subsystem of states we still have to eliminate.
storm : : storage : : BitVector subsystem = storm : : storage : : BitVector ( transitionMatrix . getRowCount ( ) , true ) ;
uint_fast64_t maximalDepth = 0 ;
if ( storm : : settings : : sparseDtmcEliminationModelCheckerSettings ( ) . getEliminationMethod ( ) = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationMethod : : State ) {
performOrdinaryStateElimination ( flexibleMatrix , flexibleBackwardTransitions , * initialStates . begin ( ) , oneStepProbabilities , stateRewards , distanceBasedPriorities ) ;
performOrdinaryStateElimination ( flexibleMatrix , flexibleBackwardTransitions , subsystem , initialStates , oneStepProbabilities , stateRewards , distanceBasedPriorities ) ;
} else if ( storm : : settings : : sparseDtmcEliminationModelCheckerSettings ( ) . getEliminationMethod ( ) = = storm : : settings : : modules : : SparseDtmcEliminationModelCheckerSettings : : EliminationMethod : : Hybrid ) {
// Create a bit vector that represents the subsystem of states we still have to eliminate.
storm : : storage : : BitVector subsystem = storm : : storage : : BitVector ( transitionMatrix . getRowCount ( ) , true ) ;
// When using the hybrid technique, we recursively treat the SCCs up to some size.
std : : vector < storm : : storage : : sparse : : state_type > entryStateQueue ;
STORM_LOG_DEBUG ( " Eliminating " < < subsystem . size ( ) < < " states using the hybrid elimination technique. " < < std : : endl ) ;
maximalDepth = treatScc ( flexibleMatrix , oneStepProbabilities , initialStates , subsystem , transitionMatrix , flexibleBackwardTransitions , false , 0 , storm : : settings : : sparseDtmcEliminationModelCheckerSettings ( ) . getMaximalSccSize ( ) , entryStateQueue , stateRewards , distanceBasedPriorities ) ;
// If the entry states were to be eliminated last, we need to do so now.
STORM_LOG_DEBUG ( " Eliminating " < < entryStateQueue . size ( ) < < " entry states as a last step. " ) ;
if ( storm : : settings : : sparseDtmcEliminationModelCheckerSettings ( ) . isEliminateEntryStatesLastSet ( ) ) {
for ( auto const & state : entryStateQueue ) {
eliminateState ( flexibleMatrix , oneStepProbabilities , state , flexibleBackwardTransitions , stateRewards ) ;
}
}
STORM_LOG_DEBUG ( " Eliminated " < < subsystem . size ( ) < < " states. " < < std : : endl ) ;
maximalDepth = performHybridStateElimination ( transitionMatrix , flexibleMatrix , flexibleBackwardTransitions , subsystem , initialStates , oneStepProbabilities , stateRewards , distanceBasedPriorities ) ;
}
// Make sure that at this point, we have at most one transition and if so, it must be a self-loop. Otherwise,
// something went wrong.
if ( ! flexibleMatrix . getRow ( * initialStates . begin ( ) ) . empty ( ) ) {
STORM_LOG_ASSERT ( flexibleMatrix . getRow ( * initialStates . begin ( ) ) . size ( ) = = 1 , " At most one outgoing transition expected at this point, but found more. " ) ;
STORM_LOG_ASSERT ( flexibleMatrix . getRow ( * initialStates . begin ( ) ) . front ( ) . getColumn ( ) = = * initialStates . begin ( ) , " Remaining entry should be a self-loop, but it is not. " ) ;
}
// Finally eliminate initial state.
@ -550,8 +583,6 @@ namespace storm {
// of the initial state, this amounts to checking whether the outgoing transitions of the initial
// state are non-empty.
if ( ! flexibleMatrix . getRow ( * initialStates . begin ( ) ) . empty ( ) ) {
STORM_LOG_ASSERT ( flexibleMatrix . getRow ( * initialStates . begin ( ) ) . size ( ) = = 1 , " At most one outgoing transition expected at this point, but found more. " ) ;
STORM_LOG_ASSERT ( flexibleMatrix . getRow ( * initialStates . begin ( ) ) . front ( ) . getColumn ( ) = = * initialStates . begin ( ) , " Remaining entry should be a self-loop, but it is not. " ) ;
ValueType loopProbability = flexibleMatrix . getRow ( * initialStates . begin ( ) ) . front ( ) . getValue ( ) ;
loopProbability = storm : : utility : : one < ValueType > ( ) / ( storm : : utility : : one < ValueType > ( ) - loopProbability ) ;
STORM_LOG_DEBUG ( " Scaling the reward of the initial state " < < stateRewards . get ( ) [ ( * initialStates . begin ( ) ) ] < < " with " < < loopProbability ) ;
@ -614,27 +645,21 @@ namespace storm {
storm : : storage : : BitVector remainingSccs ( decomposition . size ( ) , true ) ;
// First, get rid of the trivial SCCs.
std : : vector < std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > > trivialSccs ;
storm : : storage : : BitVector statesInTrivialSccs ( matrix . getNumberOfRows ( ) ) ;
for ( uint_fast64_t sccIndex = 0 ; sccIndex < decomposition . size ( ) ; + + sccIndex ) {
storm : : storage : : StronglyConnectedComponent const & scc = decomposition . getBlock ( sccIndex ) ;
if ( scc . isTrivial ( ) ) {
storm : : storage : : sparse : : state_type onlyState = * scc . begin ( ) ;
trivialSccs . emplace_back ( onlyState , sccIndex ) ;
// Put the only state of the trivial SCC into the set of states to eliminate.
statesInTrivialSccs . set ( * scc . begin ( ) , true ) ;
remainingSccs . set ( sccIndex , false ) ;
}
}
// If we are given priorities, sort the trivial SCCs accordingly.
if ( distanceBasedPriorities ) {
std : : sort ( trivialSccs . begin ( ) , trivialSccs . end ( ) , [ & distanceBasedPriorities ] ( std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > const & a , std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > const & b ) { return distanceBasedPriorities . get ( ) [ a . first ] < distanceBasedPriorities . get ( ) [ b . first ] ; } ) ;
}
STORM_LOG_TRACE ( " Eliminating " < < trivialSccs . size ( ) < < " trivial SCCs. " ) ;
for ( auto const & stateIndexPair : trivialSccs ) {
eliminateState ( matrix , oneStepProbabilities , stateIndexPair . first , backwardTransitions , stateRewards ) ;
remainingSccs . set ( stateIndexPair . second , false ) ;
}
std : : unique_ptr < StatePriorityQueue > statePriorities = createStatePriorityQueue ( distanceBasedPriorities , matrix , backwardTransitions , oneStepProbabilities , statesInTrivialSccs ) ;
STORM_LOG_TRACE ( " Eliminating " < < statePriorities - > size ( ) < < " trivial SCCs. " ) ;
performPrioritizedStateElimination ( statePriorities , matrix , backwardTransitions , oneStepProbabilities , stateRewards ) ;
STORM_LOG_TRACE ( " Eliminated all trivial SCCs. " ) ;
// And then recursively treat the remaining sub-SCCs.
STORM_LOG_TRACE ( " Eliminating " < < remainingSccs . getNumberOfSetBits ( ) < < " remaining SCCs on level " < < level < < " . " ) ;
for ( auto sccIndex : remainingSccs ) {
@ -657,25 +682,11 @@ namespace storm {
uint_fast64_t depth = treatScc ( matrix , oneStepProbabilities , entryStates , newSccAsBitVector , forwardTransitions , backwardTransitions , eliminateEntryStates | | ! storm : : settings : : sparseDtmcEliminationModelCheckerSettings ( ) . isEliminateEntryStatesLastSet ( ) , level + 1 , maximalSccSize , entryStateQueue , stateRewards , distanceBasedPriorities ) ;
maximalDepth = std : : max ( maximalDepth , depth ) ;
}
} else {
// In this case, we perform simple state elimination in the current SCC.
STORM_LOG_TRACE ( " SCC of size " < < scc . getNumberOfSetBits ( ) < < " is small enough to be eliminated directly. " ) ;
storm : : storage : : BitVector remainingStates = scc & ~ entryStates ;
std : : vector < uint_fast64_t > states ( remainingStates . begin ( ) , remainingStates . end ( ) ) ;
// If we are given priorities, sort the trivial SCCs accordingly.
if ( distanceBasedPriorities ) {
std : : sort ( states . begin ( ) , states . end ( ) , [ & distanceBasedPriorities ] ( storm : : storage : : sparse : : state_type const & a , storm : : storage : : sparse : : state_type const & b ) { return distanceBasedPriorities . get ( ) [ a ] < distanceBasedPriorities . get ( ) [ b ] ; } ) ;
}
// Eliminate the remaining states that do not have a self-loop (in the current, i.e. modified)
// transition probability matrix.
for ( auto const & state : states ) {
eliminateState ( matrix , oneStepProbabilities , state , backwardTransitions , stateRewards ) ;
}
std : : unique_ptr < StatePriorityQueue > statePriorities = createStatePriorityQueue ( distanceBasedPriorities , matrix , backwardTransitions , oneStepProbabilities , scc & ~ entryStates ) ;
performPrioritizedStateElimination ( statePriorities , matrix , backwardTransitions , oneStepProbabilities , stateRewards ) ;
STORM_LOG_TRACE ( " Eliminated all states of SCC. " ) ;
}
@ -696,7 +707,7 @@ namespace storm {
}
template < typename SparseDtmcModelType >
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : eliminateState ( FlexibleSparseMatrix & matrix , std : : vector < ValueType > & oneStepProbabilities , uint_fast64_t state , FlexibleSparseMatrix & backwardTransitions , boost : : optional < std : : vector < ValueType > > & stateRewards , bool removeForwardTransitions , bool constrained , storm : : storage : : BitVector const & predecessorConstraint ) {
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : eliminateState ( FlexibleSparseMatrix & matrix , std : : vector < ValueType > & oneStepProbabilities , uint_fast64_t state , FlexibleSparseMatrix & backwardTransitions , boost : : optional < std : : vector < ValueType > > & stateRewards , StatePriorityQueue * priorityQueue , bool removeForwardTransitions , bool constrained , storm : : storage : : BitVector const & predecessorConstraint ) {
STORM_LOG_TRACE ( " Eliminating state " < < state < < " . " ) ;
@ -746,11 +757,17 @@ namespace storm {
// In case we have a constrained elimination, we need to keep track of the new predecessors.
typename FlexibleSparseMatrix : : row_type newCurrentStatePredecessors ;
std : : vector < typename FlexibleSparseMatrix : : row_type > newBackwardProbabilities ( currentStateSuccessors . size ( ) ) ;
for ( auto & backwardProbabilities : newBackwardProbabilities ) {
backwardProbabilities . reserve ( currentStatePredecessors . size ( ) ) ;
}
// Now go through the predecessors and eliminate the ones (satisfying the constraint if given).
for ( auto const & predecessorEntry : currentStatePredecessors ) {
uint_fast64_t predecessor = predecessorEntry . getColumn ( ) ;
STORM_LOG_TRACE ( " Found predecessor " < < predecessor < < " . " ) ;
// Skip the state itself as one of its predecessors.
if ( predecessor = = state ) {
assert ( hasSelfLoop ) ;
@ -759,7 +776,7 @@ namespace storm {
// Skip the state if the elimination is constrained, but the predecessor is not in the constraint.
if ( constrained & & ! predecessorConstraint . get ( predecessor ) ) {
newCurrentStatePredecessors . emplace_back ( predecessor , storm : : utility : : one < ValueType > ( ) ) ;
newCurrentStatePredecessors . emplace_back ( predecessorEntry ) ;
STORM_LOG_TRACE ( " Not eliminating predecessor " < < predecessor < < " , because it does not fit the filter. " ) ;
continue ;
}
@ -785,6 +802,7 @@ namespace storm {
newSuccessors . reserve ( ( last1 - first1 ) + ( last2 - first2 ) ) ;
std : : insert_iterator < typename FlexibleSparseMatrix : : row_type > result ( newSuccessors , newSuccessors . end ( ) ) ;
uint_fast64_t successorOffsetInNewBackwardTransitions = 0 ;
// Now we merge the two successor lists. (Code taken from std::set_union and modified to suit our needs).
for ( ; first1 ! = last1 ; + + result ) {
// Skip the transitions to the state that is currently being eliminated.
@ -803,30 +821,41 @@ namespace storm {
break ;
}
if ( first2 - > getColumn ( ) < first1 - > getColumn ( ) ) {
* result = storm : : utility : : simplify ( std : : move ( * first2 * multiplyFactor ) ) ;
auto successorEntry = storm : : utility : : simplify ( std : : move ( * first2 * multiplyFactor ) ) ;
* result = successorEntry ;
newBackwardProbabilities [ successorOffsetInNewBackwardTransitions ] . emplace_back ( predecessor , successorEntry . getValue ( ) ) ;
// std::cout << "(1) adding " << newBackwardProbabilities[successorOffsetInNewBackwardTransitions].back() << std::endl;
+ + first2 ;
+ + successorOffsetInNewBackwardTransitions ;
} else if ( first1 - > getColumn ( ) < first2 - > getColumn ( ) ) {
* result = * first1 ;
+ + first1 ;
} else {
* result = storm : : storage : : MatrixEntry < typename FlexibleSparseMatrix : : index_type , typename FlexibleSparseMatrix : : value_type > ( first1 - > getColumn ( ) , storm : : utility : : simplify ( first1 - > getValue ( ) + storm : : utility : : simplify ( multiplyFactor * first2 - > getValue ( ) ) ) ) ;
auto probability = storm : : utility : : simplify ( first1 - > getValue ( ) + storm : : utility : : simplify ( multiplyFactor * first2 - > getValue ( ) ) ) ;
* result = storm : : storage : : MatrixEntry < typename FlexibleSparseMatrix : : index_type , typename FlexibleSparseMatrix : : value_type > ( first1 - > getColumn ( ) , probability ) ;
newBackwardProbabilities [ successorOffsetInNewBackwardTransitions ] . emplace_back ( predecessor , probability ) ;
// std::cout << "(2) adding " << newBackwardProbabilities[successorOffsetInNewBackwardTransitions].back() << std::endl;
+ + first1 ;
+ + first2 ;
+ + successorOffsetInNewBackwardTransitions ;
}
}
for ( ; first2 ! = last2 ; + + first2 ) {
for ( ; first2 ! = last2 ; + + first2 , + + successorOffsetInNewBackwardTransitions ) {
if ( first2 - > getColumn ( ) ! = state ) {
* result = storm : : utility : : simplify ( std : : move ( * first2 * multiplyFactor ) ) ;
auto stateProbability = storm : : utility : : simplify ( std : : move ( * first2 * multiplyFactor ) ) ;
* result = stateProbability ;
newBackwardProbabilities [ successorOffsetInNewBackwardTransitions ] . emplace_back ( predecessor , stateProbability . getValue ( ) ) ;
// std::cout << "(3) adding " << newBackwardProbabilities[successorOffsetInNewBackwardTransitions].back() << std::endl;
}
}
// Now move the new transitions in place.
predecessorForwardTransitions = std : : move ( newSuccessors ) ;
STORM_LOG_TRACE ( " Fixed new next-state probabilities of predecessor state " < < predecessor < < " . " ) ;
if ( ! stateRewards ) {
// Add the probabilities to go to a target state in just one step if we have to compute probabilities.
oneStepProbabilities [ predecessor ] + = storm : : utility : : simplify ( multiplyFactor * oneStepProbabilities [ state ] ) ;
STORM_LOG_TRACE ( " Fixed new next-state probabilities of predecessor states. " ) ;
} else {
// If we are computing rewards, we basically scale the state reward of the state to eliminate and
// add the result to the state reward of the predecessor.
@ -836,75 +865,71 @@ namespace storm {
stateRewards . get ( ) [ predecessor ] + = storm : : utility : : simplify ( multiplyFactor * stateRewards . get ( ) [ state ] ) ;
}
}
if ( priorityQueue ! = nullptr ) {
STORM_LOG_TRACE ( " Updating priority of predecessor. " ) ;
priorityQueue - > update ( predecessor , matrix , backwardTransitions , oneStepProbabilities ) ;
}
}
// Finally, we need to add the predecessor to the set of predecessors of every successor.
uint_fast64_t successorOffsetInNewBackwardTransitions = 0 ;
for ( auto const & successorEntry : currentStateSuccessors ) {
if ( successorEntry . getColumn ( ) = = state ) {
continue ;
}
typename FlexibleSparseMatrix : : row_type & successorBackwardTransitions = backwardTransitions . getRow ( successorEntry . getColumn ( ) ) ;
// Delete the current state as a predecessor of the successor state only if we are going to remove the
// current state's forward transitions.
if ( removeForwardTransitions ) {
typename FlexibleSparseMatrix : : row_type : : iterator elimIt = std : : find_if ( successorBackwardTransitions . begin ( ) , successorBackwardTransitions . end ( ) , [ & ] ( storm : : storage : : MatrixEntry < typename FlexibleSparseMatrix : : index_type , typename FlexibleSparseMatrix : : value_type > const & a ) { return a . getColumn ( ) = = state ; } ) ;
STORM_LOG_ASSERT ( elimIt ! = successorBackwardTransitions . end ( ) , " Expected a proper backward transition, but found none. " ) ;
STORM_LOG_ASSERT ( elimIt ! = successorBackwardTransitions . end ( ) , " Expected a proper backward transition from " < < successorEntry . getColumn ( ) < < " to " < < state < < " , but found none. " ) ;
successorBackwardTransitions . erase ( elimIt ) ;
}
typename FlexibleSparseMatrix : : row_type : : iterator first1 = successorBackwardTransitions . begin ( ) ;
typename FlexibleSparseMatrix : : row_type : : iterator last1 = successorBackwardTransitions . end ( ) ;
typename FlexibleSparseMatrix : : row_type : : iterator first2 = currentStatePredecessors . begin ( ) ;
typename FlexibleSparseMatrix : : row_type : : iterator last2 = currentStatePredecessors . end ( ) ;
typename FlexibleSparseMatrix : : row_type : : iterator first2 = newBackwardProbabilities [ successorOffsetInNewBackwardTransitions ] . begin ( ) ;
typename FlexibleSparseMatrix : : row_type : : iterator last2 = newBackwardProbabilities [ successorOffsetInNewBackwardTransitions ] . end ( ) ;
typename FlexibleSparseMatrix : : row_type newPredecessors ;
newPredecessors . reserve ( ( last1 - first1 ) + ( last2 - first2 ) ) ;
std : : insert_iterator < typename FlexibleSparseMatrix : : row_type > result ( newPredecessors , newPredecessors . end ( ) ) ;
if ( ! constrained ) {
for ( ; first1 ! = last1 ; + + result ) {
if ( first2 = = last2 ) {
std : : copy ( first1 , last1 , result ) ;
break ;
}
if ( first2 - > getColumn ( ) < first1 - > getColumn ( ) ) {
if ( first2 - > getColumn ( ) ! = state ) {
* result = * first2 ;
}
+ + first2 ;
} else {
* result = * first1 ;
if ( first1 - > getColumn ( ) = = first2 - > getColumn ( ) ) {
+ + first2 ;
}
+ + first1 ;
}
for ( ; first1 ! = last1 ; + + result ) {
if ( first2 = = last2 ) {
std : : copy ( first1 , last1 , result ) ;
break ;
}
std : : copy_if ( first2 , last2 , result , [ & ] ( storm : : storage : : MatrixEntry < typename FlexibleSparseMatrix : : index_type , typename FlexibleSparseMatrix : : value_type > const & a ) { return a . getColumn ( ) ! = state ; } ) ;
} else {
// If the elimination is constrained, we need to be more selective when we set the new predecessors
// of the successor state.
for ( ; first1 ! = last1 ; + + result ) {
if ( first2 = = last2 ) {
std : : copy ( first1 , last1 , result ) ;
break ;
if ( first2 - > getColumn ( ) < first1 - > getColumn ( ) ) {
if ( first2 - > getColumn ( ) ! = state ) {
* result = * first2 ;
}
if ( first2 - > getColumn ( ) < first1 - > getColumn ( ) ) {
if ( first2 - > getColumn ( ) ! = state ) {
* result = * first2 ;
}
+ + first2 ;
} else {
+ + first2 ;
} else if ( first1 - > getColumn ( ) = = first2 - > getColumn ( ) ) {
if ( estimateComplexity ( first1 - > getValue ( ) ) > estimateComplexity ( first2 - > getValue ( ) ) ) {
* result = * first1 ;
if ( first1 - > getColumn ( ) = = first2 - > getColumn ( ) ) {
+ + first2 ;
}
+ + first1 ;
} else {
* result = * first2 ;
}
+ + first1 ;
+ + first2 ;
} else {
* result = * first1 ;
+ + first1 ;
}
}
if ( constrained ) {
std : : copy_if ( first2 , last2 , result , [ & ] ( storm : : storage : : MatrixEntry < typename FlexibleSparseMatrix : : index_type , typename FlexibleSparseMatrix : : value_type > const & a ) { return a . getColumn ( ) ! = state & & ( ! constrained | | predecessorConstraint . get ( a . getColumn ( ) ) ) ; } ) ;
} else {
std : : copy_if ( first2 , last2 , result , [ & ] ( storm : : storage : : MatrixEntry < typename FlexibleSparseMatrix : : index_type , typename FlexibleSparseMatrix : : value_type > const & a ) { return a . getColumn ( ) ! = state ; } ) ;
}
// Now move the new predecessors in place.
successorBackwardTransitions = std : : move ( newPredecessors ) ;
+ + successorOffsetInNewBackwardTransitions ;
}
STORM_LOG_TRACE ( " Fixed predecessor lists of successor states. " ) ;
@ -1043,48 +1068,40 @@ namespace storm {
return flexibleMatrix ;
}
template < typename ValueType >
uint_fast64_t estimateComplexity ( ValueType const & value ) {
return 1 ;
}
template < >
uint_fast64_t estimateComplexity ( storm : : RationalFunction const & value ) {
if ( storm : : utility : : isConstant ( value ) ) {
return 1 ;
}
if ( value . denominator ( ) . isConstant ( ) ) {
return 10 * value . nominator ( ) . totalDegree ( ) ;
} else {
return 100 * std : : pow ( value . denominator ( ) . totalDegree ( ) , 2 ) + value . nominator ( ) . totalDegree ( ) ;
}
}
template < typename SparseDtmcModelType >
uint_fast64_t SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : computeStatePenalty ( storm : : storage : : sparse : : state_type const & state , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions , std : : vector < typename SparseDtmcModelType : : ValueType > & oneStepProbabilities ) {
uint_fast64_t SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : computeStatePenalty ( storm : : storage : : sparse : : state_type const & state , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions , std : : vector < ValueType > const & oneStepProbabilities ) {
uint_fast64_t penalty = 0 ;
bool hasParametricSelfLoop = false ;
for ( auto const & predecessor : backwardTransitions . getRow ( state ) ) {
for ( auto const & successor : transitionMatrix . getRow ( state ) ) {
penalty + = estimateComplexity ( predecessor . getValue ( ) ) * estimateComplexity ( successor . getValue ( ) ) ;
// STORM_LOG_TRACE("1) penalty += " << (estimateComplexity(predecessor.getValue()) * estimateComplexity(successor.getValue())) << " because of " << predecessor.getValue() << " and " << successor.getValue() << ".");
}
if ( predecessor . getColumn ( ) = = state ) {
hasParametricSelfLoop = ! storm : : utility : : isConstant ( predecessor . getValue ( ) ) ;
}
penalty + = estimateComplexity ( oneStepProbabilities [ predecessor . getColumn ( ) ] ) * estimateComplexity ( predecessor . getValue ( ) ) * estimateComplexity ( oneStepProbabilities [ state ] ) ;
// STORM_LOG_TRACE("2) penalty += " << (estimateComplexity(oneStepProbabilities[predecessor.getColumn()]) * estimateComplexity(predecessor.getValue()) * estimateComplexity(oneStepProbabilities[state])) << " because of " << oneStepProbabilities[predecessor.getColumn()] << ", " << predecessor.getValue() << " and " << oneStepProbabilities[state] << ".");
}
// If it is a self-loop that is parametric, we increase the penalty a lot.
if ( hasParametricSelfLoop ) {
penalty * = 1000 ;
penalty * = 10 ;
// STORM_LOG_TRACE("3) penalty *= 100, because of parametric self-loop.");
}
// STORM_LOG_TRACE("New penalty of state " << state << " is " << penalty << ".");
return penalty ;
}
template < typename SparseDtmcModelType >
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : StatePriorityQueue : : update ( storm : : storage : : sparse : : state_type , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions ) {
uint_fast64_t SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : computeStatePenaltyRegularExpression ( storm : : storage : : sparse : : state_type const & state , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions , std : : vector < ValueType > const & oneStepProbabilities ) {
return backwardTransitions . getRow ( state ) . size ( ) * transitionMatrix . getRow ( state ) . size ( ) ;
}
template < typename SparseDtmcModelType >
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : StatePriorityQueue : : update ( storm : : storage : : sparse : : state_type , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions , std : : vector < ValueType > const & oneStepProbabilities ) {
// Intentionally left empty.
}
@ -1110,12 +1127,16 @@ namespace storm {
}
template < typename SparseDtmcModelType >
SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : DynamicPenaltyStatePriorityQueue : : DynamicPenaltyStatePriorityQueue ( std : : vector < std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > > const & sortedStatePenaltyPairs ) : StatePriorityQueue ( ) , priorityQueue ( ) {
SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : DynamicPenaltyStatePriorityQueue : : DynamicPenaltyStatePriorityQueue ( std : : vector < std : : pair < storm : : storage : : sparse : : state_type , uint_fast64_t > > const & sortedStatePenaltyPairs , PenaltyFunctionType const & penaltyFunction ) : StatePriorityQueue ( ) , priorityQueue ( ) , stateToPriorityMapping ( ) , penaltyFunction ( penaltyFunction ) {
// Insert all state-penalty pairs into our priority queue.
for ( auto const & statePenalty : sortedStatePenaltyPairs ) {
priorityQueue . insert ( priorityQueue . end ( ) , statePenalty ) ;
}
// Insert all state-penalty pairs into auxiliary mapping.
for ( auto const & statePenalty : sortedStatePenaltyPairs ) {
stateToPriorityMapping . emplace ( statePenalty ) ;
}
}
template < typename SparseDtmcModelType >
@ -1125,14 +1146,35 @@ namespace storm {
template < typename SparseDtmcModelType >
storm : : storage : : sparse : : state_type SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : DynamicPenaltyStatePriorityQueue : : popNextState ( ) {
storm : : storage : : sparse : : state_type result = priorityQueue . begin ( ) - > first ;
auto it = priorityQueue . begin ( ) ;
STORM_LOG_TRACE ( " Popping state " < < it - > first < < " with priority " < < it - > second < < " . " ) ;
storm : : storage : : sparse : : state_type result = it - > first ;
priorityQueue . erase ( priorityQueue . begin ( ) ) ;
return result ;
}
template < typename SparseDtmcModelType >
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : DynamicPenaltyStatePriorityQueue : : update ( storm : : storage : : sparse : : state_type , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions ) {
// FIXME: update needed.
void SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : DynamicPenaltyStatePriorityQueue : : update ( storm : : storage : : sparse : : state_type state , FlexibleSparseMatrix const & transitionMatrix , FlexibleSparseMatrix const & backwardTransitions , std : : vector < ValueType > const & oneStepProbabilities ) {
// First, we need to find the priority until now.
auto priorityIt = stateToPriorityMapping . find ( state ) ;
// If the priority queue does not store the priority of the given state, we must not update it.
if ( priorityIt = = stateToPriorityMapping . end ( ) ) {
return ;
}
uint_fast64_t lastPriority = priorityIt - > second ;
uint_fast64_t newPriority = penaltyFunction ( state , transitionMatrix , backwardTransitions , oneStepProbabilities ) ;
if ( lastPriority ! = newPriority ) {
// Erase and re-insert into the priority queue with the new priority.
auto queueIt = priorityQueue . find ( std : : make_pair ( state , lastPriority ) ) ;
priorityQueue . erase ( queueIt ) ;
priorityQueue . emplace ( state , newPriority ) ;
// Finally, update the probability in the mapping.
priorityIt - > second = newPriority ;
}
}
template < typename SparseDtmcModelType >
@ -1140,6 +1182,30 @@ namespace storm {
return priorityQueue . size ( ) ;
}
template < typename SparseDtmcModelType >
bool SparseDtmcEliminationModelChecker < SparseDtmcModelType > : : checkConsistent ( FlexibleSparseMatrix & transitionMatrix , FlexibleSparseMatrix & backwardTransitions ) {
for ( uint_fast64_t forwardIndex = 0 ; forwardIndex < transitionMatrix . getNumberOfRows ( ) ; + + forwardIndex ) {
for ( auto const & forwardEntry : transitionMatrix . getRow ( forwardIndex ) ) {
if ( forwardEntry . getColumn ( ) = = forwardIndex ) {
continue ;
}
bool foundCorrespondingElement = false ;
for ( auto const & backwardEntry : backwardTransitions . getRow ( forwardEntry . getColumn ( ) ) ) {
if ( backwardEntry . getColumn ( ) = = forwardIndex ) {
foundCorrespondingElement = true ;
}
}
if ( ! foundCorrespondingElement ) {
std : : cout < < " forward entry: " < < forwardEntry < < std : : endl ;
return false ;
}
}
}
return true ;
}
template class SparseDtmcEliminationModelChecker < storm : : models : : sparse : : Dtmc < double > > ;
# ifdef STORM_HAVE_CARL