@ -1,5 +1,5 @@
# ifndef STORM_TRANSFORMER_EFFECTLESSM ECREMOVER_H
# define STORM_TRANSFORMER_EFFECTLESSM ECREMOVER_H
# ifndef STORM_TRANSFORMER_NEUTRAL ECREMOVER_H
# define STORM_TRANSFORMER_NEUTRAL ECREMOVER_H
# include "src/utility/constants.h"
@ -12,52 +12,51 @@ namespace storm {
namespace transformer {
template < typename ValueType >
class EffectlessM ECRemover {
class Neutral ECRemover {
public :
struct EffectlessM ECRemoverReturnType {
struct Neutral ECRemoverReturnType {
/ / The resulting matrix
storm : : storage : : SparseMatrix < ValueType > matrix ;
/ / The resulting vector
std : : vector < ValueType > vector ;
/ / Index mapping that gives for each row of the resulting matrix and vector the corresponding row in the original matrix and vector .
/ / For the rows that lead to the newly introduced sink state , some row of the original matrix that stays inside the EC is given .
/ / The selfloop of the newly introduced sink state has no entry , i . e . , matrix . rowCount ( ) = = newToOldRowMapping . size ( ) + 1.
/ / For the empty rows added to EC states , some row of the original matrix that stays inside the EC is given .
std : : vector < uint_fast64_t > newToOldRowMapping ;
/ / Gives for each state ( = rowGroup ) of the original matrix and vector the corresponding state in the resulting matrix and vector .
/ / if the given state does not exist in the result , the returned value will be numeric_limits < uint_fast64_t > : : max ( )
/ / if the given state does not exist in the result , the returned value will be std : : numeric_limits < uint_fast64_t > : : max ( ) , i . e . , an invalid index .
std : : vector < uint_fast64_t > oldToNewStateMapping ;
} ;
/*
* Identifies maximal effectless end components and replaces them by a single state .
* Identifies neutral end components and replaces them by a single state .
*
* A choice is effectless , iff the given vector is zero at the corresponding row .
* An EC is effectless iff it only consideres effectless choices .
* For each such EC that is not contained by another effectles EC , we add a new state and redirect all incoming and outgoing
* A choice is neutral , iff the given vector is zero at the corresponding row .
* An EC is neutral iff it only consideres neutral choices .
* For each such EC that is not contained by another neutral EC , we add a new state and redirect all incoming and outgoing
* transitions of the EC to ( and from ) this state .
* If allowChoiceToSink is true for at least one state in an effectless EC , a choice that leads to a sink state is added to the new state .
* States from which all reachable choices are effectless will be removed .
* If allowEmptyRow is true for at least one state in a neutral EC , an empty row is added to the new state ( representing the choice to stay at the neutral EC forever ) .
* States from which all reachable choices are neutral will be removed .
*
*/
static EffectlessM ECRemoverReturnType transform ( storm : : storage : : SparseMatrix < ValueType > const & originalMatrix , std : : vector < ValueType > const & originalVector , storm : : storage : : BitVector const & allowChoiceToSink ) {
STORM_LOG_DEBUG ( " Invoked EffectlessM ECRemover on matrix with " < < originalMatrix . getRowGroupCount ( ) < < " row groups. " ) ;
static Neutral ECRemoverReturnType transform ( storm : : storage : : SparseMatrix < ValueType > const & originalMatrix , std : : vector < ValueType > const & originalVector , storm : : storage : : BitVector const & allowEmptyRow ) {
STORM_LOG_DEBUG ( " Invoked Neutral ECRemover on matrix with " < < originalMatrix . getRowGroupCount ( ) < < " row groups. " ) ;
storm : : storage : : BitVector keptStates = computeStatesFromWhichNonEffectless ChoiceIsReachable ( originalMatrix , originalVector ) ;
storm : : storage : : MaximalEndComponentDecomposition < ValueType > effectlessECs = computeEffectless ECs( originalMatrix , originalVector , keptStates ) ;
storm : : storage : : BitVector keptStates = computeStatesFromWhichNonNeutral ChoiceIsReachable ( originalMatrix , originalVector ) ;
storm : : storage : : MaximalEndComponentDecomposition < ValueType > neutralECs = computeNeutral ECs( originalMatrix , originalVector , keptStates ) ;
/ / further shrink the set of kept states by removing all states that are part of an effectless EC
for ( auto const & ec : effectless ECs) {
/ / further shrink the set of kept states by removing all states that are part of a neutral EC
for ( auto const & ec : neutral ECs) {
for ( auto const & stateActionsPair : ec ) {
keptStates . set ( stateActionsPair . first , false ) ;
}
}
STORM_LOG_DEBUG ( " Found " < < effectless ECs. size ( ) < < " effectless End Components. Keeping " < < keptStates . getNumberOfSetBits ( ) < < " of " < < keptStates . size ( ) < < " original states. " ) ;
STORM_LOG_DEBUG ( " Found " < < neutral ECs. size ( ) < < " neutral End Components. Keeping " < < keptStates . getNumberOfSetBits ( ) < < " of " < < keptStates . size ( ) < < " original states. " ) ;
EffectlessM ECRemoverReturnType result ;
Neutral ECRemoverReturnType result ;
std : : vector < uint_fast64_t > newRowGroupIndices ;
result . oldToNewStateMapping = std : : vector < uint_fast64_t > ( originalMatrix . getRowGroupCount ( ) , std : : numeric_limits < uint_fast64_t > : : max ( ) ) ;
storm : : storage : : BitVector rowsToSinkState ( originalMatrix . getRowCount ( ) , false ) ; / / will be resized as soon as rowCount of resulting matrix is known
storm : : storage : : BitVector emptyRows ( originalMatrix . getRowCount ( ) , false ) ; / / will be resized as soon as the rowCount of the resulting matrix is known
for ( auto keptState : keptStates ) {
result . oldToNewStateMapping [ keptState ] = newRowGroupIndices . size ( ) ; / / i . e . , the current number of processed states
@ -66,9 +65,9 @@ namespace storm {
result . newToOldRowMapping . push_back ( oldRow ) ;
}
}
for ( auto const & ec : effectless ECs) {
for ( auto const & ec : neutral ECs) {
newRowGroupIndices . push_back ( result . newToOldRowMapping . size ( ) ) ;
bool ecHasChoiceToSink = false ;
bool ecGetsEmptyRow = false ;
for ( auto const & stateActionsPair : ec ) {
result . oldToNewStateMapping [ stateActionsPair . first ] = newRowGroupIndices . size ( ) - 1 ;
for ( uint_fast64_t choice = 0 ; choice < originalMatrix . getRowGroupSize ( stateActionsPair . first ) ; + + choice ) {
@ -76,54 +75,52 @@ namespace storm {
result . newToOldRowMapping . push_back ( originalMatrix . getRowGroupIndices ( ) [ stateActionsPair . first ] + choice ) ;
}
}
ecHasChoiceToSink | = allowChoiceToSink . get ( stateActionsPair . first ) ;
ecGetsEmptyRow | = allowEmptyRow . get ( stateActionsPair . first ) ;
}
if ( ecHasChoiceToSink ) {
if ( ecGetsEmptyRow ) {
STORM_LOG_ASSERT ( result . newToOldRowMapping . size ( ) < originalMatrix . getRowCount ( ) , " Didn't expect to see more rows in the reduced matrix than in the original one. " ) ;
rowsToSinkState . set ( result . newToOldRowMapping . size ( ) , true ) ;
emptyRows . set ( result . newToOldRowMapping . size ( ) , true ) ;
result . newToOldRowMapping . push_back ( originalMatrix . getRowGroupIndices ( ) [ ec . begin ( ) - > first ] + ( * ec . begin ( ) - > second . begin ( ) ) ) ;
}
}
newRowGroupIndices . push_back ( result . newToOldRowMapping . size ( ) ) ;
newRowGroupIndices . push_back ( result . newToOldRowMapping . size ( ) + 1 ) ;
rowsToSinkState . resize ( result . newToOldRowMapping . size ( ) ) ;
emptyRows . resize ( result . newToOldRowMapping . size ( ) ) ;
result . matrix = buildTransformedMatrix ( originalMatrix , newRowGroupIndices , result . newToOldRowMapping , result . oldToNewStateMapping , rowsToSinkState ) ;
result . matrix = buildTransformedMatrix ( originalMatrix , newRowGroupIndices , result . newToOldRowMapping , result . oldToNewStateMapping , emptyRows ) ;
result . vector = buildTransformedVector ( originalVector , result . newToOldRowMapping ) ;
STORM_LOG_DEBUG ( " EffectlessMECRemover is done. Resulting matrix has " < < result . matrix . getRowGroupCount ( ) < < " row groups. " ) ;
STORM_LOG_DEBUG ( " NeutralECRemover is done. Resulting matrix has " < < result . matrix . getRowGroupCount ( ) < < " row groups. Resulting Matrix: " < < std : : endl < < result . matrix < < std : : endl < < " resulting vector: " < < result . vector ) ;
return result ;
}
private :
static storm : : storage : : BitVector computeStatesFromWhichNonEffectless ChoiceIsReachable ( storm : : storage : : SparseMatrix < ValueType > const & originalMatrix , std : : vector < ValueType > const & originalVector ) {
storm : : storage : : BitVector statesWithNonEffectless Choice ( originalMatrix . getRowGroupCount ( ) , false ) ;
static storm : : storage : : BitVector computeStatesFromWhichNonNeutral ChoiceIsReachable ( storm : : storage : : SparseMatrix < ValueType > const & originalMatrix , std : : vector < ValueType > const & originalVector ) {
storm : : storage : : BitVector statesWithNonNeutral Choice ( originalMatrix . getRowGroupCount ( ) , false ) ;
for ( uint_fast64_t rowGroup = 0 ; rowGroup < originalMatrix . getRowGroupCount ( ) ; + + rowGroup ) {
for ( uint_fast64_t row = originalMatrix . getRowGroupIndices ( ) [ rowGroup ] ; row < originalMatrix . getRowGroupIndices ( ) [ rowGroup + 1 ] ; + + row ) {
if ( ! storm : : utility : : isZero ( originalVector [ row ] ) ) {
statesWithNonEffectless Choice . set ( rowGroup ) ;
statesWithNonNeutral Choice . set ( rowGroup ) ;
break ;
}
}
}
storm : : storage : : BitVector trueVector ( originalMatrix . getRowGroupCount ( ) , true ) ;
return storm : : utility : : graph : : performProbGreater0E ( originalMatrix , originalMatrix . getRowGroupIndices ( ) , originalMatrix . transpose ( true ) , trueVector , statesWithNonEffectless Choice ) ;
return storm : : utility : : graph : : performProbGreater0E ( originalMatrix , originalMatrix . getRowGroupIndices ( ) , originalMatrix . transpose ( true ) , trueVector , statesWithNonNeutral Choice ) ;
}
static storm : : storage : : MaximalEndComponentDecomposition < ValueType > computeEffectless ECs ( storm : : storage : : SparseMatrix < ValueType > const & originalMatrix , std : : vector < ValueType > const & originalVector , storm : : storage : : BitVector const & keptStates ) {
/ / Get an auxiliary matrix to identify the effectless end components .
/ / This is done by redirecting choices that can never be part of an effectless EC to a sink state .
/ / Such choices are either non - effectless choices or choices that lead to a state that is not in keptStates .
storm : : storage : : BitVector effectless Choices = storm : : utility : : vector : : filter < ValueType > ( originalVector , [ & ] ( ValueType const & value ) - > bool { return storm : : utility : : isZero ( value ) ; } ) ;
static storm : : storage : : MaximalEndComponentDecomposition < ValueType > computeNeutral ECs ( storm : : storage : : SparseMatrix < ValueType > const & originalMatrix , std : : vector < ValueType > const & originalVector , storm : : storage : : BitVector const & keptStates ) {
/ / Get an auxiliary matrix to identify the neutral end components .
/ / This is done by redirecting choices that can never be part of a neutral EC to a sink state .
/ / Such choices are either non - neutral choices or choices that lead to a state that is not in keptStates .
storm : : storage : : BitVector neutral Choices = storm : : utility : : vector : : filter < ValueType > ( originalVector , [ & ] ( ValueType const & value ) - > bool { return storm : : utility : : isZero ( value ) ; } ) ;
uint_fast64_t sinkState = originalMatrix . getRowGroupCount ( ) ;
storm : : storage : : SparseMatrixBuilder < ValueType > builder ( originalMatrix . getRowCount ( ) + 1 , originalMatrix . getColumnCount ( ) + 1 , originalMatrix . getEntryCount ( ) + 1 , false , true , originalMatrix . getRowGroupCount ( ) + 1 ) ;
uint_fast64_t row = 0 ;
for ( uint_fast64_t rowGroup = 0 ; rowGroup < originalMatrix . getRowGroupCount ( ) ; + + rowGroup ) {
builder . newRowGroup ( row ) ;
for ( ; row < originalMatrix . getRowGroupIndices ( ) [ rowGroup + 1 ] ; + + row ) {
bool keepRow = effectless Choices. get ( row ) ;
bool keepRow = neutral Choices. get ( row ) ;
if ( keepRow ) { / / Also check whether all successors are kept
for ( auto const & entry : originalMatrix . getRow ( row ) ) {
keepRow & = keptStates . get ( entry . getColumn ( ) ) ;
@ -140,7 +137,7 @@ namespace storm {
}
builder . newRowGroup ( row ) ;
builder . addNextValue ( row , sinkState , storm : : utility : : one < ValueType > ( ) ) ;
storm : : storage : : SparseMatrix < ValueType > auxiliaryMatrix = builder . build ( ) ;
storm : : storage : : SparseMatrix < ValueType > auxiliaryMatrix = builder . build ( originalMatrix . getRowCount ( ) + 1 , originalMatrix . getColumnCount ( ) + 1 , originalMatrix . getRowGroupCount ( ) + 1 ) ;
storm : : storage : : SparseMatrix < ValueType > backwardsTransitions = auxiliaryMatrix . transpose ( true ) ;
storm : : storage : : BitVector sinkStateAsBitVector ( auxiliaryMatrix . getRowGroupCount ( ) , false ) ;
sinkStateAsBitVector . set ( sinkState ) ;
@ -155,29 +152,25 @@ namespace storm {
std : : vector < uint_fast64_t > const & newRowGroupIndices ,
std : : vector < uint_fast64_t > const & newToOldRowMapping ,
std : : vector < uint_fast64_t > const & oldToNewStateMapping ,
storm : : storage : : BitVector const & rowsToSinkState ) {
storm : : storage : : BitVector const & emptyRows ) {
uint_fast64_t numRowGroups = newRowGroupIndices . size ( ) - 1 ;
uint_fast64_t sinkState = numRowGroups - 1 ;
storm : : storage : : SparseMatrixBuilder < ValueType > builder ( newToOldRowMapping . size ( ) + 1 , numRowGroups , 0 , false , true , numRowGroups ) ;
/ / Insert all matrix entries except the selfloop of the sink state
for ( uint_fast64_t newRowGroup = 0 ; newRowGroup < numRowGroups - 1 ; + + newRowGroup ) {
uint_fast64_t newRow = newRowGroupIndices [ newRowGroup ] ;
uint_fast64_t newRow = 0 ;
storm : : storage : : SparseMatrixBuilder < ValueType > builder ( newToOldRowMapping . size ( ) , numRowGroups , originalMatrix . getEntryCount ( ) , false , true , numRowGroups ) ;
for ( uint_fast64_t newRowGroup = 0 ; newRowGroup < numRowGroups ; + + newRowGroup ) {
builder . newRowGroup ( newRow ) ;
for ( ; newRow < newRowGroupIndices [ newRowGroup + 1 ] ; + + newRow ) {
if ( rowsToSinkState . get ( newRow ) ) {
builder . addNextValue ( newRow , sinkState , storm : : utility : : one < ValueType > ( ) ) ;
} else {
if ( ! emptyRows . get ( newRow ) ) {
/ / Make sure that the entries for this row are inserted in the right order .
/ / Also , transitions to the same EC need to be merged . and transitions to states that are erased need to be ignored
/ / Also , transitions to the same EC need to be merged and transitions to states that are erased need to be ignored
std : : map < uint_fast64_t , ValueType > sortedEntries ;
for ( auto const & entry : originalMatrix . getRow ( newToOldRowMapping [ newRow ] ) ) {
uint_fast64_t newColumn = oldToNewStateMapping [ entry . getColumn ( ) ] ;
if ( newColumn < numRowGroups ) {
auto insertRes = sortedEntries . insert ( std : : make_pair ( newColumn , entry . getValue ( ) ) ) ;
if ( ! insertRes . second ) {
auto insertResult = sortedEntries . insert ( std : : make_pair ( newColumn , entry . getValue ( ) ) ) ;
if ( ! insertResult . second ) {
/ / We have already seen an entry with this column . = = > merge transitions
insertRes . first - > second + = entry . getValue ( ) ;
insertResult . first - > second + = entry . getValue ( ) ;
}
}
}
@ -187,25 +180,19 @@ namespace storm {
}
}
}
/ / Now add the selfloop at the sink state
builder . newRowGroup ( newRowGroupIndices [ sinkState ] ) ;
builder . addNextValue ( newRowGroupIndices [ sinkState ] , sinkState , storm : : utility : : one < ValueType > ( ) ) ;
return builder . build ( ) ;
return builder . build ( newToOldRowMapping . size ( ) , numRowGroups , numRowGroups ) ;
}
static std : : vector < ValueType > buildTransformedVector ( std : : vector < ValueType > const & originalVector , std : : vector < uint_fast64_t > const & newToOldRowMapping ) {
std : : vector < ValueType > v ;
v . reserve ( newToOldRowMapping . size ( ) + 1 ) ;
v . reserve ( newToOldRowMapping . size ( ) ) ;
for ( auto const & oldRow : newToOldRowMapping ) {
v . push_back ( originalVector [ oldRow ] ) ;
}
/ / add entry for the sink state
v . push_back ( storm : : utility : : zero < ValueType > ( ) ) ;
return v ;
}
} ;
}
}
# endif / / STORM_TRANSFORMER_EFFECTLESSM ECREMOVER_H
# endif / / STORM_TRANSFORMER_NEUTRAL ECREMOVER_H