@ -1,6 +1,7 @@
# include "src/modelchecker/prctl/SparseDtmcPrctlModelChecker.h"
# include <vector>
# include <memory>
# include "src/utility/macros.h"
# include "src/utility/vector.h"
@ -9,6 +10,8 @@
# include "src/modelchecker/results/ExplicitQualitativeCheckResult.h"
# include "src/modelchecker/results/ExplicitQuantitativeCheckResult.h"
# include "src/storage/StronglyConnectedComponentDecomposition.h"
# include "src/exceptions/InvalidPropertyException.h"
namespace storm {
@ -297,6 +300,132 @@ namespace storm {
return std : : unique_ptr < CheckResult > ( new ExplicitQuantitativeCheckResult < ValueType > ( this - > computeReachabilityRewardsHelper ( subResult . getTruthValuesVector ( ) , qualitative ) ) ) ;
}
template < typename ValueType >
std : : vector < ValueType > SparseDtmcPrctlModelChecker < ValueType > : : computeLongRunAverageHelper ( bool minimize , storm : : storage : : BitVector const & psiStates , bool qualitative ) const {
// If there are no goal states, we avoid the computation and directly return zero.
auto numOfStates = this - > getModel ( ) . getNumberOfStates ( ) ;
if ( psiStates . empty ( ) ) {
return std : : vector < ValueType > ( numOfStates , storm : : utility : : zero < ValueType > ( ) ) ;
}
// Likewise, if all bits are set, we can avoid the computation and set.
if ( ( ~ psiStates ) . empty ( ) ) {
return std : : vector < ValueType > ( numOfStates , storm : : utility : : one < ValueType > ( ) ) ;
}
// Start by decomposing the DTMC into its BSCCs.
storm : : storage : : StronglyConnectedComponentDecomposition < double > bsccDecomposition ( this - > getModelAs < storm : : models : : AbstractModel < ValueType > > ( ) , false , true ) ;
// Get some data members for convenience.
typename storm : : storage : : SparseMatrix < ValueType > const & transitionMatrix = this - > getModel ( ) . getTransitionMatrix ( ) ;
// Now start with compute the long-run average for all BSCCs in isolation.
std : : vector < ValueType > lraValuesForBsccs ;
// While doing so, we already gather some information for the following steps.
std : : vector < uint_fast64_t > stateToBsccIndexMap ( numOfStates ) ;
storm : : storage : : BitVector statesInBsccs ( numOfStates ) ;
for ( uint_fast64_t currentBsccIndex = 0 ; currentBsccIndex < bsccDecomposition . size ( ) ; + + currentBsccIndex ) {
storm : : storage : : StronglyConnectedComponent const & bscc = bsccDecomposition [ currentBsccIndex ] ;
// Gather information for later use.
for ( auto const & state : bscc ) {
statesInBsccs . set ( state ) ;
stateToBsccIndexMap [ state ] = currentBsccIndex ;
}
// Compute the LRA value for the current BSCC
lraValuesForBsccs . push_back ( this - > computeLraForBSCC ( transitionMatrix , psiStates , bscc ) ) ;
}
// For fast transition rewriting, we build some auxiliary data structures.
storm : : storage : : BitVector statesNotContainedInAnyBscc = ~ statesInBsccs ;
// Prepare result vector.
std : : vector < ValueType > result ( numOfStates ) ;
//Set the values for all states in BSCCs.
for ( auto state : statesInBsccs ) {
result [ state ] = lraValuesForBsccs [ stateToBsccIndexMap [ state ] ] ;
}
//for all states not in any bscc set the result to the minimal/maximal value of the reachable BSCCs
//there might be a more efficient way to do this...
for ( auto state : statesNotContainedInAnyBscc ) {
//calculate what result values the reachable states in BSCCs have
storm : : storage : : BitVector currentState ( numOfStates ) ;
currentState . set ( state ) ;
storm : : storage : : BitVector reachableStates = storm : : utility : : graph : : getReachableStates (
transitionMatrix , currentState , storm : : storage : : BitVector ( numOfStates , true ) , statesInBsccs
) ;
storm : : storage : : BitVector reachableBsccStates = statesInBsccs & reachableStates ;
std : : vector < ValueType > reachableResults ( reachableBsccStates . getNumberOfSetBits ( ) ) ;
storm : : utility : : vector : : selectVectorValues ( reachableResults , reachableBsccStates , result ) ;
//now select the minimal/maximal element
if ( minimize ) {
result [ state ] = * std : : min_element ( reachableResults . begin ( ) , reachableResults . end ( ) ) ;
} else {
result [ state ] = * std : : max_element ( reachableResults . begin ( ) , reachableResults . end ( ) ) ;
}
}
return result ;
}
template < typename ValueType >
std : : unique_ptr < CheckResult > SparseDtmcPrctlModelChecker < ValueType > : : computeLongRunAverage ( storm : : logic : : StateFormula const & stateFormula , bool qualitative , boost : : optional < storm : : logic : : OptimalityType > const & optimalityType ) {
STORM_LOG_THROW ( optimalityType , storm : : exceptions : : InvalidArgumentException , " Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model. " ) ;
std : : unique_ptr < CheckResult > subResultPointer = this - > check ( stateFormula ) ;
ExplicitQualitativeCheckResult const & subResult = subResultPointer - > asExplicitQualitativeCheckResult ( ) ;
return std : : unique_ptr < CheckResult > ( new ExplicitQuantitativeCheckResult < ValueType > ( this - > computeLongRunAverageHelper ( optimalityType . get ( ) = = storm : : logic : : OptimalityType : : Minimize , subResult . getTruthValuesVector ( ) , qualitative ) ) ) ;
}
template < typename ValueType >
ValueType SparseDtmcPrctlModelChecker < ValueType > : : computeLraForBSCC ( storm : : storage : : SparseMatrix < ValueType > const & transitionMatrix , storm : : storage : : BitVector const & psiStates , storm : : storage : : StronglyConnectedComponent const & bscc ) {
//if size is one we can immediately derive the result
if ( bscc . size ( ) = = 1 ) {
if ( psiStates . get ( * ( bscc . begin ( ) ) ) ) {
return storm : : utility : : one < ValueType > ( ) ;
} else {
return storm : : utility : : zero < ValueType > ( ) ;
}
}
std : : unique_ptr < storm : : solver : : LinearEquationSolver < ValueType > > solver = storm : : utility : : solver : : getLinearEquationSolver < ValueType > ( ) ;
storm : : storage : : BitVector subsystem = storm : : storage : : BitVector ( transitionMatrix . getRowCount ( ) ) ;
subsystem . set ( bscc . begin ( ) , bscc . end ( ) ) ;
storm : : storage : : SparseMatrix < ValueType > subsystemMatrix = transitionMatrix . getSubmatrix ( false , subsystem , subsystem ) ;
std : : vector < ValueType > steadyStateDist ( subsystemMatrix . getRowCount ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
steadyStateDist [ 0 ] = storm : : utility : : one < ValueType > ( ) ;
solver - > solveEquationSystem ( subsystemMatrix , steadyStateDist , steadyStateDist ) ;
ValueType length = storm : : utility : : zero < ValueType > ( ) ;
for ( auto value : steadyStateDist ) {
length + = value ;
}
storm : : utility : : vector : : scaleVectorInPlace ( steadyStateDist , storm : : utility : : one < ValueType > ( ) / length ) ;
std : : vector < ValueType > steadyStateForPsiStates ( transitionMatrix . getRowCount ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
storm : : utility : : vector : : setVectorValues ( steadyStateForPsiStates , psiStates & subsystem , steadyStateDist ) ;
ValueType result = storm : : utility : : zero < ValueType > ( ) ;
for ( auto value : steadyStateForPsiStates ) {
result + = value ;
}
return result ;
}
template < typename ValueType >
storm : : models : : Dtmc < ValueType > const & SparseDtmcPrctlModelChecker < ValueType > : : getModel ( ) const {
return this - > template getModelAs < storm : : models : : Dtmc < ValueType > > ( ) ;