@ -207,12 +207,83 @@ namespace storm {
return result ;
}
/*!
* Computes a scheduler taking the choices from the given set only finitely often
* @ pre such a scheduler exists
*/
template < typename ValueType >
std : : vector < uint64_t > computeSchedulerFinitelyOften ( storm : : storage : : SparseMatrix < ValueType > const & transitionMatrix , storm : : storage : : SparseMatrix < ValueType > const & backwardTransitions , storm : : storage : : BitVector const & finitelyOftenChoices ) {
std : : vector < uint64_t > result ( transitionMatrix . getRowGroupCount ( ) , 0 ) ;
auto badStates = transitionMatrix . getRowGroupFilter ( finitelyOftenChoices , true ) ;
// badStates shall only be reached finitely often
auto reachBadWithProbGreater0AStates = storm : : utility : : graph : : performProbGreater0A ( transitionMatrix , transitionMatrix . getRowGroupIndices ( ) , backwardTransitions , ~ badStates , badStates , false , 0 , ~ finitelyOftenChoices ) ;
// States in ~reachBadWithProbGreater0AStates can avoid bad states forever by only taking ~finitelyOftenChoices. We compute a scheduler for these states achieving exactly this
auto avoidBadStates = ~ reachBadWithProbGreater0AStates ;
for ( auto state : avoidBadStates ) {
auto const & groupStart = transitionMatrix . getRowGroupIndices ( ) [ state ] ;
auto const & groupEnd = transitionMatrix . getRowGroupIndices ( ) [ state + 1 ] ;
for ( auto choice = finitelyOftenChoices . getNextUnsetIndex ( groupStart ) ; choice < groupEnd ; choice = finitelyOftenChoices . getNextUnsetIndex ( choice + 1 ) ) {
bool allSuccessorsAvoidBadStates = true ;
for ( auto const & element : transitionMatrix . getRow ( choice ) ) {
if ( ! avoidBadStates . get ( element . getColumn ( ) ) ) {
allSuccessorsAvoidBadStates = false ;
break ;
}
}
if ( allSuccessorsAvoidBadStates ) {
result [ state ] = choice - groupStart ;
break ;
}
}
}
// Finally, we need to take care of states that will reach a bad state with prob greater 0 (including the bad states themselves).
// due to the precondition, we know that it has to be possible to eventually avoid the bad states for ever.
// Perform a backwards search from the avoid states and store choices with prob. 1
std : : vector < uint64_t > stack ;
storm : : storage : : BitVector processedStates ( avoidBadStates ) ;
stack . insert ( stack . end ( ) , processedStates . begin ( ) , processedStates . end ( ) ) ;
uint64_t currentState = 0 ;
while ( ! stack . empty ( ) ) {
currentState = stack . back ( ) ;
stack . pop_back ( ) ;
for ( auto predecessorEntryIt = backwardTransitions . begin ( currentState ) , predecessorEntryIte = backwardTransitions . end ( currentState ) ; predecessorEntryIt ! = predecessorEntryIte ; + + predecessorEntryIt ) {
if ( ! processedStates . get ( predecessorEntryIt - > getColumn ( ) ) ) {
// Find a choice leading to an already processed state (such a choice has to exist since this is a predecessor of the currentState)
auto const & groupStart = transitionMatrix . getRowGroupIndices ( ) [ predecessorEntryIt - > getColumn ( ) ] ;
auto const & groupEnd = transitionMatrix . getRowGroupIndices ( ) [ predecessorEntryIt - > getColumn ( ) + 1 ] ;
for ( uint64_t row = groupStart ; row < groupEnd ; + + row ) {
bool hasSuccessorInProcessedStates = false ;
for ( auto const & successorOfPredecessor : transitionMatrix . getRow ( row ) ) {
if ( processedStates . get ( successorOfPredecessor . getColumn ( ) ) ) {
hasSuccessorInProcessedStates = true ;
break ;
}
}
if ( hasSuccessorInProcessedStates ) {
result [ predecessorEntryIt - > getColumn ( ) ] = row - groupStart ;
processedStates . set ( predecessorEntryIt - > getColumn ( ) , true ) ;
stack . push_back ( predecessorEntryIt - > getColumn ( ) ) ;
break ;
}
}
}
}
}
STORM_LOG_ASSERT ( processedStates . full ( ) , " Not all states have been processed. " ) ;
return result ;
}
template < class SparseModelType >
void StandardPcaaWeightVectorChecker < SparseModelType > : : unboundedWeightedPhase ( Environment const & env , std : : vector < ValueType > const & weightedRewardVector , std : : vector < ValueType > const & weightVector ) {
if ( this - > objectivesWithNoUpperTimeBound . empty ( ) | | ! storm : : utility : : vector : : hasNonZeroEntry ( weightedRewardVector ) ) {
this - > weightedResult = std : : vector < ValueType > ( transitionMatrix . getRowGroupCount ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
this - > optimalChoices = std : : vector < uint_fast64_t > ( transitionMatrix . getRowGroupCount ( ) , 0 ) ;
// Get an arbitrary scheduler that yields finite reward for all objectives
this - > optimalChoices = computeSchedulerFinitelyOften ( transitionMatrix , transitionMatrix . transpose ( true ) , ~ actionsWithoutRewardInUnboundedPhase ) ;
return ;
}