@ -14,8 +14,8 @@
namespace storm {
namespace transformer {
template < typename ValueType >
void transformContinuousToDiscreteModelInPlace ( std : : shared_ptr < storm : : models : : sparse : : Model < ValueType > > & markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) {
template < typename ValueType , typename RewardModelType >
std : : shared_ptr < storm : : models : : sparse : : Model < ValueType > > transformContinuousToDiscreteModel ( std : : shared_ptr < storm : : models : : sparse : : Model < ValueType , RewardModelType > > markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) {
boost : : optional < std : : string > timeRewardModelName ;
if ( formula - > isTimeOperatorFormula ( ) ) {
auto const & timeOpFormula = formula - > asTimeOperatorFormula ( ) ;
@ -29,13 +29,42 @@ namespace storm {
}
if ( markovModel - > isOfType ( storm : : models : : ModelType : : Ctmc ) ) {
SparseCtmcToSparseDtmcTransformer < storm : : models : : sparse : : Ctmc < ValueType > > transformer ;
SparseCtmcToSparseDtmcTransformer < ValueType , RewardModelType > transformer ;
if ( transformer . transformationPreservesProperty ( * formula ) ) {
STORM_LOG_INFO ( " Transforming Ctmc to embedded Dtmc... " ) ;
markovModel = transformer . translate ( * markovModel - > template as < storm : : models : : sparse : : Ctmc < ValueType > > ( ) , timeRewardModelName ) ;
}
} else if ( markovModel - > isOfType ( storm : : models : : ModelType : : MarkovAutomaton ) ) {
SparseMaToSparseMdpTransformer < ValueType , RewardModelType > transformer ;
if ( transformer . transformationPreservesProperty ( * formula ) ) {
STORM_LOG_INFO ( " Transforming Markov automaton to embedded Mdp... " ) ;
markovModel = transformer . translate ( * markovModel - > template as < storm : : models : : sparse : : MarkovAutomaton < ValueType > > ( ) , timeRewardModelName ) ;
}
}
}
template < typename ValueType , typename RewardModelType >
void transformContinuousToDiscreteModelInPlace ( std : : shared_ptr < storm : : models : : sparse : : Model < ValueType , RewardModelType > > & markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) {
boost : : optional < std : : string > timeRewardModelName ;
if ( formula - > isTimeOperatorFormula ( ) ) {
auto const & timeOpFormula = formula - > asTimeOperatorFormula ( ) ;
if ( timeOpFormula . getSubformula ( ) . isReachabilityTimeFormula ( ) ) {
auto reachabilityRewardFormula = std : : make_shared < storm : : logic : : EventuallyFormula > ( storm : : logic : : CloneVisitor ( ) . clone ( timeOpFormula . getSubformula ( ) . asReachabilityTimeFormula ( ) . getSubformula ( ) ) , storm : : logic : : FormulaContext : : Reward ) ;
timeRewardModelName = " time " ;
// make sure that the reward model name is not already in use
while ( markovModel - > hasRewardModel ( * timeRewardModelName ) ) * timeRewardModelName + = " _ " ;
formula = std : : make_shared < storm : : logic : : RewardOperatorFormula const > ( reachabilityRewardFormula , timeRewardModelName , timeOpFormula . getOperatorInformation ( ) ) ;
}
}
if ( markovModel - > isOfType ( storm : : models : : ModelType : : Ctmc ) ) {
SparseCtmcToSparseDtmcTransformer < ValueType , RewardModelType > transformer ;
if ( transformer . transformationPreservesProperty ( * formula ) ) {
STORM_LOG_INFO ( " Transforming Ctmc to embedded Dtmc... " ) ;
markovModel = transformer . translate ( std : : move ( * markovModel - > template as < storm : : models : : sparse : : Ctmc < ValueType > > ( ) ) , timeRewardModelName ) ;
}
} else if ( markovModel - > isOfType ( storm : : models : : ModelType : : MarkovAutomaton ) ) {
SparseMaToSparseMdpTransformer < storm : : models : : sparse : : MarkovAutomaton < ValueType > > transformer ;
SparseMaToSparseMdpTransformer < ValueType , RewardModelType > transformer ;
if ( transformer . transformationPreservesProperty ( * formula ) ) {
STORM_LOG_INFO ( " Transforming Markov automaton to embedded Mdp... " ) ;
markovModel = transformer . translate ( std : : move ( * markovModel - > template as < storm : : models : : sparse : : MarkovAutomaton < ValueType > > ( ) ) , timeRewardModelName ) ;
@ -43,23 +72,54 @@ namespace storm {
}
}
template < typename CtmcType >
std : : shared_ptr < storm : : models : : sparse : : Dtmc < typename CtmcType : : ValueType , typename CtmcType : : RewardModelType > > SparseCtmcToSparseDtmcTransformer < CtmcType > : : translate ( CtmcType & & ctmc , boost : : optional < std : : string > const & timeRewardModelName ) {
// Turn the rates into probabilities by scaling each row of the transition matrix with the exit rate
std : : vector < typename CtmcType : : ValueType > & exitRates = ctmc . getExitRateVector ( ) ;
storm : : storage : : SparseMatrix < typename CtmcType : : ValueType > matrix ( std : : move ( ctmc . getTransitionMatrix ( ) ) ) ;
auto exitRateIt = exitRates . begin ( ) ;
for ( uint_fast64_t state = 0 ; state < matrix . getRowCount ( ) ; + + state ) {
for ( auto & entry : matrix . getRow ( state ) ) {
entry . setValue ( entry . getValue ( ) / * exitRateIt ) ;
template < typename ValueType , typename RewardModelType >
std : : shared_ptr < storm : : models : : sparse : : Dtmc < ValueType , RewardModelType > > SparseCtmcToSparseDtmcTransformer < ValueType , RewardModelType > : : translate ( storm : : models : : sparse : : Ctmc < ValueType , RewardModelType > const & ctmc , boost : : optional < std : : string > const & timeRewardModelName ) {
// Init the dtmc components
storm : : storage : : sparse : : ModelComponents < ValueType , RewardModelType > dtmcComponents ( ctmc . getTransitionMatrix ( ) , ctmc . getStateLabeling ( ) , ctmc . getRewardModels ( ) ) ;
dtmcComponents . choiceLabeling = ctmc . getOptionalChoiceLabeling ( ) ;
dtmcComponents . stateValuations = ctmc . getOptionalStateValuations ( ) ;
dtmcComponents . choiceOrigins = ctmc . getOptionalChoiceOrigins ( ) ;
// Turn the rates into probabilities by dividing each row of the transition matrix with the exit rate
std : : vector < ValueType > const & exitRates = ctmc . getExitRateVector ( ) ;
dtmcComponents . transitionMatrix . divideRowsInPlace ( exitRates ) ;
// Transform the reward models
for ( auto & rewardModel : dtmcComponents . rewardModels ) {
if ( rewardModel . second . hasStateRewards ( ) ) {
storm : : utility : : vector : : divideVectorsPointwise ( rewardModel . second . getStateRewardVector ( ) , exitRates , rewardModel . second . getStateRewardVector ( ) ) ;
}
+ + exitRateIt ;
}
STORM_LOG_ASSERT ( exitRateIt = = exitRates . end ( ) , " Unexpected size of rate vector. " ) ;
if ( timeRewardModelName ) {
// Invert the exit rate vector in place
std : : vector < ValueType > timeRewardVector ;
timeRewardVector . reserve ( exitRates . size ( ) ) ;
for ( auto const & r : exitRates ) {
timeRewardVector . push_back ( storm : : utility : : one < ValueType > ( ) / r ) ;
}
RewardModelType timeRewards ( std : : move ( timeRewardVector ) ) ;
auto insertRes = dtmcComponents . rewardModels . insert ( std : : make_pair ( * timeRewardModelName , std : : move ( timeRewards ) ) ) ;
STORM_LOG_THROW ( insertRes . second , storm : : exceptions : : InvalidArgumentException , " Could not insert auxiliary reward model " < < * timeRewardModelName < < " because a model with this name already exists. " ) ;
}
return std : : make_shared < storm : : models : : sparse : : Dtmc < ValueType , RewardModelType > > ( std : : move ( dtmcComponents ) ) ;
}
template < typename ValueType , typename RewardModelType >
std : : shared_ptr < storm : : models : : sparse : : Dtmc < ValueType , RewardModelType > > SparseCtmcToSparseDtmcTransformer < ValueType , RewardModelType > : : translate ( storm : : models : : sparse : : Ctmc < ValueType , RewardModelType > & & ctmc , boost : : optional < std : : string > const & timeRewardModelName ) {
// Init the dtmc components
storm : : storage : : sparse : : ModelComponents < ValueType , RewardModelType > dtmcComponents ( std : : move ( ctmc . getTransitionMatrix ( ) ) , std : : move ( ctmc . getStateLabeling ( ) ) , std : : move ( ctmc . getRewardModels ( ) ) ) ;
dtmcComponents . choiceLabeling = std : : move ( ctmc . getOptionalChoiceLabeling ( ) ) ;
dtmcComponents . stateValuations = std : : move ( ctmc . getOptionalStateValuations ( ) ) ;
dtmcComponents . choiceOrigins = std : : move ( ctmc . getOptionalChoiceOrigins ( ) ) ;
// Turn the rates into probabilities by dividing each row of the transition matrix with the exit rate
std : : vector < ValueType > & exitRates = ctmc . getExitRateVector ( ) ;
dtmcComponents . transitionMatrix . divideRowsInPlace ( exitRates ) ;
// Transform the reward models
std : : unordered_map < std : : string , typename CtmcType : : RewardModelType > rewardModels ( std : : move ( ctmc . getRewardModels ( ) ) ) ;
for ( auto & rewardModel : rewardModels ) {
for ( auto & rewardModel : dtmcComponents . rewardModels ) {
if ( rewardModel . second . hasStateRewards ( ) ) {
storm : : utility : : vector : : divideVectorsPointwise ( rewardModel . second . getStateRewardVector ( ) , exitRates , rewardModel . second . getStateRewardVector ( ) ) ;
}
@ -67,18 +127,18 @@ namespace storm {
if ( timeRewardModelName ) {
// Invert the exit rate vector in place
storm : : utility : : vector : : applyPointwise < typename CtmcType : : ValueType , typename CtmcType : : ValueType > ( exitRates , exitRates , [ & ] ( typename CtmcType : : ValueType const & r ) - > typename CtmcType : : ValueType { return storm : : utility : : one < typename CtmcType : : ValueType > ( ) / r ; } ) ;
typename CtmcType : : RewardModelType timeRewards ( std : : move ( exitRates ) ) ;
auto insertRes = rewardModels . insert ( std : : make_pair ( * timeRewardModelName , std : : move ( timeRewards ) ) ) ;
storm : : utility : : vector : : applyPointwise < ValueType , ValueType > ( exitRates , exitRates , [ & ] ( ValueType const & r ) - > ValueType { return storm : : utility : : one < ValueType > ( ) / r ; } ) ;
RewardModelType timeRewards ( std : : move ( exitRates ) ) ;
auto insertRes = dtmcComponents . rewardModels . insert ( std : : make_pair ( * timeRewardModelName , std : : move ( timeRewards ) ) ) ;
STORM_LOG_THROW ( insertRes . second , storm : : exceptions : : InvalidArgumentException , " Could not insert auxiliary reward model " < < * timeRewardModelName < < " because a model with this name already exists. " ) ;
}
// exitRates might be invalidated at this point!!
// Note: exitRates might be invalidated at this point.
return std : : make_shared < storm : : models : : sparse : : Dtmc < typename CtmcType : : ValueType , typename CtmcType : : RewardModelType > > ( std : : move ( matrix ) , std : : move ( ctmc . getStateLabeling ( ) ) , std : : move ( rewardModel s) ) ;
return std : : make_shared < storm : : models : : sparse : : Dtmc < ValueType , RewardModelType > > ( std : : move ( dtmcComponent s) ) ;
}
template < typename Ctmc Type>
bool SparseCtmcToSparseDtmcTransformer < Ctmc Type> : : transformationPreservesProperty ( storm : : logic : : Formula const & formula ) {
template < typename ValueType , typename RewardModel Type>
bool SparseCtmcToSparseDtmcTransformer < ValueType , RewardModel Type> : : transformationPreservesProperty ( storm : : logic : : Formula const & formula ) {
storm : : logic : : FragmentSpecification fragment = storm : : logic : : propositional ( ) ;
fragment . setProbabilityOperatorsAllowed ( true ) ;
fragment . setGloballyFormulasAllowed ( true ) ;
@ -90,16 +150,22 @@ namespace storm {
return formula . isInFragment ( fragment ) ;
}
template < typename MaType >
std : : shared_ptr < storm : : models : : sparse : : Mdp < typename MaType : : ValueType , typename MaType : : RewardModelType > > SparseMaToSparseMdpTransformer < MaType > : : translate ( MaType & & ma , boost : : optional < std : : string > const & timeRewardModelName ) {
template < typename ValueType , typename RewardModelType >
std : : shared_ptr < storm : : models : : sparse : : Mdp < ValueType , RewardModelType > > SparseMaToSparseMdpTransformer < ValueType , RewardModelType > : : translate ( storm : : models : : sparse : : MarkovAutomaton < ValueType , RewardModelType > const & ma , boost : : optional < std : : string > const & timeRewardModelName ) {
STORM_LOG_THROW ( ma . isClosed ( ) , storm : : exceptions : : InvalidArgumentException , " Transformation of MA to its underlying MDP is only possible for closed MAs " ) ;
std : : vector < typename MaType : : ValueType > & exitRates = ma . getExitRates ( ) ;
// Init the mdp components
storm : : storage : : sparse : : ModelComponents < ValueType , RewardModelType > mdpComponents ( ma . getTransitionMatrix ( ) , ma . getStateLabeling ( ) , ma . getRewardModels ( ) ) ;
mdpComponents . choiceLabeling = ma . getOptionalChoiceLabeling ( ) ;
mdpComponents . stateValuations = ma . getOptionalStateValuations ( ) ;
mdpComponents . choiceOrigins = ma . getOptionalChoiceOrigins ( ) ;
// Markov automata already store the probability matrix
// Transform the reward models
std : : unordered_map < std : : string , typename MaType : : RewardModelType > rewardModels ( std : : move ( ma . getRewardModels ( ) ) ) ;
for ( auto & rewardModel : rewardModels ) {
std : : vector < ValueType > const & exitRates = ma . getExitRates ( ) ;
for ( auto & rewardModel : mdpComponents . rewardModels ) {
if ( rewardModel . second . hasStateRewards ( ) ) {
auto & stateRewards = rewardModel . second . getStateRewardVector ( ) ;
for ( auto state : ma . getMarkovianStates ( ) ) {
@ -110,20 +176,57 @@ namespace storm {
if ( timeRewardModelName ) {
// Invert the exit rate vector. Avoid division by zero at probabilistic states
std : : vector < typename MaType : : ValueType > timeRewardVector ( exitRates . size ( ) , storm : : utility : : zero < typename MaType : : ValueType > ( ) ) ;
std : : vector < ValueType > timeRewardVector ( exitRates . size ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
for ( auto state : ma . getMarkovianStates ( ) ) {
timeRewardVector [ state ] = storm : : utility : : one < typename MaType : : ValueType > ( ) / exitRates [ state ] ;
timeRewardVector [ state ] = storm : : utility : : one < ValueType > ( ) / exitRates [ state ] ;
}
typename MaType : : RewardModelType timeRewards ( std : : move ( timeRewardVector ) ) ;
auto insertRes = rewardModels . insert ( std : : make_pair ( * timeRewardModelName , std : : move ( timeRewards ) ) ) ;
RewardModelType timeRewards ( std : : move ( timeRewardVector ) ) ;
auto insertRes = mdpComponents . rewardModels . insert ( std : : make_pair ( * timeRewardModelName , std : : move ( timeRewards ) ) ) ;
STORM_LOG_THROW ( insertRes . second , storm : : exceptions : : InvalidArgumentException , " Could not insert auxiliary reward model " < < * timeRewardModelName < < " because a model with this name already exists. " ) ;
}
return std : : make_shared < storm : : models : : sparse : : Mdp < typename MaType : : ValueType , typename MaType : : RewardModelType > > ( std : : move ( ma . getTransitionMatrix ( ) ) , std : : move ( ma . getStateLabeling ( ) ) , std : : move ( rewardModels ) ) ;
return std : : make_shared < storm : : models : : sparse : : Mdp < ValueType , RewardModelType > > ( std : : move ( mdpComponents ) ) ;
}
template < typename ValueType , typename RewardModelType >
std : : shared_ptr < storm : : models : : sparse : : Mdp < ValueType , RewardModelType > > SparseMaToSparseMdpTransformer < ValueType , RewardModelType > : : translate ( storm : : models : : sparse : : MarkovAutomaton < ValueType , RewardModelType > & & ma , boost : : optional < std : : string > const & timeRewardModelName ) {
STORM_LOG_THROW ( ma . isClosed ( ) , storm : : exceptions : : InvalidArgumentException , " Transformation of MA to its underlying MDP is only possible for closed MAs " ) ;
std : : vector < ValueType > & exitRates = ma . getExitRates ( ) ;
// Init the mdp components
storm : : storage : : sparse : : ModelComponents < ValueType , RewardModelType > mdpComponents ( std : : move ( ma . getTransitionMatrix ( ) ) , std : : move ( ma . getStateLabeling ( ) ) , std : : move ( ma . getRewardModels ( ) ) ) ;
mdpComponents . choiceLabeling = std : : move ( ma . getOptionalChoiceLabeling ( ) ) ;
mdpComponents . stateValuations = std : : move ( ma . getOptionalStateValuations ( ) ) ;
mdpComponents . choiceOrigins = std : : move ( ma . getOptionalChoiceOrigins ( ) ) ;
// Markov automata already store the probability matrix
// Transform the reward models
for ( auto & rewardModel : mdpComponents . rewardModels ) {
if ( rewardModel . second . hasStateRewards ( ) ) {
auto & stateRewards = rewardModel . second . getStateRewardVector ( ) ;
for ( auto state : ma . getMarkovianStates ( ) ) {
stateRewards [ state ] / = exitRates [ state ] ;
}
}
}
if ( timeRewardModelName ) {
// Invert the exit rate vector. Avoid division by zero at probabilistic states
std : : vector < ValueType > timeRewardVector ( exitRates . size ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
for ( auto state : ma . getMarkovianStates ( ) ) {
timeRewardVector [ state ] = storm : : utility : : one < ValueType > ( ) / exitRates [ state ] ;
}
RewardModelType timeRewards ( std : : move ( timeRewardVector ) ) ;
auto insertRes = mdpComponents . rewardModels . insert ( std : : make_pair ( * timeRewardModelName , std : : move ( timeRewards ) ) ) ;
STORM_LOG_THROW ( insertRes . second , storm : : exceptions : : InvalidArgumentException , " Could not insert auxiliary reward model " < < * timeRewardModelName < < " because a model with this name already exists. " ) ;
}
return std : : make_shared < storm : : models : : sparse : : Mdp < ValueType , RewardModelType > > ( std : : move ( mdpComponents ) ) ;
}
template < typename MaType >
bool SparseMaToSparseMdpTransformer < MaType > : : transformationPreservesProperty ( storm : : logic : : Formula const & formula ) {
template < typename ValueType , typename RewardModel Type>
bool SparseMaToSparseMdpTransformer < ValueType , RewardModel Type> : : transformationPreservesProperty ( storm : : logic : : Formula const & formula ) {
storm : : logic : : FragmentSpecification fragment = storm : : logic : : propositional ( ) ;
fragment . setProbabilityOperatorsAllowed ( true ) ;
fragment . setGloballyFormulasAllowed ( true ) ;
@ -135,15 +238,18 @@ namespace storm {
return formula . isInFragment ( fragment ) ;
}
template std : : shared_ptr < storm : : models : : sparse : : Model < double > > transformContinuousToDiscreteModel ( std : : shared_ptr < storm : : models : : sparse : : Model < double > > markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) ;
template std : : shared_ptr < storm : : models : : sparse : : Model < storm : : RationalNumber > > transformContinuousToDiscreteModel ( std : : shared_ptr < storm : : models : : sparse : : Model < storm : : RationalNumber > > markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) ;
template std : : shared_ptr < storm : : models : : sparse : : Model < storm : : RationalFunction > > transformContinuousToDiscreteModel ( std : : shared_ptr < storm : : models : : sparse : : Model < storm : : RationalFunction > > markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) ;
template void transformContinuousToDiscreteModelInPlace < double > ( std : : shared_ptr < storm : : models : : sparse : : Model < double > > & markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) ;
template void transformContinuousToDiscreteModelInPlace < storm : : RationalNumber > ( std : : shared_ptr < storm : : models : : sparse : : Model < storm : : RationalNumber > > & markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) ;
template void transformContinuousToDiscreteModelInPlace < storm : : RationalFunction > ( std : : shared_ptr < storm : : models : : sparse : : Model < storm : : RationalFunction > > & markovModel , std : : shared_ptr < storm : : logic : : Formula const > & formula ) ;
template class SparseCtmcToSparseDtmcTransformer < storm : : models : : sparse : : Ctmc < double > > ;
template class SparseCtmcToSparseDtmcTransformer < storm : : models : : sparse : : Ctmc < storm : : RationalNumber > > ;
template class SparseCtmcToSparseDtmcTransformer < storm : : models : : sparse : : Ctmc < storm : : RationalFunction > > ;
template class SparseMaToSparseMdpTransformer < storm : : models : : sparse : : MarkovAutomaton < double > > ;
template class SparseMaToSparseMdpTransformer < storm : : models : : sparse : : MarkovAutomaton < storm : : RationalNumber > > ;
template class SparseMaToSparseMdpTransformer < storm : : models : : sparse : : MarkovAutomaton < storm : : RationalFunction > > ;
template class SparseCtmcToSparseDtmcTransformer < double > ;
template class SparseCtmcToSparseDtmcTransformer < storm : : RationalNumber > ;
template class SparseCtmcToSparseDtmcTransformer < storm : : RationalFunction > ;
template class SparseMaToSparseMdpTransformer < double > ;
template class SparseMaToSparseMdpTransformer < storm : : RationalNumber > ;
template class SparseMaToSparseMdpTransformer < storm : : RationalFunction > ;
}
}