Browse Source
handling of end components in which no reward is earned
handling of end components in which no reward is earned
Former-commit-id: 84f6149011
main
3 changed files with 261 additions and 45 deletions
-
4src/modelchecker/multiobjective/helper/SparseMultiObjectiveModelCheckerHelper.cpp
-
91src/modelchecker/multiobjective/helper/SparseWeightedObjectivesModelCheckerHelper.cpp
-
211src/transformer/EffectlessMECRemover.h
@ -0,0 +1,211 @@ |
|||
#ifndef STORM_TRANSFORMER_EFFECTLESSMECREMOVER_H |
|||
#define STORM_TRANSFORMER_EFFECTLESSMECREMOVER_H |
|||
|
|||
|
|||
#include "src/utility/constants.h" |
|||
#include "src/utility/macros.h" |
|||
#include "src/utility/graph.h" |
|||
#include "src/utility/vector.h" |
|||
#include "src/storage/MaximalEndComponentDecomposition.h" |
|||
|
|||
namespace storm { |
|||
namespace transformer { |
|||
|
|||
template <typename ValueType> |
|||
class EffectlessMECRemover { |
|||
public: |
|||
|
|||
struct EffectlessMECRemoverReturnType { |
|||
// 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. |
|||
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() |
|||
std::vector<uint_fast64_t> oldToNewStateMapping; |
|||
}; |
|||
|
|||
/* |
|||
* Identifies maximal effectless 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 |
|||
* 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. |
|||
* |
|||
*/ |
|||
static EffectlessMECRemoverReturnType transform(storm::storage::SparseMatrix<ValueType> const& originalMatrix, std::vector<ValueType> const& originalVector, storm::storage::BitVector const& allowChoiceToSink) { |
|||
STORM_LOG_DEBUG("Invoked EffectlessMECRemover on matrix with " << originalMatrix.getRowGroupCount() << " row groups."); |
|||
|
|||
storm::storage::BitVector keptStates = computeStatesFromWhichNonEffectlessChoiceIsReachable(originalMatrix, originalVector); |
|||
storm::storage::MaximalEndComponentDecomposition<ValueType> effectlessECs = computeEffectlessECs(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 : effectlessECs) { |
|||
for (auto const& stateActionsPair : ec) { |
|||
keptStates.set(stateActionsPair.first, false); |
|||
} |
|||
} |
|||
STORM_LOG_DEBUG("Found " << effectlessECs.size() << " effectless End Components. Keeping " << keptStates.getNumberOfSetBits() << " of " << keptStates.size() << " original states."); |
|||
|
|||
EffectlessMECRemoverReturnType 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 |
|||
|
|||
for(auto keptState : keptStates) { |
|||
result.oldToNewStateMapping[keptState] = newRowGroupIndices.size(); // i.e., the current number of processed states |
|||
newRowGroupIndices.push_back(result.newToOldRowMapping.size()); // i.e., the current number of processed rows |
|||
for(uint_fast64_t oldRow = originalMatrix.getRowGroupIndices()[keptState]; oldRow < originalMatrix.getRowGroupIndices()[keptState + 1]; ++oldRow) { |
|||
result.newToOldRowMapping.push_back(oldRow); |
|||
} |
|||
} |
|||
for (auto const& ec : effectlessECs) { |
|||
newRowGroupIndices.push_back(result.newToOldRowMapping.size()); |
|||
bool ecHasChoiceToSink = 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) { |
|||
if(stateActionsPair.second.find(choice) == stateActionsPair.second.end()) { |
|||
result.newToOldRowMapping.push_back(originalMatrix.getRowGroupIndices()[stateActionsPair.first] + choice); |
|||
} |
|||
} |
|||
ecHasChoiceToSink |= allowChoiceToSink.get(stateActionsPair.first); |
|||
} |
|||
if(ecHasChoiceToSink) { |
|||
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); |
|||
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()); |
|||
|
|||
result.matrix = buildTransformedMatrix(originalMatrix, newRowGroupIndices, result.newToOldRowMapping, result.oldToNewStateMapping, rowsToSinkState); |
|||
result.vector = buildTransformedVector(originalVector, result.newToOldRowMapping); |
|||
|
|||
STORM_LOG_DEBUG("EffectlessMECRemover is done. Resulting matrix has " << result.matrix.getRowGroupCount() << " row groups."); |
|||
return result; |
|||
} |
|||
|
|||
private: |
|||
|
|||
static storm::storage::BitVector computeStatesFromWhichNonEffectlessChoiceIsReachable(storm::storage::SparseMatrix<ValueType> const& originalMatrix, std::vector<ValueType> const& originalVector) { |
|||
storm::storage::BitVector statesWithNonEffectlessChoice(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])) { |
|||
statesWithNonEffectlessChoice.set(rowGroup); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
storm::storage::BitVector trueVector(originalMatrix.getRowGroupCount(), true); |
|||
return storm::utility::graph::performProbGreater0E(originalMatrix, originalMatrix.getRowGroupIndices(), originalMatrix.transpose(true), trueVector, statesWithNonEffectlessChoice); |
|||
} |
|||
|
|||
static storm::storage::MaximalEndComponentDecomposition<ValueType> computeEffectlessECs(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 effectlessChoices = 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 = effectlessChoices.get(row); |
|||
if(keepRow) { //Also check whether all successors are kept |
|||
for(auto const& entry : originalMatrix.getRow(row)){ |
|||
keepRow &= keptStates.get(entry.getColumn()); |
|||
} |
|||
} |
|||
if(keepRow) { |
|||
for(auto const& entry : originalMatrix.getRow(row)){ |
|||
builder.addNextValue(row, entry.getColumn(), entry.getValue()); |
|||
} |
|||
} else { |
|||
builder.addNextValue(row, sinkState, storm::utility::one<ValueType>()); |
|||
} |
|||
} |
|||
} |
|||
builder.newRowGroup(row); |
|||
builder.addNextValue(row, sinkState, storm::utility::one<ValueType>()); |
|||
storm::storage::SparseMatrix<ValueType> auxiliaryMatrix = builder.build(); |
|||
storm::storage::SparseMatrix<ValueType> backwardsTransitions = auxiliaryMatrix.transpose(true); |
|||
storm::storage::BitVector sinkStateAsBitVector(auxiliaryMatrix.getRowGroupCount(), false); |
|||
sinkStateAsBitVector.set(sinkState); |
|||
storm::storage::BitVector subsystem = keptStates; |
|||
subsystem.resize(keptStates.size() + 1, true); |
|||
// The states for which sinkState is reachable under any scheduler can not be part of an EC |
|||
subsystem &= ~(storm::utility::graph::performProbGreater0A(auxiliaryMatrix, auxiliaryMatrix.getRowGroupIndices(), backwardsTransitions, subsystem, sinkStateAsBitVector)); |
|||
return storm::storage::MaximalEndComponentDecomposition<ValueType>(auxiliaryMatrix, backwardsTransitions, subsystem); |
|||
} |
|||
|
|||
static storm::storage::SparseMatrix<ValueType> buildTransformedMatrix(storm::storage::SparseMatrix<ValueType> const& originalMatrix, |
|||
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) { |
|||
|
|||
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]; |
|||
builder.newRowGroup(newRow); |
|||
for(; newRow < newRowGroupIndices[newRowGroup+1]; ++newRow) { |
|||
if(rowsToSinkState.get(newRow)) { |
|||
builder.addNextValue(newRow, sinkState, storm::utility::one<ValueType>()); |
|||
} else { |
|||
// 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 |
|||
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) { |
|||
// We have already seen an entry with this column. ==> merge transitions |
|||
insertRes.first->second += entry.getValue(); |
|||
} |
|||
} |
|||
} |
|||
for(auto const& sortedEntry : sortedEntries) { |
|||
builder.addNextValue(newRow, sortedEntry.first, sortedEntry.second); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
//Now add the selfloop at the sink state |
|||
builder.newRowGroup(newRowGroupIndices[sinkState]); |
|||
builder.addNextValue(newRowGroupIndices[sinkState], sinkState, storm::utility::one<ValueType>()); |
|||
|
|||
return builder.build(); |
|||
} |
|||
|
|||
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); |
|||
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_EFFECTLESSMECREMOVER_H |
Write
Preview
Loading…
Cancel
Save
Reference in new issue