Browse Source

Merge pull request 'Merge SMG LRA MC' (#4) from smg_lra_model_checking into main

Reviewed-on: http://git.pranger.xyz/TEMPEST/tempest-devel/pulls/4

WIP w.r.t. debug output, will be fixed in the future
main
Stefan Pranger 4 years ago
parent
commit
fd87e0ef2d
  1. 5
      CMakeLists.txt
  2. 12
      src/storm-parsers/parser/FormulaParserGrammar.cpp
  3. 1
      src/storm/builder/ExplicitModelBuilder.cpp
  4. 8
      src/storm/environment/solver/MultiplierEnvironment.cpp
  5. 10
      src/storm/environment/solver/MultiplierEnvironment.h
  6. 4
      src/storm/logic/GameFormula.cpp
  7. 2
      src/storm/modelchecker/AbstractModelChecker.cpp
  8. 2
      src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h
  9. 135
      src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp
  10. 73
      src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h
  11. 50
      src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp
  12. 5
      src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h
  13. 59
      src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp
  14. 1
      src/storm/models/sparse/Smg.cpp
  15. 30
      src/storm/solver/GmmxxMultiplier.cpp
  16. 16
      src/storm/solver/Multiplier.cpp
  17. 20
      src/storm/solver/Multiplier.h
  18. 2
      src/storm/storage/Decomposition.cpp
  19. 281
      src/storm/storage/GameMaximalEndComponentDecomposition.cpp
  20. 109
      src/storm/storage/GameMaximalEndComponentDecomposition.h
  21. 2
      src/storm/storage/MaximalEndComponent.cpp
  22. 5
      src/storm/storage/SparseMatrix.cpp
  23. 2
      src/storm/utility/Engine.cpp

5
CMakeLists.txt

@ -325,6 +325,11 @@ if (STORM_DEVELOPER)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-float-equal")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedef")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-variable-declarations")
elseif (GCC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs")
endif ()
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")

12
src/storm-parsers/parser/FormulaParserGrammar.cpp

@ -140,6 +140,18 @@ namespace storm {
gameFormula = (qi::lit("<<") > playerCoalition > qi::lit(">>") > operatorFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createGameFormula, phoenix::ref(*this), qi::_1, qi::_2)];
gameFormula.name("game formula");
stateFormula = (orStateFormula | multiFormula | quantileFormula | gameFormula);
coalitionOperator = (qi::lit("<<")
> *( (identifier[phoenix::push_back(qi::_a, qi::_1)]
| qi::int_[phoenix::push_back(qi::_a, qi::_1)]) % ','
)
> qi::lit(">>"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createCoalition, phoenix::ref(*this), qi::_a)];
coalitionOperator.name("coalition operator");
gameFormula = (coalitionOperator > operatorFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createGameFormula, phoenix::ref(*this), qi::_1, qi::_2)];
gameFormula.name("game formula");
stateFormula = (orStateFormula | multiFormula | quantileFormula | gameFormula);
stateFormula.name("state formula");

1
src/storm/builder/ExplicitModelBuilder.cpp

@ -154,6 +154,7 @@ namespace storm {
while (!statesToExplore.empty()) {
// Get the first state in the queue.
CompressedState currentState = statesToExplore.front().first;
STORM_LOG_DEBUG("Exploring (" << currentRowGroup << ") : " << toString(currentState, this->generator->getVariableInformation()));
StateType currentIndex = statesToExplore.front().second;
statesToExplore.pop_front();

8
src/storm/environment/solver/MultiplierEnvironment.cpp

@ -30,4 +30,12 @@ namespace storm {
typeSetFromDefault = isSetFromDefault;
}
void MultiplierEnvironment::setOptimizationDirectionOverride(storm::storage::BitVector optDirOverride) {
optimizationDirectionOverride = optDirOverride;
}
boost::optional<storm::storage::BitVector> const& MultiplierEnvironment::getOptimizationDirectionOverride() const {
return optimizationDirectionOverride;
}
}

10
src/storm/environment/solver/MultiplierEnvironment.h

@ -1,8 +1,12 @@
#pragma once
#include <boost/optional.hpp>
#include "storm/environment/solver/SolverEnvironment.h"
#include "storm/solver/SolverSelectionOptions.h"
#include "storm/storage/BitVector.h"
namespace storm {
class MultiplierEnvironment {
@ -15,9 +19,13 @@ namespace storm {
bool const& isTypeSetFromDefault() const;
void setType(storm::solver::MultiplierType value, bool isSetFromDefault = false);
void setOptimizationDirectionOverride(storm::storage::BitVector optimizationDirectionOverride);
boost::optional<storm::storage::BitVector> const& getOptimizationDirectionOverride() const;
private:
storm::solver::MultiplierType type;
bool typeSetFromDefault;
boost::optional<storm::storage::BitVector> optimizationDirectionOverride = boost::none;
};
}

4
src/storm/logic/GameFormula.cpp

@ -24,6 +24,10 @@ namespace storm {
return coalition;
}
void GameFormula::gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const {
this->getSubformula().gatherReferencedRewardModels(referencedRewardModels);
}
boost::any GameFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}

2
src/storm/modelchecker/AbstractModelChecker.cpp

@ -54,6 +54,8 @@ namespace storm {
return this->checkMultiObjectiveFormula(env, checkTask.substituteFormula(formula.asMultiObjectiveFormula()));
} else if (formula.isQuantileFormula()){
return this->checkQuantileFormula(env, checkTask.substituteFormula(formula.asQuantileFormula()));
} else if(formula.isGameFormula()){
return this->checkGameFormula(env, checkTask.substituteFormula(formula.asGameFormula()));
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << formula << "' is invalid.");
}

2
src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h

