Stefan Pranger
4 years ago
3 changed files with 392 additions and 1 deletions
-
3src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp
-
281src/storm/storage/GameMaximalEndComponentDecomposition.cpp
-
109src/storm/storage/GameMaximalEndComponentDecomposition.h
@ -0,0 +1,281 @@ |
|||
#include <list>
|
|||
#include <queue>
|
|||
#include <numeric>
|
|||
|
|||
#include "storm/models/sparse/StandardRewardModel.h"
|
|||
|
|||
#include "storm/storage/GameMaximalEndComponentDecomposition.h"
|
|||
#include "storm/storage/StronglyConnectedComponentDecomposition.h"
|
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition() : Decomposition() { |
|||
// Intentionally left empty.
|
|||
} |
|||
|
|||
template<typename ValueType> |
|||
template<typename RewardModelType> |
|||
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType, RewardModelType> const& model) { |
|||
singleMEC(model.getTransitionMatrix(), model.getBackwardTransitions()); |
|||
//performGameMaximalEndComponentDecomposition(model.getTransitionMatrix(), model.getBackwardTransitions());
|
|||
} |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) { |
|||
singleMEC(transitionMatrix, backwardTransitions); |
|||
//performGameMaximalEndComponentDecomposition(transitionMatrix, backwardTransitions);
|
|||
} |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states) { |
|||
} |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states, storm::storage::BitVector const& choices) { |
|||
} |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType> const& model, storm::storage::BitVector const& states) { |
|||
} |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition const& other) : Decomposition(other) { |
|||
// Intentionally left empty.
|
|||
} |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>& GameMaximalEndComponentDecomposition<ValueType>::operator=(GameMaximalEndComponentDecomposition const& other) { |
|||
Decomposition::operator=(other); |
|||
return *this; |
|||
} |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition&& other) : Decomposition(std::move(other)) { |
|||
// Intentionally left empty.
|
|||
} |
|||
|
|||
template<typename ValueType> |
|||
GameMaximalEndComponentDecomposition<ValueType>& GameMaximalEndComponentDecomposition<ValueType>::operator=(GameMaximalEndComponentDecomposition&& other) { |
|||
Decomposition::operator=(std::move(other)); |
|||
return *this; |
|||
} |
|||
|
|||
template <typename ValueType> |
|||
void GameMaximalEndComponentDecomposition<ValueType>::performGameMaximalEndComponentDecomposition(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 (states) { |
|||
endComponentStateSets.emplace_back(states->begin(), states->end(), true); |
|||
} else { |
|||
std::vector<storm::storage::sparse::state_type> allStates; |
|||
allStates.resize(transitionMatrix.getRowGroupCount()); |
|||
std::iota(allStates.begin(), allStates.end(), 0); |
|||
endComponentStateSets.emplace_back(allStates.begin(), allStates.end(), true); |
|||
} |
|||
storm::storage::BitVector statesToCheck(numberOfStates); |
|||
storm::storage::BitVector includedChoices; |
|||
if (choices) { |
|||
includedChoices = *choices; |
|||
} else if (states) { |
|||
includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount()); |
|||
for (auto state : *states) { |
|||
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { |
|||
includedChoices.set(choice, true); |
|||
} |
|||
} |
|||
} else { |
|||
includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true); |
|||
} |
|||
storm::storage::BitVector currMecAsBitVector(transitionMatrix.getRowGroupCount()); |
|||
|
|||
for (std::list<StateBlock>::const_iterator mecIterator = endComponentStateSets.begin(); mecIterator != endComponentStateSets.end();) { |
|||
StateBlock const& mec = *mecIterator; |
|||
currMecAsBitVector.clear(); |
|||
currMecAsBitVector.set(mec.begin(), mec.end(), true); |
|||
// Keep track of whether the MEC changed during this iteration.
|
|||
bool mecChanged = false; |
|||
|
|||
// Get an SCC decomposition of the current MEC candidate.
|
|||
|
|||
StronglyConnectedComponentDecomposition<ValueType> sccs(transitionMatrix, StronglyConnectedComponentDecompositionOptions().subsystem(&currMecAsBitVector).choices(&includedChoices).dropNaiveSccs()); |
|||
for(auto const& sc: sccs) { |
|||
STORM_LOG_DEBUG("SCC size: " << sc.size()); |
|||
} |
|||
|
|||
// We need to do another iteration in case we have either more than once SCC or the SCC is smaller than
|
|||
// the MEC canditate itself.
|
|||
mecChanged |= sccs.size() != 1 || (sccs.size() > 0 && sccs[0].size() < mec.size()); |
|||
|
|||
// Check for each of the SCCs whether all actions for each state do not leave the SCC. // TODO there is certainly a better way to do that...
|
|||
for (auto& scc : sccs) { |
|||
statesToCheck.set(scc.begin(), scc.end()); |
|||
|
|||
while (!statesToCheck.empty()) { |
|||
storm::storage::BitVector statesToRemove(numberOfStates); |
|||
|
|||
for (auto state : statesToCheck) { |
|||
bool keepStateInMEC = true; |
|||
|
|||
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; |
|||
} |
|||
|
|||
// If the choice is not included any more, skip it.
|
|||
//if (!includedChoices.get(choice)) {
|
|||
// continue;
|
|||
//}
|
|||
|
|||
bool choiceContainedInMEC = true; |
|||
for (auto const& entry : transitionMatrix.getRow(choice)) { |
|||
if (storm::utility::isZero(entry.getValue())) { |
|||
continue; |
|||
} |
|||
|
|||
if (!scc.containsState(entry.getColumn())) { |
|||
//includedChoices.set(choice, false);
|
|||
choiceContainedInMEC = false; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
//TODO If there is at least one choice whose successor states are fully contained in the MEC, we can leave the state in the MEC.
|
|||
if (!choiceContainedInMEC) { |
|||
keepStateInMEC = false; |
|||
break; |
|||
} |
|||
} |
|||
if (!keepStateInMEC) { |
|||
statesToRemove.set(state, true); |
|||
} |
|||
|
|||
} |
|||
|
|||
// Now erase the states that have no option to stay inside the MEC with all successors.
|
|||
mecChanged |= !statesToRemove.empty(); |
|||
for (uint_fast64_t state : statesToRemove) { |
|||
scc.erase(state); |
|||
} |
|||
|
|||
// Now check which states should be reconsidered, because successors of them were removed.
|
|||
statesToCheck.clear(); |
|||
for (auto state : statesToRemove) { |
|||
for (auto const& entry : backwardTransitions.getRow(state)) { |
|||
if (scc.containsState(entry.getColumn())) { |
|||
statesToCheck.set(entry.getColumn()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// If the MEC changed, we delete it from the list of MECs and append the possible new MEC candidates to
|
|||
// the list instead.
|
|||
if (mecChanged) { |
|||
for (StronglyConnectedComponent& scc : sccs) { |
|||
if (!scc.empty()) { |
|||
endComponentStateSets.push_back(std::move(scc)); |
|||
} |
|||
} |
|||
|
|||
std::list<StateBlock>::const_iterator eraseIterator(mecIterator); |
|||
++mecIterator; |
|||
endComponentStateSets.erase(eraseIterator); |
|||
} else { |
|||
// Otherwise, we proceed with the next MEC candidate.
|
|||
++mecIterator; |
|||
} |
|||
|
|||
} // End of loop over all MEC candidates.
|
|||
|
|||
// Now that we computed the underlying state sets of the MECs, we need to properly identify the choices
|
|||
// contained in the MEC and store them as actual MECs.
|
|||
this->blocks.reserve(endComponentStateSets.size()); |
|||
for (auto const& mecStateSet : endComponentStateSets) { |
|||
MaximalEndComponent newMec; |
|||
|
|||
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; |
|||
} |
|||
|
|||
if (includedChoices.get(choice)) { |
|||
containedChoices.insert(choice); |
|||
} |
|||
} |
|||
|
|||
STORM_LOG_ASSERT(!containedChoices.empty(), "The contained choices of any state in an MEC must be non-empty."); |
|||
newMec.addState(state, std::move(containedChoices)); |
|||
} |
|||
|
|||
this->blocks.emplace_back(std::move(newMec)); |
|||
} |
|||
|
|||
STORM_LOG_DEBUG("MEC decomposition found " << this->size() << " GMEC(s)."); |
|||
} |
|||
|
|||
template <typename ValueType> |
|||
void GameMaximalEndComponentDecomposition<ValueType>::singleMEC(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states, storm::storage::BitVector const* choices) { |
|||
MaximalEndComponent singleMec; |
|||
|
|||
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices(); |
|||
|
|||
std::list<StateBlock> endComponentStateSets; |
|||
std::vector<storm::storage::sparse::state_type> allStates; |
|||
allStates.resize(transitionMatrix.getRowGroupCount()); |
|||
std::iota(allStates.begin(), allStates.end(), 0); |
|||
endComponentStateSets.emplace_back(allStates.begin(), allStates.end(), true); |
|||
|
|||
storm::storage::BitVector includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true); |
|||
this->blocks.reserve(endComponentStateSets.size()); |
|||
for (auto const& mecStateSet : endComponentStateSets) { |
|||
MaximalEndComponent newMec; |
|||
|
|||
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; |
|||
} |
|||
|
|||
if (includedChoices.get(choice)) { |
|||
containedChoices.insert(choice); |
|||
} |
|||
} |
|||
|
|||
STORM_LOG_ASSERT(!containedChoices.empty(), "The contained choices of any state in an MEC must be non-empty."); |
|||
newMec.addState(state, std::move(containedChoices)); |
|||
} |
|||
|
|||
this->blocks.emplace_back(std::move(newMec)); |
|||
} |
|||
|
|||
STORM_LOG_DEBUG("Whole state space is one single MEC"); |
|||
|
|||
} |
|||
|
|||
// Explicitly instantiate the MEC decomposition.
|
|||
template class GameMaximalEndComponentDecomposition<double>; |
|||
template GameMaximalEndComponentDecomposition<double>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<double> const& model); |
|||
|
|||
#ifdef STORM_HAVE_CARL
|
|||
template class GameMaximalEndComponentDecomposition<storm::RationalNumber>; |
|||
template GameMaximalEndComponentDecomposition<storm::RationalNumber>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<storm::RationalNumber> const& model); |
|||
|
|||
template class GameMaximalEndComponentDecomposition<storm::RationalFunction>; |
|||
template GameMaximalEndComponentDecomposition<storm::RationalFunction>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<storm::RationalFunction> const& model); |
|||
#endif
|
|||
} |
|||
} |
@ -0,0 +1,109 @@ |
|||
#ifndef STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_ |
|||
#define STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_ |
|||
|
|||
#include "storm/storage/Decomposition.h" |
|||
#include "storm/storage/MaximalEndComponent.h" |
|||
#include "storm/models/sparse/NondeterministicModel.h" |
|||
|
|||
namespace storm { |
|||
namespace storage { |
|||
|
|||
/*! |
|||
* This class represents the decomposition of a stochastic multiplayer game into its (irreducible) maximal end components. |
|||
*/ |
|||
template <typename ValueType> |
|||
class GameMaximalEndComponentDecomposition : public Decomposition<MaximalEndComponent> { |
|||
public: |
|||
/* |
|||
* Creates an empty MEC decomposition. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition(); |
|||
|
|||
/* |
|||
* Creates an MEC decomposition of the given model. |
|||
* |
|||
* @param model The model to decompose into MECs. |
|||
*/ |
|||
template <typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>> |
|||
GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType, RewardModelType> const& model); |
|||
|
|||
/* |
|||
* Creates an MEC decomposition of the 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. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions); |
|||
|
|||
/* |
|||
* 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. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition(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. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition(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 states The states of the subsystem to decompose. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition(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. |
|||
* |
|||
* @param other The MEC decomposition to copy. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition const& other); |
|||
|
|||
/*! |
|||
* Assigns the contents of the given MEC decomposition to the current one by copying its contents. |
|||
* |
|||
* @param other The MEC decomposition from which to copy-assign. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition& operator=(GameMaximalEndComponentDecomposition const& other); |
|||
|
|||
/*! |
|||
* Creates an MEC decomposition by moving the contents of the given MEC decomposition. |
|||
* |
|||
* @param other The MEC decomposition to move. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition&& other); |
|||
|
|||
/*! |
|||
* Assigns the contents of the given MEC decomposition to the current one by moving its contents. |
|||
* |
|||
* @param other The MEC decomposition from which to move-assign. |
|||
*/ |
|||
GameMaximalEndComponentDecomposition& operator=(GameMaximalEndComponentDecomposition&& other); |
|||
|
|||
private: |
|||
/*! |
|||
* Performs the actual decomposition of the given subsystem in the given model into MECs. As a side-effect |
|||
* this stores the MECs found in the current decomposition. |
|||
* |
|||
* @param transitionMatrix The transition matrix representing the system whose subsystem to decompose into MECs. |
|||
* @param backwardTransitions The reversed transition relation. |
|||
* @param states The states of the subsystem to decompose. |
|||
* @param choices The choices of the subsystem to decompose. |
|||
*/ |
|||
void performGameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states = nullptr, storm::storage::BitVector const* choices = nullptr); |
|||
void singleMEC(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states = nullptr, storm::storage::BitVector const* choices = nullptr); |
|||
}; |
|||
} |
|||
} |
|||
|
|||
#endif /* STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_ */ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue