@ -7,14 +7,18 @@
# include <boost/iterator/transform_iterator.hpp>
# include "src/storage/parameters.h"
# include "src/modelchecker/propositional/SparsePropositionalModelChecker.h"
# include "src/modelchecker/results/ExplicitQualitativeCheckResult.h"
# include "src/utility/graph.h"
# include "src/exceptions/IllegalFunctionCallException.h"
# include "src/exceptions/InvalidOptionException.h"
namespace storm {
namespace storage {
template < typename ValueType >
DeterministicModelBisimulationDecomposition < ValueType > : : Block : : Block ( storm : : storage : : sparse : : state_type begin , storm : : storage : : sparse : : state_type end , Block * prev , Block * next , std : : size_t id , std : : shared_ptr < std : : string > const & label ) : next ( next ) , prev ( prev ) , begin ( begin ) , end ( end ) , markedAsSplitter ( false ) , markedAsPredecessorBlock ( false ) , markedPosition ( begin ) , absorbing ( false ) , id ( id ) , label ( label ) {
DeterministicModelBisimulationDecomposition < ValueType > : : Block : : Block ( storm : : storage : : sparse : : state_type begin , storm : : storage : : sparse : : state_type end , Block * prev , Block * next , std : : size_t id ) : next ( next ) , prev ( prev ) , begin ( begin ) , end ( end ) , markedAsSplitter ( false ) , markedAsPredecessorBlock ( false ) , markedPosition ( begin ) , absorbing ( false ) , id ( id ) {
if ( next ! = nullptr ) {
next - > prev = this ;
}
@ -131,12 +135,12 @@ namespace storm {
typename DeterministicModelBisimulationDecomposition < ValueType > : : Block * DeterministicModelBisimulationDecomposition < ValueType > : : Block : : getPreviousBlockPointer ( ) {
return this - > prev ;
}
template < typename ValueType >
typename DeterministicModelBisimulationDecomposition < ValueType > : : Block * DeterministicModelBisimulationDecomposition < ValueType > : : Block : : getNextBlockPointer ( ) {
return this - > next ;
}
template < typename ValueType >
typename DeterministicModelBisimulationDecomposition < ValueType > : : Block const & DeterministicModelBisimulationDecomposition < ValueType > : : Block : : getPreviousBlock ( ) const {
return * this - > prev ;
@ -170,12 +174,12 @@ namespace storm {
void DeterministicModelBisimulationDecomposition < ValueType > : : Block : : markAsSplitter ( ) {
this - > markedAsSplitter = true ;
}
template < typename ValueType >
void DeterministicModelBisimulationDecomposition < ValueType > : : Block : : unmarkAsSplitter ( ) {
this - > markedAsSplitter = false ;
}
template < typename ValueType >
std : : size_t DeterministicModelBisimulationDecomposition < ValueType > : : Block : : getId ( ) const {
return this - > id ;
@ -191,6 +195,22 @@ namespace storm {
return this - > absorbing ;
}
template < typename ValueType >
void DeterministicModelBisimulationDecomposition < ValueType > : : Block : : setRepresentativeState ( storm : : storage : : sparse : : state_type representativeState ) {
this - > representativeState = representativeState ;
}
template < typename ValueType >
bool DeterministicModelBisimulationDecomposition < ValueType > : : Block : : hasRepresentativeState ( ) const {
return static_cast < bool > ( representativeState ) ;
}
template < typename ValueType >
storm : : storage : : sparse : : state_type DeterministicModelBisimulationDecomposition < ValueType > : : Block : : getRepresentativeState ( ) const {
STORM_LOG_THROW ( representativeState , storm : : exceptions : : InvalidOperationException , " Unable to retrieve representative state for block. " ) ;
return representativeState . get ( ) ;
}
template < typename ValueType >
storm : : storage : : sparse : : state_type DeterministicModelBisimulationDecomposition < ValueType > : : Block : : getMarkedPosition ( ) const {
return this - > markedPosition ;
@ -226,22 +246,6 @@ namespace storm {
return markedAsPredecessorBlock ;
}
template < typename ValueType >
bool DeterministicModelBisimulationDecomposition < ValueType > : : Block : : hasLabel ( ) const {
return this - > label ! = nullptr ;
}
template < typename ValueType >
std : : string const & DeterministicModelBisimulationDecomposition < ValueType > : : Block : : getLabel ( ) const {
STORM_LOG_THROW ( this - > label ! = nullptr , storm : : exceptions : : IllegalFunctionCallException , " Unable to retrieve label of block that has none. " ) ;
return * this - > label ;
}
template < typename ValueType >
std : : shared_ptr < std : : string > const & DeterministicModelBisimulationDecomposition < ValueType > : : Block : : getLabelPtr ( ) const {
return this - > label ;
}
template < typename ValueType >
DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : Partition ( std : : size_t numberOfStates , bool keepSilentProbabilities ) : numberOfBlocks ( 0 ) , stateToBlockMapping ( numberOfStates ) , statesAndValues ( numberOfStates ) , positions ( numberOfStates ) , keepSilentProbabilities ( keepSilentProbabilities ) , silentProbabilities ( ) {
// Create the block and give it an iterator to itself.
@ -262,7 +266,7 @@ namespace storm {
}
template < typename ValueType >
DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : Partition ( std : : size_t numberOfStates , storm : : storage : : BitVector const & prob0States , storm : : storage : : BitVector const & prob1States , std : : string const & otherLabel , std : : string const & prob1Label , bool keepSilentProbabilities ) : numberOfBlocks ( 0 ) , stateToBlockMapping ( numberOfStates ) , statesAndValues ( numberOfStates ) , positions ( numberOfStates ) , keepSilentProbabilities ( keepSilentProbabilities ) , silentProbabilities ( ) {
DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : Partition ( std : : size_t numberOfStates , storm : : storage : : BitVector const & prob0States , storm : : storage : : BitVector const & prob1States , boo st: : optional < storm : : storage : : sparse : : state_type > representativeProb1State , bool keepSilentProbabilities ) : numberOfBlocks ( 0 ) , stateToBlockMapping ( numberOfStates ) , statesAndValues ( numberOfStates ) , positions ( numberOfStates ) , keepSilentProbabilities ( keepSilentProbabilities ) , silentProbabilities ( ) {
storm : : storage : : sparse : : state_type position = 0 ;
Block * firstBlock = nullptr ;
Block * secondBlock = nullptr ;
@ -271,7 +275,7 @@ namespace storm {
typename std : : list < Block > : : iterator firstIt = blocks . emplace ( this - > blocks . end ( ) , 0 , prob0States . getNumberOfSetBits ( ) , nullptr , nullptr , numberOfBlocks + + ) ;
firstBlock = & ( * firstIt ) ;
firstBlock - > setIterator ( firstIt ) ;
for ( auto state : prob0States ) {
statesAndValues [ position ] = std : : make_pair ( state , storm : : utility : : zero < ValueType > ( ) ) ;
positions [ state ] = position ;
@ -280,9 +284,9 @@ namespace storm {
}
firstBlock - > setAbsorbing ( true ) ;
}
if ( ! prob1States . empty ( ) ) {
typename std : : list < Block > : : iterator secondIt = blocks . emplace ( this - > blocks . end ( ) , position , position + prob1States . getNumberOfSetBits ( ) , firstBlock , nullptr , numberOfBlocks + + , std : : shared_ptr < std : : string > ( new std : : string ( prob1Label ) ) ) ;
typename std : : list < Block > : : iterator secondIt = blocks . emplace ( this - > blocks . end ( ) , position , position + prob1States . getNumberOfSetBits ( ) , firstBlock , nullptr , numberOfBlocks + + ) ;
secondBlock = & ( * secondIt ) ;
secondBlock - > setIterator ( secondIt ) ;
@ -293,11 +297,12 @@ namespace storm {
+ + position ;
}
secondBlock - > setAbsorbing ( true ) ;
secondBlock - > setRepresentativeState ( representativeProb1State . get ( ) ) ;
}
storm : : storage : : BitVector otherStates = ~ ( prob0States | prob1States ) ;
if ( ! otherStates . empty ( ) ) {
typename std : : list < Block > : : iterator thirdIt = blocks . emplace ( this - > blocks . end ( ) , position , numberOfStates , secondBlock , nullptr , numberOfBlocks + + , otherLabel = = " true " ? std : : shared_ptr < std : : string > ( nullptr ) : std : : shared_ptr < std : : string > ( new std : : string ( otherLabel ) ) ) ;
typename std : : list < Block > : : iterator thirdIt = blocks . emplace ( this - > blocks . end ( ) , position , numberOfStates , secondBlock , nullptr , numberOfBlocks + + ) ;
thirdBlock = & ( * thirdIt ) ;
thirdBlock - > setIterator ( thirdIt ) ;
@ -320,7 +325,7 @@ namespace storm {
std : : swap ( this - > statesAndValues [ this - > positions [ state1 ] ] , this - > statesAndValues [ this - > positions [ state2 ] ] ) ;
std : : swap ( this - > positions [ state1 ] , this - > positions [ state2 ] ) ;
}
template < typename ValueType >
void DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : swapStatesAtPositions ( storm : : storage : : sparse : : state_type position1 , storm : : storage : : sparse : : state_type position2 ) {
storm : : storage : : sparse : : state_type state1 = this - > statesAndValues [ position1 ] . first ;
@ -366,7 +371,7 @@ namespace storm {
void DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : increaseValue ( storm : : storage : : sparse : : state_type state , ValueType value ) {
this - > statesAndValues [ this - > positions [ state ] ] . second + = value ;
}
template < typename ValueType >
void DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : updateBlockMapping ( Block & block , typename std : : vector < std : : pair < storm : : storage : : sparse : : state_type , ValueType > > : : iterator first , typename std : : vector < std : : pair < storm : : storage : : sparse : : state_type , ValueType > > : : iterator last ) {
for ( ; first ! = last ; + + first ) {
@ -383,12 +388,12 @@ namespace storm {
typename DeterministicModelBisimulationDecomposition < ValueType > : : Block & DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : getBlock ( storm : : storage : : sparse : : state_type state ) {
return * this - > stateToBlockMapping [ state ] ;
}
template < typename ValueType >
typename DeterministicModelBisimulationDecomposition < ValueType > : : Block const & DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : getBlock ( storm : : storage : : sparse : : state_type state ) const {
return * this - > stateToBlockMapping [ state ] ;
}
template < typename ValueType >
typename std : : vector < std : : pair < storm : : storage : : sparse : : state_type , ValueType > > : : iterator DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : getBegin ( Block const & block ) {
return this - > statesAndValues . begin ( ) + block . getBegin ( ) ;
@ -398,7 +403,7 @@ namespace storm {
typename std : : vector < std : : pair < storm : : storage : : sparse : : state_type , ValueType > > : : iterator DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : getEnd ( Block const & block ) {
return this - > statesAndValues . begin ( ) + block . getEnd ( ) ;
}
template < typename ValueType >
typename std : : vector < std : : pair < storm : : storage : : sparse : : state_type , ValueType > > : : const_iterator DeterministicModelBisimulationDecomposition < ValueType > : : Partition : : getBegin ( Block const & block ) const {
return this - > statesAndValues . begin ( ) + block . getBegin ( ) ;
@ -418,7 +423,7 @@ namespace storm {
}
// Actually create the new block and insert it at the correct position.
typename std : : list < Block > : : iterator selfIt = this - > blocks . emplace ( block . getIterator ( ) , block . getBegin ( ) , position , block . getPreviousBlockPointer ( ) , & block , numberOfBlocks + + , block . getLabelPtr ( ) ) ;
typename std : : list < Block > : : iterator selfIt = this - > blocks . emplace ( block . getIterator ( ) , block . getBegin ( ) , position , block . getPreviousBlockPointer ( ) , & block , numberOfBlocks + + ) ;
selfIt - > setIterator ( selfIt ) ;
Block & newBlock = * selfIt ;
@ -590,48 +595,124 @@ namespace storm {
}
template < typename ValueType >
DeterministicModelBisimulationDecomposition < ValueType > : : DeterministicModelBisimulationDecomposition ( storm : : models : : Dtmc < ValueType > const & model , boost : : optional < std : : set < std : : string > > const & atomicPropositions , bool keepRewards , bool weak , bool buildQuotient ) : comparator ( ) {
STORM_LOG_THROW ( ! model . hasTransitionRewards ( ) , storm : : exceptions : : IllegalFunctionCallException , " Bisimulation is currently only supported for models without transition rewards. " ) ;
storm : : storage : : SparseMatrix < ValueType > backwardTransitions = model . getBackwardTransitions ( ) ;
BisimulationType bisimulationType = weak ? BisimulationType : : WeakDtmc : BisimulationType : : Strong ;
Partition initialPartition = getLabelBasedInitialPartition ( model , backwardTransitions , bisimulationType , atomicPropositions , keepRewards ) ;
partitionRefinement ( model , atomicPropositions , backwardTransitions , initialPartition , bisimulationType , keepRewards , buildQuotient ) ;
DeterministicModelBisimulationDecomposition < ValueType > : : Options : : Options ( storm : : models : : AbstractModel < ValueType > const & model , storm : : logic : : Formula const & formula ) : Options ( ) {
if ( ! formula . containsRewardOperator ( ) ) {
this - > keepRewards = false ;
}
// As a tradeoff, we compute a strong bisimulation, because that is typically much faster. If the number of
// states is to be minimized, this should be set to weak by the calling site.
weak = false ;
// We need to preserve bounded properties iff the formula contains a bounded until or a next subformula.
bounded = formula . containsBoundedUntilFormula ( ) | | formula . containsNextFormula ( ) ;
std : : vector < std : : shared_ptr < storm : : logic : : AtomicExpressionFormula const > > atomicExpressionFormulas = formula . getAtomicExpressionFormulas ( ) ;
std : : vector < std : : shared_ptr < storm : : logic : : AtomicLabelFormula const > > atomicLabelFormulas = formula . getAtomicLabelFormulas ( ) ;
std : : set < std : : string > labelsToRespect ;
for ( auto const & labelFormula : atomicLabelFormulas ) {
labelsToRespect . insert ( labelFormula - > getLabel ( ) ) ;
}
for ( auto const & expressionFormula : atomicExpressionFormulas ) {
std : : stringstream stream ;
stream < < * expressionFormula ;
labelsToRespect . insert ( stream . str ( ) ) ;
}
respectedAtomicPropositions = labelsToRespect ;
std : : shared_ptr < storm : : logic : : Formula const > newFormula = formula . asSharedPointer ( ) ;
if ( formula . isProbabilityOperatorFormula ( ) ) {
newFormula = formula . asProbabilityOperatorFormula ( ) . getSubformula ( ) . asSharedPointer ( ) ;
} else if ( formula . isRewardOperatorFormula ( ) ) {
newFormula = formula . asRewardOperatorFormula ( ) . getSubformula ( ) . asSharedPointer ( ) ;
}
std : : shared_ptr < storm : : logic : : Formula const > leftSubformula = std : : make_shared < storm : : logic : : BooleanLiteralFormula > ( true ) ;
std : : shared_ptr < storm : : logic : : Formula const > rightSubformula ;
if ( newFormula - > isUntilFormula ( ) ) {
leftSubformula = newFormula - > asUntilFormula ( ) . getLeftSubformula ( ) . asSharedPointer ( ) ;
rightSubformula = newFormula - > asUntilFormula ( ) . getRightSubformula ( ) . asSharedPointer ( ) ;
if ( leftSubformula - > isPropositionalFormula ( ) & & rightSubformula - > isPropositionalFormula ( ) ) {
measureDrivenInitialPartition = true ;
}
} else if ( newFormula - > isEventuallyFormula ( ) ) {
rightSubformula = newFormula - > asEventuallyFormula ( ) . getSubformula ( ) . asSharedPointer ( ) ;
if ( rightSubformula - > isPropositionalFormula ( ) ) {
measureDrivenInitialPartition = true ;
}
} else if ( newFormula - > isReachabilityRewardFormula ( ) ) {
rightSubformula = newFormula - > asReachabilityRewardFormula ( ) . getSubformula ( ) . asSharedPointer ( ) ;
if ( rightSubformula - > isPropositionalFormula ( ) ) {
measureDrivenInitialPartition = true ;
}
}
if ( measureDrivenInitialPartition ) {
storm : : modelchecker : : SparsePropositionalModelChecker < ValueType > checker ( model ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > phiStatesCheckResult = checker . check ( * leftSubformula ) ;
std : : unique_ptr < storm : : modelchecker : : CheckResult > psiStatesCheckResult = checker . check ( * rightSubformula ) ;
phiStates = phiStatesCheckResult - > asExplicitQualitativeCheckResult ( ) . getTruthValuesVector ( ) ;
psiStates = psiStatesCheckResult - > asExplicitQualitativeCheckResult ( ) . getTruthValuesVector ( ) ;
}
}
template < typename ValueType >
DeterministicModelBisimulationDecomposition < ValueType > : : DeterministicModelBisimulationDecomposition ( storm : : models : : Ctmc < ValueType > const & model , boost : : optional < std : : set < std : : string > > const & atomicPropositions , bool keepRewards , bool weak , bool buildQuotient ) {
STORM_LOG_THROW ( ! keepRewards | | ! model . hasTransitionRewards ( ) , storm : : exceptions : : IllegalFunctionCallException , " Bisimulation is currently only supported for models without transition rewards. " ) ;
storm : : storage : : SparseMatrix < ValueType > backwardTransitions = model . getBackwardTransitions ( ) ;
BisimulationType bisimulationType = weak ? BisimulationType : : WeakCtmc : BisimulationType : : Strong ;
Partition initialPartition = getLabelBasedInitialPartition ( model , backwardTransitions , bisimulationType , atomicPropositions , keepRewards ) ;
partitionRefinement ( model , atomicPropositions , backwardTransitions , initialPartition , bisimulationType , keepRewards , buildQuotient ) ;
DeterministicModelBisimulationDecomposition < ValueType > : : Options : : Options ( ) : measureDrivenInitialPartition ( false ) , phiStates ( ) , psiStates ( ) , respectedAtomicPropositions ( ) , keepRewards ( true ) , weak ( false ) , bounded ( true ) , buildQuotient ( true ) {
// Intentionally left empty.
}
template < typename ValueType >
DeterministicModelBisimulationDecomposition < ValueType > : : DeterministicModelBisimulationDecomposition ( storm : : models : : Dtmc < ValueType > const & model , std : : string const & phiLabel , std : : string const & psiLabel , bool keepRewards , bool weak , bool bounded , bool buildQuotient ) {
STORM_LOG_THROW ( ! keepRewards | | ! model . hasTransitionRewards ( ) , storm : : exceptions : : IllegalFunctionCallException , " Bisimulation is currently only supported for models without transition rewards. " ) ;
STORM_LOG_THROW ( ! weak | | ! bounded , storm : : exceptions : : IllegalFunctionCallException , " Weak bisimulation does not preserve bounded properties. " ) ;
DeterministicModelBisimulationDecomposition < ValueType > : : DeterministicModelBisimulationDecomposition ( storm : : models : : Dtmc < ValueType > const & model , Options const & options ) {
STORM_LOG_THROW ( ! model . hasTransitionRewards ( ) , storm : : exceptions : : IllegalFunctionCallException , " Bisimulation is currently only supported for models without transition rewards. Consider converting the transition rewards to state rewards (via suitable function calls) . " ) ;
STORM_LOG_THROW ( ! options . weak | | ! options . bounded , storm : : exceptions : : IllegalFunctionCallException , " Weak bisimulation can not preserve bounded properties. " ) ;
storm : : storage : : SparseMatrix < ValueType > backwardTransitions = model . getBackwardTransitions ( ) ;
BisimulationType bisimulationType = weak ? BisimulationType : : WeakDtmc : BisimulationType : : Strong ;
Partition initialPartition = getMeasureDrivenInitialPartition ( model , backwardTransitions , phiLabel , psiLabel , bisimulationType , keepRewards , bounded ) ;
BisimulationType bisimulationType = options . weak ? BisimulationType : : WeakDtmc : BisimulationType : : Strong ;
std : : set < std : : string > atomicPropositions ;
if ( phiLabel ! = " true " & & phiLabel ! = " false " ) {
atomicPropositions . insert ( phiLabel ) ;
if ( options . respectedAtomicPropositions ) {
atomicPropositions = options . respectedAtomicPropositions . get ( ) ;
} else {
atomicPropositions = model . getStateLabeling ( ) . getAtomicPropositions ( ) ;
}
if ( psiLabel ! = " true " & & phiLabel ! = " false " ) {
atomicPropositions . insert ( psiLabel ) ;
Partition initialPartition ;
if ( options . measureDrivenInitialPartition ) {
STORM_LOG_THROW ( options . phiStates , storm : : exceptions : : InvalidOptionException , " Unable to compute measure-driven initial partition without phi and psi states. " ) ;
STORM_LOG_THROW ( options . psiStates , storm : : exceptions : : InvalidOptionException , " Unable to compute measure-driven initial partition without phi and psi states. " ) ;
initialPartition = getMeasureDrivenInitialPartition ( model , backwardTransitions , options . phiStates . get ( ) , options . psiStates . get ( ) , bisimulationType , options . keepRewards , options . bounded ) ;
} else {
initialPartition = getLabelBasedInitialPartition ( model , backwardTransitions , bisimulationType , atomicPropositions , options . keepRewards ) ;
}
partitionRefinement ( model , std : : set < std : : string > ( { phiLabel , psiLabel } ) , model . getBackwardTransitions ( ) , initialPartition , bisimulationType , keepRewards , buildQuotient ) ;
partitionRefinement ( model , atomicPropositions , backwardTransitions , initialPartition , bisimulationType , options . keepRewards , options . buildQuotient ) ;
}
template < typename ValueType >
DeterministicModelBisimulationDecomposition < ValueType > : : DeterministicModelBisimulationDecomposition ( storm : : models : : Ctmc < ValueType > const & model , std : : string const & phiLabel , std : : string const & psiLabel , bool keepRewards , bool weak , bool bounded , bool buildQuotient ) {
STORM_LOG_THROW ( ! keepRewards | | ! model . hasTransitionRewards ( ) , storm : : exceptions : : IllegalFunctionCallException , " Bisimulation is currently only supported for models without transition rewards. " ) ;
STORM_LOG_THROW ( ! weak | | ! bounded , storm : : exceptions : : IllegalFunctionCallException , " Weak bisimulation does not preserve bounded properties. " ) ;
DeterministicModelBisimulationDecomposition < ValueType > : : DeterministicModelBisimulationDecomposition ( storm : : models : : Ctmc < ValueType > const & model , Options const & options ) {
STORM_LOG_THROW ( ! model . hasTransitionRewards ( ) , storm : : exceptions : : IllegalFunctionCallException , " Bisimulation is currently only supported for models without transition rewards. Consider converting the transition rewards to state rewards (via suitable function calls) . " ) ;
STORM_LOG_THROW ( ! options . weak | | ! options . bounded , storm : : exceptions : : IllegalFunctionCallException , " Weak bisimulation can not preserve bounded properties. " ) ;
storm : : storage : : SparseMatrix < ValueType > backwardTransitions = model . getBackwardTransitions ( ) ;
BisimulationType bisimulationType = weak ? BisimulationType : : WeakCtmc : BisimulationType : : Strong ;
Partition initialPartition = getMeasureDrivenInitialPartition ( model , backwardTransitions , phiLabel , psiLabel , bisimulationType , keepRewards , bounded ) ;
partitionRefinement ( model , std : : set < std : : string > ( { phiLabel , psiLabel } ) , model . getBackwardTransitions ( ) , initialPartition , bisimulationType , keepRewards , buildQuotient ) ;
BisimulationType bisimulationType = options . weak ? BisimulationType : : WeakCtmc : BisimulationType : : Strong ;
std : : set < std : : string > atomicPropositions ;
if ( options . respectedAtomicPropositions ) {
atomicPropositions = options . respectedAtomicPropositions . get ( ) ;
} else {
atomicPropositions = model . getStateLabeling ( ) . getAtomicPropositions ( ) ;
}
Partition initialPartition ;
if ( options . measureDrivenInitialPartition ) {
STORM_LOG_THROW ( options . phiStates , storm : : exceptions : : InvalidOptionException , " Unable to compute measure-driven initial partition without phi and psi states. " ) ;
STORM_LOG_THROW ( options . psiStates , storm : : exceptions : : InvalidOptionException , " Unable to compute measure-driven initial partition without phi and psi states. " ) ;
initialPartition = getMeasureDrivenInitialPartition ( model , backwardTransitions , options . phiStates . get ( ) , options . psiStates . get ( ) , bisimulationType , options . keepRewards , options . bounded ) ;
} else {
initialPartition = getLabelBasedInitialPartition ( model , backwardTransitions , bisimulationType , atomicPropositions , options . keepRewards ) ;
}
partitionRefinement ( model , atomicPropositions , backwardTransitions , initialPartition , bisimulationType , options . keepRewards , options . buildQuotient ) ;
}
template < typename ValueType >
@ -642,7 +723,7 @@ namespace storm {
template < typename ValueType >
template < typename ModelType >
void DeterministicModelBisimulationDecomposition < ValueType > : : buildQuotient ( ModelType const & model , boost : : optional < std : : set < std : : string > > const & selectedAtomicPropositions , Partition const & partition , BisimulationType bisimulationType , bool keepRewards ) {
void DeterministicModelBisimulationDecomposition < ValueType > : : buildQuotient ( ModelType const & model , std : : set < std : : string > const & selectedAtomicPropositions , Partition const & partition , BisimulationType bisimulationType , bool keepRewards ) {
// In order to create the quotient model, we need to construct
// (a) the new transition matrix,
// (b) the new labeling,
@ -653,7 +734,7 @@ namespace storm {
// Prepare the new state labeling for (b).
storm : : models : : AtomicPropositionsLabeling newLabeling ( this - > size ( ) , model . getStateLabeling ( ) . getNumberOfAtomicPropositions ( ) ) ;
std : : set < std : : string > atomicPropositionsSet = selectedAtomicPropositions ? selectedAtomicPropositions . get ( ) : model . getStateLabeling ( ) . getAtomicPropositions ( ) ;
std : : set < std : : string > atomicPropositionsSet = selectedAtomicPropositions ;
atomicPropositionsSet . insert ( " init " ) ;
std : : vector < std : : string > atomicPropositions = std : : vector < std : : string > ( atomicPropositionsSet . begin ( ) , atomicPropositionsSet . end ( ) ) ;
for ( auto const & ap : atomicPropositions ) {
@ -691,15 +772,16 @@ namespace storm {
if ( oldBlock . isAbsorbing ( ) ) {
builder . addNextValue ( blockIndex , blockIndex , storm : : utility : : constantOne < ValueType > ( ) ) ;
if ( oldBlock . hasLabel ( ) ) {
newLabeling . addAtomicPropositionToState ( oldBlock . getLabel ( ) , blockIndex ) ;
} else {
// Otherwise add all atomic propositions to the equivalence class that the representative state
// satisfies.
for ( auto const & ap : atomicPropositions ) {
if ( model . getStateLabeling ( ) . getStateHasAtomicProposition ( ap , representativeState ) ) {
newLabeling . addAtomicPropositionToState ( ap , blockIndex ) ;
}
// If the block has a special representative state, we retrieve it now.
if ( oldBlock . hasRepresentativeState ( ) ) {
representativeState = oldBlock . getRepresentativeState ( ) ;
}
// Add all of the selected atomic propositions that hold in the representative state to the state
// representing the block.
for ( auto const & ap : atomicPropositions ) {
if ( model . getStateLabeling ( ) . getStateHasAtomicProposition ( ap , representativeState ) ) {
newLabeling . addAtomicPropositionToState ( ap , blockIndex ) ;
}
}
} else {
@ -730,16 +812,11 @@ namespace storm {
}
}
// If the block has a special label, we only add that to the block.
if ( oldBlock . hasLabel ( ) ) {
newLabeling . addAtomicPropositionToState ( oldBlock . getLabel ( ) , blockIndex ) ;
} else {
// Otherwise add all atomic propositions to the equivalence class that the representative state
// satisfies.
for ( auto const & ap : atomicPropositions ) {
if ( model . getStateLabeling ( ) . getStateHasAtomicProposition ( ap , representativeState ) ) {
newLabeling . addAtomicPropositionToState ( ap , blockIndex ) ;
}
// Otherwise add all atomic propositions to the equivalence class that the representative state
// satisfies.
for ( auto const & ap : atomicPropositions ) {
if ( model . getStateLabeling ( ) . getStateHasAtomicProposition ( ap , representativeState ) ) {
newLabeling . addAtomicPropositionToState ( ap , blockIndex ) ;
}
}
}
@ -763,9 +840,9 @@ namespace storm {
template < typename ValueType >
template < typename ModelType >
void DeterministicModelBisimulationDecomposition < ValueType > : : partitionRefinement ( ModelType const & model , boost : : optional < std : : set < std : : string > > const & atomicPropositions , storm : : storage : : SparseMatrix < ValueType > const & backwardTransitions , Partition & partition , BisimulationType bisimulationType , bool keepRewards , bool buildQuotient ) {
void DeterministicModelBisimulationDecomposition < ValueType > : : partitionRefinement ( ModelType const & model , std : : set < std : : string > const & atomicPropositions , storm : : storage : : SparseMatrix < ValueType > const & backwardTransitions , Partition & partition , BisimulationType bisimulationType , bool keepRewards , bool buildQuotient ) {
std : : chrono : : high_resolution_clock : : time_point totalStart = std : : chrono : : high_resolution_clock : : now ( ) ;
// Initially, all blocks are potential splitter, so we insert them in the splitterQueue.
std : : chrono : : high_resolution_clock : : time_point refinementStart = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : deque < Block * > splitterQueue ;
@ -775,6 +852,7 @@ namespace storm {
while ( ! splitterQueue . empty ( ) ) {
// Optionally: sort the splitter queue according to some criterion (here: prefer small splitters).
std : : sort ( splitterQueue . begin ( ) , splitterQueue . end ( ) , [ ] ( Block const * b1 , Block const * b2 ) { return b1 - > getNumberOfStates ( ) < b2 - > getNumberOfStates ( ) | | ( b1 - > getNumberOfStates ( ) = = b2 - > getNumberOfStates ( ) & & b1 - > getId ( ) < b2 - > getId ( ) ) ; } ) ;
std : : sort ( splitterQueue . begin ( ) , splitterQueue . end ( ) , [ ] ( Block const * b1 , Block const * b2 ) { return b1 - > getNumberOfStates ( ) < b2 - > getNumberOfStates ( ) ; } ) ;
// Get and prepare the next splitter.
Block * splitter = splitterQueue . front ( ) ;
@ -785,7 +863,7 @@ namespace storm {
refinePartition ( model . getTransitionMatrix ( ) , backwardTransitions , * splitter , partition , bisimulationType , splitterQueue ) ;
}
std : : chrono : : high_resolution_clock : : duration refinementTime = std : : chrono : : high_resolution_clock : : now ( ) - refinementStart ;
// Now move the states from the internal partition into their final place in the decomposition. We do so in
// a way that maintains the block IDs as indices.
std : : chrono : : high_resolution_clock : : time_point extractionStart = std : : chrono : : high_resolution_clock : : now ( ) ;
@ -798,12 +876,12 @@ namespace storm {
std : : function < storm : : storage : : sparse : : state_type ( std : : pair < storm : : storage : : sparse : : state_type , ValueType > const & ) > projection = [ ] ( std : : pair < storm : : storage : : sparse : : state_type , ValueType > const & a ) - > storm : : storage : : sparse : : state_type { return a . first ; } ;
this - > blocks [ block . getId ( ) ] = block_type ( boost : : make_transform_iterator ( partition . getBegin ( block ) , projection ) , boost : : make_transform_iterator ( partition . getEnd ( block ) , projection ) , true ) ;
}
// If we are required to build the quotient model, do so now.
if ( buildQuotient ) {
this - > buildQuotient ( model , atomicPropositions , partition , bisimulationType , keepRewards ) ;
}
std : : chrono : : high_resolution_clock : : duration extractionTime = std : : chrono : : high_resolution_clock : : now ( ) - extractionStart ;
std : : chrono : : high_resolution_clock : : duration totalTime = std : : chrono : : high_resolution_clock : : now ( ) - totalStart ;
@ -1018,7 +1096,7 @@ namespace storm {
typename std : : vector < std : : pair < storm : : storage : : sparse : : state_type , ValueType > > : : const_iterator end = partition . getStatesAndValues ( ) . begin ( ) + block . getBegin ( ) - 1 ;
storm : : storage : : sparse : : state_type currentIndex = block . getOriginalBegin ( ) ;
result . push_back ( currentIndex ) ;
// Now we can check whether the block needs to be split, which is the case iff the probabilities for the
// first and the last state are different.
while ( ! comparator . isEqual ( begin - > second , end - > second ) ) {
@ -1033,7 +1111,7 @@ namespace storm {
+ + begin ;
+ + currentIndex ;
}
// Remember the index at which the probabilities were different.
result . push_back ( currentIndex ) ;
}
@ -1126,7 +1204,7 @@ namespace storm {
storm : : storage : : sparse : : state_type predecessor = predecessorEntry . getColumn ( ) ;
Block & predecessorBlock = partition . getBlock ( predecessor ) ;
storm : : storage : : sparse : : state_type predecessorPosition = partition . getPosition ( predecessor ) ;
if ( predecessorPosition > = predecessorBlock . getBegin ( ) ) {
partition . swapStatesAtPositions ( predecessorPosition , predecessorBlock . getBegin ( ) ) ;
predecessorBlock . incrementBegin ( ) ;
@ -1141,7 +1219,7 @@ namespace storm {
}
}
}
if ( bisimulationType = = BisimulationType : : Strong | | bisimulationType = = BisimulationType : : WeakCtmc ) {
std : : vector < Block * > blocksToSplit ;
@ -1192,7 +1270,7 @@ namespace storm {
partition . setSilentProbabilities ( partition . getStatesAndValues ( ) . begin ( ) + splitter . getOriginalBegin ( ) , partition . getStatesAndValues ( ) . begin ( ) + splitter . getBegin ( ) ) ;
partition . setSilentProbabilitiesToZero ( partition . getStatesAndValues ( ) . begin ( ) + splitter . getBegin ( ) , partition . getStatesAndValues ( ) . begin ( ) + splitter . getEnd ( ) ) ;
}
// Now refine all predecessor blocks in a weak manner. That is, we split according to the criterion of
// weak bisimulation.
for ( auto blockPtr : predecessorBlocks ) {
@ -1205,7 +1283,7 @@ namespace storm {
// Restore the begin of the block.
block . setBegin ( block . getOriginalBegin ( ) ) ;
}
block . unmarkAsPredecessorBlock ( ) ;
block . resetMarkedPosition ( ) ;
}
@ -1216,9 +1294,15 @@ namespace storm {
template < typename ValueType >
template < typename ModelType >
typename DeterministicModelBisimulationDecomposition < ValueType > : : Partition DeterministicModelBisimulationDecomposition < ValueType > : : getMeasureDrivenInitialPartition ( ModelType const & model , storm : : storage : : SparseMatrix < ValueType > const & backwardTransitions , std : : string const & phiLabel , std : : string const & psiLabel , BisimulationType bisimulationType , bool keepRewards , bool bounded ) {
std : : pair < storm : : storage : : BitVector , storm : : storage : : BitVector > statesWithProbability01 = storm : : utility : : graph : : performProb01 ( backwardTransitions , phiLabel = = " true " ? storm : : storage : : BitVector ( model . getNumberOfStates ( ) , true ) : model . getLabeledStates ( phiLabel ) , model . getLabeledStates ( psiLabel ) ) ;
Partition partition ( model . getNumberOfStates ( ) , statesWithProbability01 . first , bounded | | keepRewards ? model . getLabeledStates ( psiLabel ) : statesWithProbability01 . second , phiLabel , psiLabel , bisimulationType = = BisimulationType : : WeakDtmc ) ;
typename DeterministicModelBisimulationDecomposition < ValueType > : : Partition DeterministicModelBisimulationDecomposition < ValueType > : : getMeasureDrivenInitialPartition ( ModelType const & model , storm : : storage : : SparseMatrix < ValueType > const & backwardTransitions , storm : : storage : : BitVector const & phiStates , storm : : storage : : BitVector const & psiStates , BisimulationType bisimulationType , bool keepRewards , bool bounded ) {
std : : pair < storm : : storage : : BitVector , storm : : storage : : BitVector > statesWithProbability01 = storm : : utility : : graph : : performProb01 ( backwardTransitions , phiStates , psiStates ) ;
boost : : optional < storm : : storage : : sparse : : state_type > representativePsiState ;
if ( ! psiStates . empty ( ) ) {
representativePsiState = * psiStates . begin ( ) ;
}
Partition partition ( model . getNumberOfStates ( ) , statesWithProbability01 . first , bounded | | keepRewards ? psiStates : statesWithProbability01 . second , representativePsiState , bisimulationType = = BisimulationType : : WeakDtmc ) ;
// If the model has state rewards, we need to consider them, because otherwise reward properties are not
// preserved.