@ -93,7 +93,7 @@ namespace storm {
* @param actionValuesGetter a function returning a value for a given (global) choice index
* @return a value for each state
*/
std::vector<ValueType> computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter);
virtual std::vector<ValueType> computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter);
/*!
* @param stateValuesGetter a function returning a value for a given state index

135
src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp

@ -0,0 +1,135 @@
#include "SparseNondeterministicGameInfiniteHorizonHelper.h"
#include "storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h"
#include "storm/storage/SparseMatrix.h"
#include "storm/storage/MaximalEndComponentDecomposition.h"
#include "storm/storage/GameMaximalEndComponentDecomposition.h"
#include "storm/storage/Scheduler.h"
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/solver/Multiplier.h"
#include "storm/utility/solver.h"
#include "storm/utility/vector.h"
#include "storm/environment/solver/LongRunAverageSolverEnvironment.h"
#include "storm/environment/solver/MinMaxSolverEnvironment.h"
#include "storm/exceptions/UnmetRequirementException.h"
#include "storm/exceptions/InternalException.h"
namespace storm {
namespace modelchecker {
namespace helper {
template <typename ValueType>
SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<std::pair<std::string, uint_fast64_t>> const& player) : SparseInfiniteHorizonHelper<ValueType, true>(transitionMatrix), player(player) {
// Intentionally left empty.
}
template <typename ValueType>
std::vector<uint64_t> const& SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::getProducedOptimalChoices() const {
STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested.");
STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?");
return this->_producedOptimalChoices.get();
}
template <typename ValueType>
std::vector<uint64_t>& SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::getProducedOptimalChoices() {
STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested.");
STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?");
return this->_producedOptimalChoices.get();
}
template <typename ValueType>
storm::storage::Scheduler<ValueType> SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::extractScheduler() const {
auto const& optimalChoices = getProducedOptimalChoices();
storm::storage::Scheduler<ValueType> scheduler(optimalChoices.size());
for (uint64_t state = 0; state < optimalChoices.size(); ++state) {
scheduler.setChoice(optimalChoices[state], state);
}
return scheduler;
}
template <typename ValueType>
void SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::createDecomposition() {
// TODO This needs to be changed to return the whole model as one component as long as there is no overwritten version of MaximalEndComponentDecomposition for SMGs.
if (this->_longRunComponentDecomposition == nullptr) {
// The decomposition has not been provided or computed, yet.
if (this->_backwardTransitions == nullptr) {
this->_computedBackwardTransitions = std::make_unique<storm::storage::SparseMatrix<ValueType>>(this->_transitionMatrix.transpose(true));
this->_backwardTransitions = this->_computedBackwardTransitions.get();
}
this->_computedLongRunComponentDecomposition = std::make_unique<storm::storage::GameMaximalEndComponentDecomposition<ValueType>>(this->_transitionMatrix, *this->_backwardTransitions);
this->_longRunComponentDecomposition = this->_computedLongRunComponentDecomposition.get();
//STORM_LOG_DEBUG("\n" << this->_transitionMatrix);
STORM_LOG_DEBUG("GMEC: " << *(this->_longRunComponentDecomposition));
}
}
template <typename ValueType>
std::vector<ValueType> SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter) {
auto underlyingSolverEnvironment = env;
std::vector<ValueType> componentLraValues;
createDecomposition();
componentLraValues.reserve(this->_longRunComponentDecomposition->size());
for (auto const& c : *(this->_longRunComponentDecomposition)) {
componentLraValues.push_back(computeLraForComponent(underlyingSolverEnvironment, stateValuesGetter, actionValuesGetter, c));
}
return componentLraValues;
}
template <typename ValueType>
ValueType SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::computeLraForComponent(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) {
// Allocate memory for the nondeterministic choices.
if (this->isProduceSchedulerSet()) {
if (!this->_producedOptimalChoices.is_initialized()) {
this->_producedOptimalChoices.emplace();
}
this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount());
}
storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod();
if (method == storm::solver::LraMethod::LinearProgramming) {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique.");
} else if (method == storm::solver::LraMethod::ValueIteration) {
return computeLraVi(env, stateRewardsGetter, actionRewardsGetter, component);
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique.");
}
}
template <typename ValueType>
ValueType SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::computeLraVi(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& mec) {
// Collect some parameters of the computation
ValueType aperiodicFactor = storm::utility::convertNumber<ValueType>(env.solver().lra().getAperiodicFactor());
std::vector<uint64_t>* optimalChoices = nullptr;
if (this->isProduceSchedulerSet()) {
optimalChoices = &this->_producedOptimalChoices.get();
}
// Now create a helper and perform the algorithm
if (this->isContinuousTime()) {
STORM_LOG_THROW(false, storm::exceptions::InternalException, "We cannot handle continuous time games.");
} else {
storm::modelchecker::helper::internal::LraViHelper<ValueType, storm::storage::MaximalEndComponent, storm::modelchecker::helper::internal::LraViTransitionsType::GameNondetTsNoIs> viHelper(mec, this->_transitionMatrix, aperiodicFactor);
return viHelper.performValueIteration(env, stateRewardsGetter, actionRewardsGetter, nullptr, &this->getOptimizationDirection(), optimalChoices);
}
}
template <typename ValueType>
std::vector<ValueType> SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& componentLraValues) {
STORM_LOG_THROW(false, storm::exceptions::InternalException, "We do not create compositions for LRA for SMGs, solving a stochastic shortest path problem is not available.");
}
template class SparseNondeterministicGameInfiniteHorizonHelper<double>;
template class SparseNondeterministicGameInfiniteHorizonHelper<storm::RationalNumber>;
}
}
}

73
src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h

@ -0,0 +1,73 @@
#pragma once
#include "storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h"
namespace storm {
namespace storage {
template <typename VT> class Scheduler;
}
namespace modelchecker {
namespace helper {
/*!
* Helper class for model checking queries that depend on the long run behavior of the (nondeterministic) system with different players choices.
* @tparam ValueType the type a value can have
*/
template <typename ValueType>
class SparseNondeterministicGameInfiniteHorizonHelper : public SparseInfiniteHorizonHelper<ValueType, true> {
public:
/*!
* Function mapping from indices to values
*/
typedef typename SparseInfiniteHorizonHelper<ValueType, true>::ValueGetter ValueGetter;
/*!
* Initializes the helper for a discrete time model with different players (i.e. SMG)
*/
SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<std::pair<std::string, uint_fast64_t>> const& player);
/*! TODO
* Computes the long run average value given the provided state and action based rewards
* @param stateValuesGetter a function returning a value for a given state index
* @param actionValuesGetter a function returning a value for a given (global) choice index
* @return a value for each state
*/
std::vector<ValueType> computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter) override;
/*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return the produced scheduler of the most recent call.
*/
std::vector<uint64_t> const& getProducedOptimalChoices() const;
/*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return the produced scheduler of the most recent call.
*/
std::vector<uint64_t>& getProducedOptimalChoices();
/*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return a new scheduler containing optimal choices for each state that yield the long run average values of the most recent call.
*/
storm::storage::Scheduler<ValueType> extractScheduler() const;
ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& component);
ValueType computeLraVi(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec);
void createDecomposition();
std::vector<ValueType> buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& mecLraValues);
private:
std::vector<std::pair<std::string, uint_fast64_t>> player;
};
}
}
}

