Browse Source

zero-reward MEC elimination for reachability rewards

tempestpy_adaptions
dehnert 7 years ago
parent
commit
b4a0016362
  1. 233
      src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp
  2. 43
      src/storm/storage/MaximalEndComponentDecomposition.cpp
  3. 25
      src/storm/storage/MaximalEndComponentDecomposition.h

233
src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp

@ -305,7 +305,7 @@ namespace storm {
// Initialize the solution vector.
std::vector<ValueType> x = hint.hasValueHint() ? std::move(hint.getValueHint()) : std::vector<ValueType>(submatrix.getRowGroupCount(), hint.hasLowerResultBound() ? hint.getLowerResultBound() : storm::utility::zero<ValueType>());
// Solve the corresponding system of equations.
solver->solveEquations(x, b);
@ -423,10 +423,10 @@ namespace storm {
struct SparseMdpEndComponentInformation {
SparseMdpEndComponentInformation(storm::storage::MaximalEndComponentDecomposition<ValueType> const& endComponentDecomposition, storm::storage::BitVector const& maybeStates) : eliminatedEndComponents(false), numberOfMaybeStatesInEc(0), numberOfMaybeStatesNotInEc(0), numberOfEc(endComponentDecomposition.size()) {
// (0) Compute how many maybe states there are before each other maybe state.
// (1) Compute how many maybe states there are before each other maybe state.
maybeStatesBefore = maybeStates.getNumberOfSetBitsBeforeIndices();
// (1) Create mapping from maybe states to their MEC. If they are not contained in an MEC, their value
// (2) Create mapping from maybe states to their MEC. If they are not contained in an MEC, their value
// is set to a special constant.
maybeStateToEc.resize(maybeStates.getNumberOfSetBits(), NOT_IN_EC);
uint64_t mecIndex = 0;
@ -437,6 +437,9 @@ namespace storm {
}
++mecIndex;
}
// (3) Compute number of states not in MECs.
numberOfMaybeStatesNotInEc = maybeStateToEc.size() - numberOfMaybeStatesInEc;
}
bool isMaybeStateInEc(uint64_t maybeState) const {
@ -467,6 +470,10 @@ namespace storm {
return maybeStateToEc[maybeStatesBefore[state]];
}
uint64_t getSubmatrixRowGroupOfStateInEc(uint64_t state) const {
return numberOfMaybeStatesNotInEc + getEc(state);
}
bool eliminatedEndComponents;
std::vector<uint64_t> maybeStatesBefore;
@ -478,37 +485,48 @@ namespace storm {
};
template<typename ValueType>
SparseMdpEndComponentInformation<ValueType> eliminateEndComponents(storm::storage::MaximalEndComponentDecomposition<ValueType> const& endComponentDecomposition, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, QualitativeStateSetsUntilProbabilities const& qualitativeStateSets, storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& b) {
SparseMdpEndComponentInformation<ValueType> eliminateEndComponents(storm::storage::MaximalEndComponentDecomposition<ValueType> const& endComponentDecomposition, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const* sumColumns, storm::storage::BitVector const* selectedChoices, std::vector<ValueType> const* summand, storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& b) {
SparseMdpEndComponentInformation<ValueType> result(endComponentDecomposition, qualitativeStateSets.maybeStates);
SparseMdpEndComponentInformation<ValueType> result(endComponentDecomposition, maybeStates);
// (2) Compute the number of maybe states not in ECs before any other maybe state.
// (1) Compute the number of maybe states not in ECs before any other maybe state.
std::vector<uint64_t> maybeStatesNotInEcBefore = result.getNumberOfMaybeStatesNotInEcBeforeIndices();
uint64_t numberOfMaybeStatesNotInEc = qualitativeStateSets.maybeStates.getNumberOfSetBits() - result.numberOfMaybeStatesInEc;
// Create temporary vector storing possible transitions to ECs.
std::vector<std::pair<uint64_t, ValueType>> ecValuePairs;
// (3) Create the parts of the submatrix and vector b that belong to states not contained in ECs.
storm::storage::SparseMatrixBuilder<ValueType> builder(0, 0, 0, false, true, result.numberOfMaybeStatesNotInEc + result.numberOfEc);
b.resize(result.numberOfMaybeStatesNotInEc + result.numberOfEc);
// (2) Create the parts of the submatrix and vector b that belong to states not contained in ECs.
uint64_t numberOfStates = result.numberOfMaybeStatesNotInEc + result.numberOfEc;
STORM_LOG_TRACE("Found " << numberOfStates << " states, " << result.numberOfMaybeStatesNotInEc << " not in ECs, " << result.numberOfMaybeStatesInEc << " in ECs and " << result.numberOfEc << " ECs.");
storm::storage::SparseMatrixBuilder<ValueType> builder(0, numberOfStates, 0, true, true, numberOfStates);
b.resize(numberOfStates);
uint64_t currentRow = 0;
for (auto state : qualitativeStateSets.maybeStates) {
for (auto state : maybeStates) {
if (!result.isStateInEc(state)) {
builder.newRowGroup(currentRow);
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row, ++currentRow) {
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
// If the choices is not in the selected ones, drop it.
if (selectedChoices && !selectedChoices->get(row)) {
continue;
}
ecValuePairs.clear();
if (summand) {
b[currentRow] += (*summand)[row];
}
for (auto const& e : transitionMatrix.getRow(row)) {
if (qualitativeStateSets.statesWithProbability1.get(e.getColumn())) {
if (sumColumns && sumColumns->get(e.getColumn())) {
b[currentRow] += e.getValue();
} else if (qualitativeStateSets.maybeStates.get(e.getColumn())) {
} else if (maybeStates.get(e.getColumn())) {
// If the target state of the transition is not contained in an EC, we can just add the entry.
if (result.isStateInEc(e.getColumn())) {
builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
} else {
// Otherwise, we store the information that the state can go to a certain EC.
ecValuePairs.push_back(std::make_pair(result.getEc(e.getColumn()), e.getValue()));
ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
}
}
}
@ -517,16 +535,19 @@ namespace storm {
std::sort(ecValuePairs.begin(), ecValuePairs.end());
for (auto const& e : ecValuePairs) {
builder.addNextValue(currentRow, numberOfMaybeStatesNotInEc + e.first, e.second);
builder.addNextValue(currentRow, result.numberOfMaybeStatesNotInEc + e.first, e.second);
}
}
++currentRow;
}
}
}
// (4) Create the parts of the submatrix and vector b that belong to states contained in ECs.
// (3) Create the parts of the submatrix and vector b that belong to states contained in ECs.
for (auto const& mec : endComponentDecomposition) {
builder.newRowGroup(currentRow);
for (auto const& stateActions : mec) {
uint64_t const& state = stateActions.first;
for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row < endRow; ++row) {
@ -534,19 +555,26 @@ namespace storm {
if (stateActions.second.find(row) != stateActions.second.end()) {
continue;
}
// If the choices is not in the selected ones, drop it.
if (selectedChoices && !selectedChoices->get(row)) {
continue;
}
ecValuePairs.clear();
if (summand) {
b[currentRow] += (*summand)[row];
}
for (auto const& e : transitionMatrix.getRow(row)) {
if (qualitativeStateSets.statesWithProbability1.get(e.getColumn())) {
if (sumColumns && sumColumns->get(e.getColumn())) {
b[currentRow] += e.getValue();
} else if (qualitativeStateSets.maybeStates.get(e.getColumn())) {
} else if (maybeStates.get(e.getColumn())) {
// If the target state of the transition is not contained in an EC, we can just add the entry.
if (result.isStateInEc(e.getColumn())) {
builder.addNextValue(currentRow, maybeStatesNotInEcBefore[result.maybeStatesBefore[e.getColumn()]], e.getValue());
} else {
// Otherwise, we store the information that the state can go to a certain EC.
ecValuePairs.push_back(std::make_pair(result.getEc(e.getColumn()), e.getValue()));
ecValuePairs.emplace_back(result.getEc(e.getColumn()), e.getValue());
}
}
}
@ -555,7 +583,7 @@ namespace storm {
std::sort(ecValuePairs.begin(), ecValuePairs.end());
for (auto const& e : ecValuePairs) {
builder.addNextValue(currentRow, numberOfMaybeStatesNotInEc + e.first, e.second);
builder.addNextValue(currentRow, result.numberOfMaybeStatesNotInEc + e.first, e.second);
}
}
@ -565,7 +593,6 @@ namespace storm {
}
submatrix = builder.build();
return result;
}
@ -578,7 +605,7 @@ namespace storm {
// Only do more work if there are actually end-components.
if (!endComponentDecomposition.empty()) {
STORM_LOG_DEBUG("Eliminating " << endComponentDecomposition.size() << " ECs.");
return eliminateEndComponents(endComponentDecomposition, transitionMatrix, qualitativeStateSets, submatrix, b);
return eliminateEndComponents<ValueType>(endComponentDecomposition, transitionMatrix, qualitativeStateSets.maybeStates, &qualitativeStateSets.statesWithProbability1, nullptr, nullptr, submatrix, b);
} else {
STORM_LOG_DEBUG("Not eliminating ECs as there are none.");
computeFixedPointSystemUntilProbabilities(transitionMatrix, qualitativeStateSets, submatrix, b);
@ -591,7 +618,7 @@ namespace storm {
auto notInEcResultIt = result.begin();
for (auto state : maybeStates) {
if (ecInformation.isStateInEc(state)) {
result[state] = result[ecInformation.numberOfMaybeStatesNotInEc + ecInformation.getEc(state)];
result[state] = result[ecInformation.getSubmatrixRowGroupOfStateInEc(state)];
} else {
result[state] = *notInEcResultIt;
++notInEcResultIt;
@ -635,7 +662,7 @@ namespace storm {
storm::storage::SparseMatrix<ValueType> submatrix;
std::vector<ValueType> b;
// If the hint information tells us that we have to do an (M)EC decomposition, we compute one now.
// If the hint information tells us that we have to eliminate MECs, we do so now.
boost::optional<SparseMdpEndComponentInformation<ValueType>> ecInformation;
if (hintInformation.getEliminateEndComponents()) {
ecInformation = computeFixedPointSystemUntilProbabilitiesEliminateEndComponents(transitionMatrix, backwardTransitions, qualitativeStateSets, submatrix, b);
@ -643,6 +670,7 @@ namespace storm {
// Make sure we are not supposed to produce a scheduler if we actually eliminate end components.
STORM_LOG_THROW(!ecInformation || !ecInformation.get().eliminatedEndComponents || !produceScheduler, storm::exceptions::NotSupportedException, "Producing schedulers is not supported if end-components need to be eliminated for the solver.");
} else {
// Otherwise, we compute the standard equations.
computeFixedPointSystemUntilProbabilities(transitionMatrix, qualitativeStateSets, submatrix, b);
}
@ -841,6 +869,96 @@ namespace storm {
}
}
template<typename ValueType>
void extractSchedulerChoices(storm::storage::Scheduler<ValueType>& scheduler, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<uint_fast64_t> const& subChoices, storm::storage::BitVector const& maybeStates, boost::optional<storm::storage::BitVector> const& selectedChoices) {
auto subChoiceIt = subChoices.begin();
if (selectedChoices) {
for (auto maybeState : maybeStates) {
// find the rowindex that corresponds to the selected row of the submodel
uint_fast64_t firstRowIndex = transitionMatrix.getRowGroupIndices()[maybeState];
uint_fast64_t selectedRowIndex = selectedChoices->getNextSetIndex(firstRowIndex);
for (uint_fast64_t choice = 0; choice < *subChoiceIt; ++choice) {
selectedRowIndex = selectedChoices->getNextSetIndex(selectedRowIndex + 1);
}
scheduler.setChoice(selectedRowIndex - firstRowIndex, maybeState);
++subChoiceIt;
}
} else {
for (auto maybeState : maybeStates) {
scheduler.setChoice(*subChoiceIt, maybeState);
++subChoiceIt;
}
}
assert(subChoiceIt == subChoices.end());
}
template<typename ValueType>
void computeFixedPointSystemReachabilityRewards(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional<storm::storage::BitVector> const& selectedChoices, std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& b) {
// Remove rows and columns from the original transition probability matrix for states whose reward values are already known.
// If there are infinity states, we additionally have to remove choices of maybeState that lead to infinity.
if (qualitativeStateSets.infinityStates.empty()) {
submatrix = transitionMatrix.getSubmatrix(true, qualitativeStateSets.maybeStates, qualitativeStateSets.maybeStates, false);
b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix, qualitativeStateSets.maybeStates);
} else {
submatrix = transitionMatrix.getSubmatrix(false, *selectedChoices, qualitativeStateSets.maybeStates, false);
b = totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
storm::utility::vector::filterVectorInPlace(b, *selectedChoices);
}
}
template<typename ValueType>
boost::optional<SparseMdpEndComponentInformation<ValueType>> computeFixedPointSystemReachabilityRewardsEliminateEndComponents(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional<storm::storage::BitVector> const& selectedChoices, std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& b) {
// Start by computing the choices with reward 0, as we only want ECs within this fragment.
storm::storage::BitVector zeroRewardChoices(transitionMatrix.getRowCount());
// Get the rewards of all choices.
std::vector<ValueType> rewardVector = totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
uint64_t index = 0;
for (auto const& e : rewardVector) {
if (storm::utility::isZero(e)) {
zeroRewardChoices.set(index);
}
++index;
}
// Compute the states that have some zero reward choice.
storm::storage::BitVector candidateStates(qualitativeStateSets.maybeStates);
for (auto state : qualitativeStateSets.maybeStates) {
bool keepState = false;
for (auto row = transitionMatrix.getRowGroupIndices()[state], rowEnd = transitionMatrix.getRowGroupIndices()[state + 1]; row < rowEnd; ++row) {
if (zeroRewardChoices.get(row)) {
keepState = true;
break;
}
}
if (!keepState) {
candidateStates.set(state, false);
}
}
bool doDecomposition = !candidateStates.empty();
storm::storage::MaximalEndComponentDecomposition<ValueType> endComponentDecomposition;
if (doDecomposition) {
// Then compute the states that are in MECs with zero reward.
endComponentDecomposition = storm::storage::MaximalEndComponentDecomposition<ValueType>(transitionMatrix, backwardTransitions, candidateStates, zeroRewardChoices);
}
// Only do more work if there are actually end-components.
if (doDecomposition && !endComponentDecomposition.empty()) {
STORM_LOG_DEBUG("Eliminating " << endComponentDecomposition.size() << " ECs.");
return eliminateEndComponents<ValueType>(endComponentDecomposition, transitionMatrix, qualitativeStateSets.maybeStates, nullptr, selectedChoices ? &selectedChoices.get() : nullptr, &rewardVector, submatrix, b);
} else {
STORM_LOG_DEBUG("Not eliminating ECs as there are none.");
computeFixedPointSystemReachabilityRewards(transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b);
return boost::none;
}
}
template<typename ValueType>
MDPSparseModelCheckingHelperReturnType<ValueType> SparseMdpPrctlHelper<ValueType>::computeReachabilityRewardsHelper(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) {
@ -866,54 +984,45 @@ namespace storm {
} else {
if (!qualitativeStateSets.maybeStates.empty()) {
// In this case we have to compute the reward values for the remaining states.
// Store the choices that lead to non-infinity values. If none, all choices im maybe states can be selected.
boost::optional<storm::storage::BitVector> selectedChoices;
if (!qualitativeStateSets.infinityStates.empty()) {
selectedChoices = transitionMatrix.getRowFilter(qualitativeStateSets.maybeStates, ~qualitativeStateSets.infinityStates);
}
// Obtain proper hint information either from the provided hint or from requirements of the solver.
SparseMdpHintType<ValueType> hintInformation = computeHints(storm::solver::EquationSystemType::ReachabilityRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~targetStates, targetStates, minMaxLinearEquationSolverFactory, selectedChoices);
// Prepare matrix and vector for the equation system.
// Declare the components of the equation system we will solve.
storm::storage::SparseMatrix<ValueType> submatrix;
std::vector<ValueType> b;
// Remove rows and columns from the original transition probability matrix for states whose reward values are already known.
// If there are infinity states, we additionaly have to remove choices of maybeState that lead to infinity
boost::optional<storm::storage::BitVector> selectedChoices; // if not given, all maybeState choices are selected
if (qualitativeStateSets.infinityStates.empty()) {
submatrix = transitionMatrix.getSubmatrix(true, qualitativeStateSets.maybeStates, qualitativeStateSets.maybeStates, false);
b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix, qualitativeStateSets.maybeStates);
// If the hint information tells us that we have to eliminate MECs, we do so now.
boost::optional<SparseMdpEndComponentInformation<ValueType>> ecInformation;
if (hintInformation.getEliminateEndComponents()) {
ecInformation = computeFixedPointSystemReachabilityRewardsEliminateEndComponents(transitionMatrix, backwardTransitions, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b);
// Make sure we are not supposed to produce a scheduler if we actually eliminate end components.
STORM_LOG_THROW(!ecInformation || !ecInformation.get().eliminatedEndComponents || !produceScheduler, storm::exceptions::NotSupportedException, "Producing schedulers is not supported if end-components need to be eliminated for the solver.");
} else {
selectedChoices = transitionMatrix.getRowFilter(qualitativeStateSets.maybeStates, ~qualitativeStateSets.infinityStates);
submatrix = transitionMatrix.getSubmatrix(false, *selectedChoices, qualitativeStateSets.maybeStates, false);
b = totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
storm::utility::vector::filterVectorInPlace(b, *selectedChoices);
// Otherwise, we compute the standard equations.
computeFixedPointSystemReachabilityRewards(transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b);
}
// Obtain proper hint information either from the provided hint or from requirements of the solver.
SparseMdpHintType<ValueType> hintInformation = computeHints(storm::solver::EquationSystemType::ReachabilityRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~targetStates, targetStates, minMaxLinearEquationSolverFactory, selectedChoices);
// Now compute the results for the maybe states.
MaybeStateResult<ValueType> resultForMaybeStates = computeValuesForMaybeStates(goal, submatrix, b, produceScheduler, minMaxLinearEquationSolverFactory, hintInformation);
// Set values of resulting vector according to result.
storm::utility::vector::setVectorValues<ValueType>(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues());
// If we eliminated end components, we need to extract the result differently.
if (ecInformation && ecInformation.get().eliminatedEndComponents) {
setResultValuesWrtEndComponents(ecInformation.get(), result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues());
} else {
// Set values of resulting vector according to result.
storm::utility::vector::setVectorValues<ValueType>(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues());
}
if (produceScheduler) {
std::vector<uint_fast64_t> const& subChoices = resultForMaybeStates.getScheduler();
auto subChoiceIt = subChoices.begin();
if (selectedChoices) {
for (auto maybeState : qualitativeStateSets.maybeStates) {
// find the rowindex that corresponds to the selected row of the submodel
uint_fast64_t firstRowIndex = transitionMatrix.getRowGroupIndices()[maybeState];
uint_fast64_t selectedRowIndex = selectedChoices->getNextSetIndex(firstRowIndex);
for (uint_fast64_t choice = 0; choice < *subChoiceIt; ++choice) {
selectedRowIndex = selectedChoices->getNextSetIndex(selectedRowIndex + 1);
}
scheduler->setChoice(selectedRowIndex - firstRowIndex, maybeState);
++subChoiceIt;
}
} else {
for (auto maybeState : qualitativeStateSets.maybeStates) {
scheduler->setChoice(*subChoiceIt, maybeState);
++subChoiceIt;
}
}
assert(subChoiceIt == subChoices.end());
extractSchedulerChoices(*scheduler, transitionMatrix, resultForMaybeStates.getScheduler(), qualitativeStateSets.maybeStates, selectedChoices);
}
}
}

43
src/storm/storage/MaximalEndComponentDecomposition.cpp

@ -1,5 +1,6 @@
#include <list>
#include <queue>
#include <numeric>
#include "storm/models/sparse/StandardRewardModel.h"
@ -17,22 +18,27 @@ namespace storm {
template<typename ValueType>
template<typename RewardModelType>
MaximalEndComponentDecomposition<ValueType>::MaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType, RewardModelType> const& model) {
performMaximalEndComponentDecomposition(model.getTransitionMatrix(), model.getBackwardTransitions(), storm::storage::BitVector(model.getNumberOfStates(), true));
performMaximalEndComponentDecomposition(model.getTransitionMatrix(), model.getBackwardTransitions());
}
template<typename ValueType>
MaximalEndComponentDecomposition<ValueType>::MaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) {
performMaximalEndComponentDecomposition(transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
performMaximalEndComponentDecomposition(transitionMatrix, backwardTransitions);
}
template<typename ValueType>
MaximalEndComponentDecomposition<ValueType>::MaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& subsystem) {
performMaximalEndComponentDecomposition(transitionMatrix, backwardTransitions, subsystem);
MaximalEndComponentDecomposition<ValueType>::MaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states) {
performMaximalEndComponentDecomposition(transitionMatrix, backwardTransitions, &states);
}
template<typename ValueType>
MaximalEndComponentDecomposition<ValueType>::MaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType> const& model, storm::storage::BitVector const& subsystem) {
performMaximalEndComponentDecomposition(model.getTransitionMatrix(), model.getBackwardTransitions(), subsystem);
MaximalEndComponentDecomposition<ValueType>::MaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states, storm::storage::BitVector const& choices) {
performMaximalEndComponentDecomposition(transitionMatrix, backwardTransitions, &states, &choices);
}
template<typename ValueType>
MaximalEndComponentDecomposition<ValueType>::MaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType> const& model, storm::storage::BitVector const& states) {
performMaximalEndComponentDecomposition(model.getTransitionMatrix(), model.getBackwardTransitions(), &states);
}
template<typename ValueType>
@ -58,22 +64,23 @@ namespace storm {
}
template <typename ValueType>
void MaximalEndComponentDecomposition<ValueType>::performMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const& subsystem) {
void MaximalEndComponentDecomposition<ValueType>::performMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states, storm::storage::BitVector const* choices) {
// Get some data for convenient access.
uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices();
// Initialize the maximal end component list to be the full state space.
std::list<StateBlock> endComponentStateSets;
if(!subsystem.empty()) {
endComponentStateSets.emplace_back(subsystem.begin(), subsystem.end());
if (states) {
endComponentStateSets.emplace_back(states->begin(), states->end(), true);
} else {
std::vector<storm::storage::sparse::state_type> states;
states.resize(transitionMatrix.getRowGroupCount());
std::iota(states.begin(), states.end(), 0);
endComponentStateSets.emplace_back(states.begin(), states.end(), true);
}
storm::storage::BitVector statesToCheck(numberOfStates);
// The iterator used here should really be a const_iterator.
// However, gcc 4.8 (and assorted libraries) does not provide an erase(const_iterator) method for std::list
// but only an erase(iterator). This is in compliance with the c++11 draft N3337, which specifies the change
// from iterator to const_iterator only for "set, multiset, map [and] multimap".
for (std::list<StateBlock>::const_iterator mecIterator = endComponentStateSets.begin(); mecIterator != endComponentStateSets.end();) {
StateBlock const& mec = *mecIterator;
@ -98,6 +105,11 @@ namespace storm {
bool keepStateInMEC = false;
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
// If the choice is not part of our subsystem, skip it.
if (choices && !choices->get(choice)) {
continue;
}
bool choiceContainedInMEC = true;
for (auto const& entry : transitionMatrix.getRow(choice)) {
if (storm::utility::isZero(entry.getValue())) {
@ -168,6 +180,11 @@ namespace storm {
for (auto state : mecStateSet) {
MaximalEndComponent::set_type containedChoices;
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
// Skip the choice if it is not part of our subsystem.
if (choices && !choices->get(choice)) {
continue;
}
bool choiceContained = true;
for (auto const& entry : transitionMatrix.getRow(choice)) {
if (!mecStateSet.containsState(entry.getColumn())) {

25
src/storm/storage/MaximalEndComponentDecomposition.h

@ -40,17 +40,27 @@ namespace storm {
*
* @param transitionMatrix The transition relation of model to decompose into MECs.
* @param backwardTransition The reversed transition relation.
* @param subsystem The subsystem to decompose.
* @param states The states of the subsystem to decompose.
*/
MaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& subsystem);
MaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states);
/*
* Creates an MEC decomposition of the given subsystem of given model (represented by a row-grouped matrix).
*
* @param transitionMatrix The transition relation of model to decompose into MECs.
* @param backwardTransition The reversed transition relation.
* @param states The states of the subsystem to decompose.
* @param choices The choices of the subsystem to decompose.
*/
MaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states, storm::storage::BitVector const& choices);
/*!
* Creates an MEC decomposition of the given subsystem in the given model.
*
* @param model The model whose subsystem to decompose into MECs.
* @param subsystem The subsystem to decompose.
* @param states The states of the subsystem to decompose.
*/
MaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType> const& model, storm::storage::BitVector const& subsystem);
MaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType> const& model, storm::storage::BitVector const& states);
/*!
* Creates an MEC decomposition by copying the contents of the given MEC decomposition.
@ -87,9 +97,10 @@ namespace storm {
*
* @param transitionMatrix The transition matrix representing the system whose subsystem to decompose into MECs.
* @param backwardTransitions The reversed transition relation.
* @param subsystem The subsystem to decompose.
* @param states The states of the subsystem to decompose.
* @param choices The choices of the subsystem to decompose.
*/
void performMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const& subsystem);
void performMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states = nullptr, storm::storage::BitVector const* choices = nullptr);
};
}
}

Loading…
Cancel
Save