@ -22,7 +22,7 @@ namespace storm {
}
template < typename ValueType , typename StateType >
JaniNextStateGenerator < ValueType , StateType > : : JaniNextStateGenerator ( storm : : jani : : Model const & model , NextStateGeneratorOptions const & options , bool flag ) : NextStateGenerator < ValueType , StateType > ( model . getExpressionManager ( ) , VariableInformation ( model ) , options ) , model ( model ) , rewardVariables ( ) {
JaniNextStateGenerator < ValueType , StateType > : : JaniNextStateGenerator ( storm : : jani : : Model const & model , NextStateGeneratorOptions const & options , bool flag ) : NextStateGenerator < ValueType , StateType > ( model . getExpressionManager ( ) , VariableInformation ( model ) , options ) , model ( model ) , rewardVariables ( ) , hasStateActionRewards ( false ) {
STORM_LOG_THROW ( model . hasDefaultComposition ( ) , storm : : exceptions : : WrongFormatException , " The explicit next-state generator currently does not support custom system compositions. " ) ;
STORM_LOG_THROW ( ! model . hasNonGlobalTransientVariable ( ) , storm : : exceptions : : InvalidSettingsException , " The explicit next-state generator currently does not support automata-local transient variables. " ) ;
STORM_LOG_THROW ( ! this - > options . isBuildChoiceLabelsSet ( ) , storm : : exceptions : : InvalidSettingsException , " JANI next-state generator cannot generate choice labels. " ) ;
@ -282,6 +282,10 @@ namespace storm {
if ( this - > isDeterministicModel ( ) & & totalNumberOfChoices > 1 ) {
Choice < ValueType > globalChoice ;
// For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs
// this is equal to the number of choices, which is why we initialize it like this here.
ValueType totalExitRate = this - > isDiscreteTimeModel ( ) ? static_cast < ValueType > ( totalNumberOfChoices ) : storm : : utility : : zero < ValueType > ( ) ;
// Iterate over all choices and combine the probabilities/rates into one choice.
for ( auto const & choice : allChoices ) {
for ( auto const & stateProbabilityPair : choice ) {
@ -292,11 +296,23 @@ namespace storm {
}
}
if ( hasStateActionRewards & & ! this - > isDiscreteTimeModel ( ) ) {
totalExitRate + = choice . getTotalMass ( ) ;
}
if ( this - > options . isBuildChoiceLabelsSet ( ) ) {
globalChoice . addChoiceLabels ( choice . getChoiceLabels ( ) ) ;
globalChoice . addLabels ( choice . getLabels ( ) ) ;
}
}
std : : vector < ValueType > stateActionRewards ( rewardVariables . size ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
for ( auto const & choice : allChoices ) {
for ( uint_fast64_t rewardVariableIndex = 0 ; rewardVariableIndex < rewardVariables . size ( ) ; + + rewardVariableIndex ) {
stateActionRewards [ rewardVariableIndex ] + = choice . getRewards ( ) [ rewardVariableIndex ] * choice . getTotalMass ( ) / totalExitRate ;
}
}
globalChoice . addRewards ( std : : move ( stateActionRewards ) ) ;
// Move the newly fused choice in place.
allChoices . clear ( ) ;
allChoices . push_back ( std : : move ( globalChoice ) ) ;
@ -349,7 +365,7 @@ namespace storm {
}
// Create the state-action reward for the newly created choice.
performTransientAssignments ( edge . getAssignments ( ) . getTransientAssignments ( ) , [ & choice ] ( ValueType const & value ) { choice . addChoice Reward ( value ) ; } ) ;
performTransientAssignments ( edge . getAssignments ( ) . getTransientAssignments ( ) , [ & choice ] ( ValueType const & value ) { choice . addReward ( value ) ; } ) ;
// Check that the resulting distribution is in fact a distribution.
STORM_LOG_THROW ( ! this - > isDiscreteTimeModel ( ) | | this - > comparator . isOne ( probabilitySum ) , storm : : exceptions : : WrongFormatException , " Probabilities do not sum to one for edge (actually sum to " < < probabilitySum < < " ). " ) ;
@ -385,6 +401,7 @@ namespace storm {
while ( ! done ) {
boost : : container : : flat_map < CompressedState , ValueType > * currentTargetStates = new boost : : container : : flat_map < CompressedState , ValueType > ( ) ;
boost : : container : : flat_map < CompressedState , ValueType > * newTargetStates = new boost : : container : : flat_map < CompressedState , ValueType > ( ) ;
std : : vector < ValueType > stateActionRewards ( rewardVariables . size ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
currentTargetStates - > emplace ( state , storm : : utility : : one < ValueType > ( ) ) ;
@ -405,6 +422,10 @@ namespace storm {
newTargetStates - > emplace ( newTargetState , stateProbabilityPair . second * this - > evaluator . asRational ( destination . getProbability ( ) ) ) ;
}
}
// Create the state-action reward for the newly created choice.
auto valueIt = stateActionRewards . begin ( ) ;
performTransientAssignments ( edge . getAssignments ( ) . getTransientAssignments ( ) , [ & valueIt ] ( ValueType const & value ) { * valueIt + = value ; + + valueIt ; } ) ;
}
// If there is one more command to come, shift the target states one time step back.
@ -423,6 +444,9 @@ namespace storm {
// Now create the actual distribution.
Choice < ValueType > & choice = result . back ( ) ;
// Add the rewards to the choice.
choice . addRewards ( std : : move ( stateActionRewards ) ) ;
// Add the probabilities/rates to the newly created choice.
ValueType probabilitySum = storm : : utility : : zero < ValueType > ( ) ;
for ( auto const & stateProbabilityPair : * newTargetStates ) {
@ -601,6 +625,7 @@ namespace storm {
}
if ( * rewardVariableIt = = assignment . getExpressionVariable ( ) ) {
rewardModelInformation [ std : : distance ( rewardVariables . begin ( ) , rewardVariableIt ) ] . setHasStateActionRewards ( ) ;
hasStateActionRewards = true ;
+ + rewardVariableIt ;
}
}