50
src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp

@ -14,6 +14,7 @@
#include "storm/environment/solver/SolverEnvironment.h"
#include "storm/environment/solver/LongRunAverageSolverEnvironment.h"
#include "storm/environment/solver/MinMaxSolverEnvironment.h"
#include "storm/environment/solver/MultiplierEnvironment.h"
#include "storm/exceptions/UnmetRequirementException.h"
@ -140,6 +141,7 @@ namespace storm {
_IsTransitions = isTransitionsBuilder.build();
_IsToTsTransitions = isToTsTransitionsBuilder.build();
}
STORM_LOG_DEBUG(uniformizationFactor << " - " << _uniformizationRate);
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
@ -173,17 +175,34 @@ namespace storm {
++iter;
performIterationStep(env, dir);
std::vector<ValueType> xOldTemp = xOld();
std::vector<ValueType> xNewTemp = xNew();
if(gameNondetTs() && iter > 1) {
// Weight values with current iteration step
storm::utility::vector::applyPointwise<ValueType, ValueType>(xOld(), xOld(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)(iter - 1); });
storm::utility::vector::applyPointwise<ValueType, ValueType>(xNew(), xNew(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)iter; });
}
// Check if we are done
auto convergenceCheckResult = checkConvergence(relative, precision);
result = convergenceCheckResult.currentValue;
if(gameNondetTs() && iter > 1) {
xOld() = xOldTemp;
xNew() = xNewTemp;
}
if (convergenceCheckResult.isPrecisionAchieved) {
break;
}
if (storm::utility::resources::isTerminate()) {
break;
}
// If there will be a next iteration, we have to prepare it.
if(!gameNondetTs()) {
prepareNextIteration(env);
}
}
if (maxIter.is_initialized() && iter == maxIter.get()) {
@ -196,9 +215,18 @@ namespace storm {
if (choices) {
// We will be doing one more iteration step and track scheduler choices this time.
if(!gameNondetTs()) {
prepareNextIteration(env);
}
performIterationStep(env, dir, choices);
}
std::cout << "result (" << iter << " steps):" << std::endl;
storm::utility::vector::applyPointwise<ValueType, ValueType>(xNew(), xNew(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)iter; });
for(int i = 0; i < xNew().size() ; i++ ) {
std::cout << std::setprecision(4) << i << "\t: " << xNew().at(i) << "\t" << xNew().at(i) * _uniformizationRate << "\t" << std::setprecision(16) << xOld().at(i) *_uniformizationRate << std::endl;
//if(i == 50) {std::cout << "only showing top 50 lines"; break; }
}
if(gameNondetTs()) result = xOld().at(0) * _uniformizationRate; // TODO is "init" always going to be .at(0) ?
return result;
}
@ -306,6 +334,9 @@ namespace storm {
_TsToIsMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _TsToIsTransitions);
_IsToTsMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _IsToTsTransitions);
}
if(env.solver().multiplier().getOptimizationDirectionOverride().is_initialized()) {
_TsMultiplier->setOptimizationDirectionOverride(env.solver().multiplier().getOptimizationDirectionOverride().get());
}
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
@ -346,7 +377,7 @@ namespace storm {
// The result of this ongoing computation will be stored in xNew()
// Compute the values obtained by a single uniformization step between timed states only
if (nondetTs()) {
if (nondetTs() && !gameNondetTs()) {
if (choices == nullptr) {
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew());
} else {
@ -358,6 +389,14 @@ namespace storm {
STORM_LOG_ASSERT(!_hasInstantStates, "Nondeterministic timed states are only supported if there are no instant states.");
setInputModelChoices(*choices, tsChoices);
}
} else if(gameNondetTs()) { // TODO DRYness? exact same behaviour as case above?
if (choices == nullptr) {
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew());
} else {
std::vector<uint64_t> tsChoices(_TsTransitions.getRowGroupCount());
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew(), &tsChoices);
setInputModelChoices(*choices, tsChoices); // no components -> no need for that call?
}
} else {
_TsMultiplier->multiply(env, xOld(), &_TsChoiceValues, xNew());
}
@ -485,7 +524,7 @@ namespace storm {
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
bool LraViHelper<ValueType, ComponentType, TransitionsType>::nondetTs() const {
return TransitionsType == LraViTransitionsType::NondetTsNoIs;
return TransitionsType == LraViTransitionsType::NondetTsNoIs || gameNondetTs();
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
@ -493,8 +532,15 @@ namespace storm {
return TransitionsType == LraViTransitionsType::DetTsNondetIs;
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
bool LraViHelper<ValueType, ComponentType, TransitionsType>::gameNondetTs() const {
return TransitionsType == LraViTransitionsType::GameNondetTsNoIs;
}
template class LraViHelper<double, storm::storage::MaximalEndComponent, LraViTransitionsType::NondetTsNoIs>;
template class LraViHelper<storm::RationalNumber, storm::storage::MaximalEndComponent, LraViTransitionsType::NondetTsNoIs>;
template class LraViHelper<double, storm::storage::MaximalEndComponent, LraViTransitionsType::GameNondetTsNoIs>;
template class LraViHelper<storm::RationalNumber, storm::storage::MaximalEndComponent, LraViTransitionsType::GameNondetTsNoIs>;
template class LraViHelper<double, storm::storage::MaximalEndComponent, LraViTransitionsType::DetTsNondetIs>;
template class LraViHelper<storm::RationalNumber, storm::storage::MaximalEndComponent, LraViTransitionsType::DetTsNondetIs>;

5
src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h

@ -25,7 +25,8 @@ namespace storm {
DetTsNoIs, /// deterministic choice at timed states, no instant states (as in DTMCs and CTMCs)
DetTsNondetIs, /// deterministic choice at timed states, nondeterministic choice at instant states (as in Markov Automata)
DetTsDetIs, /// deterministic choice at timed states, deterministic choice at instant states (as in Markov Automata without any nondeterminisim)
NondetTsNoIs /// nondeterministic choice at timed states, no instant states (as in MDPs)
NondetTsNoIs, /// nondeterministic choice at timed states, no instant states (as in MDPs)
GameNondetTsNoIs // nondeterministic choices of different players at timed states, no instant states (as in SMGs)
};
/*!
@ -127,6 +128,8 @@ namespace storm {
/// @return true iff there potentially is a nondeterministic choice at instant states. Returns false if there are no instant states.
bool nondetIs() const;
/// @return true iff there potentially are nondeterministic choices for different players at timed states
bool gameNondetTs() const;
void setComponent(ComponentType component);

59
src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp

@ -2,6 +2,8 @@
#include <vector>
#include <memory>
#include <algorithm>
#include <boost/variant/get.hpp>
#include "storm/utility/macros.h"
#include "storm/utility/FilteredRewardModel.h"
@ -12,6 +14,10 @@
#include "storm/modelchecker/helper/utility/SetInformationFromCheckTask.h"
#include "storm/logic/FragmentSpecification.h"
#include "storm/logic/Coalition.h"
#include "storm/storage/BitVector.h"
#include "storm/environment/solver/MultiplierEnvironment.h"
#include "storm/models/sparse/StandardRewardModel.h"
@ -27,6 +33,8 @@ namespace storm {
// Intentionally left empty.
}
template<typename SparseSmgModelType>
bool SparseSmgRpatlModelChecker<SparseSmgModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState) {
storm::logic::Formula const& formula = checkTask.getFormula();
@ -44,14 +52,46 @@ namespace storm {
}
}
template<typename SparseSmgModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<SparseSmgModelType>::checkGameFormula(Environment const& env, CheckTask<storm::logic::GameFormula, ValueType> const& checkTask) {
storm::logic::GameFormula const& gameFormula = checkTask.getFormula();
storm::logic::Formula const& subFormula = gameFormula.getSubformula();
if (subFormula.isOperatorFormula()) {
return this->checkStateFormula(env, checkTask.substituteFormula(subFormula.asStateFormula()).setPlayerCoalition(gameFormula.getCoalition()));
if (subFormula.isRewardOperatorFormula()) {
return this->checkRewardOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asRewardOperatorFormula()));
} else if (subFormula.isLongRunAverageOperatorFormula()) {
return this->checkLongRunAverageOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asLongRunAverageOperatorFormula()));
}
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Cannot check this property (yet).");
}
template<typename ModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<ModelType>::checkRewardOperatorFormula(Environment const& env, CheckTask<storm::logic::RewardOperatorFormula, ValueType> const& checkTask) {
storm::logic::RewardOperatorFormula const& formula = checkTask.getFormula();
std::unique_ptr<CheckResult> result = this->computeRewards(env, formula.getMeasureType(), checkTask.substituteFormula(formula.getSubformula()));
return result;
}
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Only game formulas with Operatorformulas as subformula are supported.");
template<typename ModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<ModelType>::checkLongRunAverageOperatorFormula(Environment const& env, CheckTask<storm::logic::LongRunAverageOperatorFormula, ValueType> const& checkTask) {
storm::logic::LongRunAverageOperatorFormula const& formula = checkTask.getFormula();
std::unique_ptr<CheckResult> result = this->computeLongRunAverageProbabilities(env, checkTask.substituteFormula(formula.getSubformula().asStateFormula()));
return result;
}
template<typename ModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<ModelType>::computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula, ValueType> const& checkTask) {
storm::logic::Formula const& rewardFormula = checkTask.getFormula();
if (rewardFormula.isLongRunAverageRewardFormula()) {
return this->computeLongRunAverageRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula()));
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << rewardFormula << "' cannot (yet) be handled.");
}
template<typename SparseSmgModelType>
@ -62,10 +102,15 @@ namespace storm {
template<typename SparseSmgModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<SparseSmgModelType>::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula, ValueType> const& checkTask) {
auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask);
STORM_LOG_THROW(checkTask.isPlayerCoalitionSet(), storm::exceptions::InvalidPropertyException, "No player coalition was set.");
auto coalitionStates = this->getModel().computeStatesOfCoalition(checkTask.getPlayerCoalition());
std::cout << "Found " << coalitionStates.getNumberOfSetBits() << " states in coalition." << std::endl;
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Not implemented.");
storm::modelchecker::helper::SparseNondeterministicGameInfiniteHorizonHelper<ValueType> helper(this->getModel().getTransitionMatrix(), this->getModel().getPlayerActionIndices());
storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel());
auto values = helper.computeLongRunAverageRewards(env, rewardModel.get());
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(values)));
if (checkTask.isProduceSchedulersSet()) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler()));
}
return result;
}
template class SparseSmgRpatlModelChecker<storm::models::sparse::Smg<double>>;

1
src/storm/models/sparse/Smg.cpp

@ -37,7 +37,6 @@ namespace storm {
storm::storage::PlayerIndex Smg<ValueType, RewardModelType>::getPlayerOfState(uint64_t stateIndex) const {
STORM_LOG_ASSERT(stateIndex < this->getNumberOfStates(), "Invalid state index: " << stateIndex << ".");
return statePlayerIndications[stateIndex];
}
template <typename ValueType, typename RewardModelType>
storm::storage::PlayerIndex Smg<ValueType, RewardModelType>::getPlayerIndex(std::string const& playerName) const {

30
src/storm/solver/GmmxxMultiplier.cpp

@ -1,5 +1,7 @@
#include "storm/solver/GmmxxMultiplier.h"
#include <boost/optional.hpp>
#include "storm/adapters/RationalNumberAdapter.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include "storm/adapters/IntelTbbAdapter.h"
@ -18,6 +20,7 @@ namespace storm {
template<typename ValueType>
GmmxxMultiplier<ValueType>::GmmxxMultiplier(storm::storage::SparseMatrix<ValueType> const& matrix) : Multiplier<ValueType>(matrix) {
// Intentionally left empty.
//STORM_LOG_DEBUG("\n" << matrix);
}
template<typename ValueType>
@ -166,13 +169,20 @@ namespace storm {
choice_it = backwards ? choices->end() - 1 : choices->begin();
}
boost::optional<storm::storage::BitVector> optimizationDirectionOverride;
if(this->getOptimizationDirectionOverride().is_initialized()) {
optimizationDirectionOverride = this->getOptimizationDirectionOverride();
}
// Variables for correctly tracking choices (only update if new choice is strictly better).
ValueType oldSelectedChoiceValue;
uint64_t selectedChoice;
uint64_t currentRow = backwards ? gmmMatrix.nrows() - 1 : 0;
uint64_t currentRowGroup = backwards ? rowGroupIndices.size() - 1 : 0;
auto row_group_it = backwards ? rowGroupIndices.end() - 2 : rowGroupIndices.begin();
auto row_group_ite = backwards ? rowGroupIndices.begin() - 1 : rowGroupIndices.end() - 1;
//if(choices) STORM_LOG_DEBUG(" ");
while (row_group_it != row_group_ite) {
ValueType currentValue = storm::utility::zero<ValueType>();
@ -205,6 +215,10 @@ namespace storm {
// Process the (rowGroupSize-1) remaining rows within the current row Group
uint64_t rowGroupSize = *(row_group_it + 1) - *row_group_it;
uint choiceforprintout = 0;
//std::cout << currentRowGroup << ": " << currentValue << ", ";
//STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x) << " + " << *add_it << "; ");
//STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x) << " + " << *add_it << "; ");
for (uint64_t i = 1; i < rowGroupSize; ++i) {
ValueType newValue = b ? *add_it : storm::utility::zero<ValueType>();
newValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
@ -212,12 +226,14 @@ namespace storm {
if (choices && currentRow == *choice_it + *row_group_it) {
oldSelectedChoiceValue = newValue;
}
if (compare(newValue, currentValue)) {
//std::cout << newValue << ", ";
//STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x) << " + " << *add_it << "; ");
if(this->isOverridden(currentRowGroup) ? compare(currentValue, newValue) : compare(newValue, currentValue)) {
currentValue = newValue;
if (choices) {
selectedChoice = currentRow - *row_group_it;
}
choiceforprintout = currentRow - *row_group_it;
}
// move row-based iterators to the next row
if (backwards) {
@ -230,25 +246,31 @@ namespace storm {
++add_it;
}
}
//STORM_LOG_DEBUG("\t= " << currentValue << "\tchoice: " << choiceforprintout);
//std::cout << std::fixed << std::setprecision(2) << " | v(" << currentRowGroup << ")=" << currentValue << " c: " << choiceforprintout << " |\n" ;
// Finally write value to target vector.
*target_it = currentValue;
if (choices && compare(currentValue, oldSelectedChoiceValue)) {
if(choices) {
if(this->isOverridden(currentRowGroup) ? compare(oldSelectedChoiceValue, currentValue) : compare(currentValue, oldSelectedChoiceValue) ) {
*choice_it = selectedChoice;
}
}
}
// move rowGroup-based iterators to the next row group
if (backwards) {
--row_group_it;
--choice_it;
--target_it;
--currentRowGroup;
} else {
++row_group_it;
++choice_it;
++target_it;
++currentRowGroup;
}
}
//std::cout << std::endl;
}
template<>

16
src/storm/solver/Multiplier.cpp

@ -74,6 +74,22 @@ namespace storm {
multiplyRow(rowIndex, x2, val2);
}
template<typename ValueType>
void Multiplier<ValueType>::setOptimizationDirectionOverride(storm::storage::BitVector const& optDirOverride) {
optimizationDirectionOverride = optDirOverride;
}
template<typename ValueType>
boost::optional<storm::storage::BitVector> Multiplier<ValueType>::getOptimizationDirectionOverride() const {
return optimizationDirectionOverride;
}
template<typename ValueType>
bool Multiplier<ValueType>::isOverridden(uint_fast64_t const index) const {
if(!optimizationDirectionOverride.is_initialized()) return false;
return optimizationDirectionOverride.get().get(index);
}
template<typename ValueType>
std::unique_ptr<Multiplier<ValueType>> MultiplierFactory<ValueType>::create(Environment const& env, storm::storage::SparseMatrix<ValueType> const& matrix) {
auto type = env.solver().multiplier().getType();

20
src/storm/solver/Multiplier.h

@ -2,6 +2,9 @@
#include <vector>
#include <memory>
#include <boost/optional.hpp>
#include "storm/storage/BitVector.h"
#include "storm/solver/OptimizationDirection.h"
#include "storm/solver/MultiplicationStyle.h"
@ -134,9 +137,26 @@ namespace storm {
*/
virtual void multiplyRow2(uint64_t const& rowIndex, std::vector<ValueType> const& x1, ValueType& val1, std::vector<ValueType> const& x2, ValueType& val2) const;
/*
* TODO
*/
void setOptimizationDirectionOverride(storm::storage::BitVector const& optimizationDirectionOverride);
/*
* TODO
*/
boost::optional<storm::storage::BitVector> getOptimizationDirectionOverride() const;
/*
* TODO
*/
bool isOverridden(uint_fast64_t const index) const;
protected:
mutable std::unique_ptr<std::vector<ValueType>> cachedVector;
storm::storage::SparseMatrix<ValueType> const& matrix;
boost::optional<storm::storage::BitVector> optimizationDirectionOverride = boost::none;
};
template<typename ValueType>

2
src/storm/storage/Decomposition.cpp

@ -132,7 +132,7 @@ namespace storm {
out << "[ ";
if (decomposition.size() > 0) {
for (uint_fast64_t blockIndex = 0; blockIndex < decomposition.size() - 1; ++blockIndex) {
out << decomposition.blocks[blockIndex] << ", ";
out << decomposition.blocks[blockIndex] << ", " << std::endl;
}
out << decomposition.blocks.back();
}

281
src/storm/storage/GameMaximalEndComponentDecomposition.cpp

@ -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
}
}

109
src/storm/storage/GameMaximalEndComponentDecomposition.h

@ -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_ */

2
src/storm/storage/MaximalEndComponent.cpp

@ -103,7 +103,7 @@ namespace storm {
std::ostream& operator<<(std::ostream& out, MaximalEndComponent const& component) {
out << "{";
for (auto const& stateChoicesPair : component.stateToChoicesMapping) {
out << "{" << stateChoicesPair.first << ", " << stateChoicesPair.second << "}";
out << "(" << stateChoicesPair.first << ", " << stateChoicesPair.second << ")";
}
out << "}";

5
src/storm/storage/SparseMatrix.cpp

@ -2350,7 +2350,7 @@ namespace storm {
typename SparseMatrix<ValueType>::index_type currentRealIndex = 0;
while (currentRealIndex < matrix.columnCount) {
if (nextIndex < matrix.rowIndications[i + 1] && currentRealIndex == matrix.columnsAndValues[nextIndex].getColumn()) {
out << matrix.columnsAndValues[nextIndex].getValue() << "\t";
out << std::setprecision(3) << matrix.columnsAndValues[nextIndex].getValue() << "\t";
++nextIndex;
} else {
out << "0\t";
@ -2522,6 +2522,3 @@ namespace storm {
} // namespace storage
} // namespace storm

2
src/storm/utility/Engine.cpp

@ -179,10 +179,10 @@ namespace storm {
return storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>>::canHandleStatic(checkTask);
case ModelType::CTMC:
return storm::modelchecker::SparseCtmcCslModelChecker<storm::models::sparse::Ctmc<storm::RationalFunction>>::canHandleStatic(checkTask);
case ModelType::SMG:
case ModelType::MDP:
case ModelType::MA:
case ModelType::POMDP:
case ModelType::SMG:
return false;
}
break;

Loading…
Cancel
Save