diff --git a/src/builder/ExplicitDFTModelBuilder.cpp b/src/builder/ExplicitDFTModelBuilder.cpp index 723d75920..aa4d46f15 100644 --- a/src/builder/ExplicitDFTModelBuilder.cpp +++ b/src/builder/ExplicitDFTModelBuilder.cpp @@ -73,20 +73,20 @@ namespace storm { } std::shared_ptr> model; - if (deterministic) { - // Turn the probabilities into rates by multiplying each row with the exit rate of the state. - // TODO Matthias: avoid transforming back and forth - storm::storage::SparseMatrix rateMatrix(modelComponents.transitionMatrix); - for (uint_fast64_t row = 0; row < rateMatrix.getRowCount(); ++row) { + // Turn the probabilities into rates by multiplying each row with the exit rate of the state. + // TODO Matthias: avoid transforming back and forth + storm::storage::SparseMatrix rateMatrix(modelComponents.transitionMatrix); + for (uint_fast64_t row = 0; row < rateMatrix.getRowCount(); ++row) { + if (modelComponents.markovianStates.get(row)) { for (auto& entry : rateMatrix.getRow(row)) { entry.setValue(entry.getValue() * modelComponents.exitRates[row]); } } - + } + if (deterministic) { model = std::make_shared>(std::move(rateMatrix), std::move(modelComponents.stateLabeling)); } else { - model = std::make_shared>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates)); - + model = std::make_shared>(std::move(rateMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.markovianStates), std::move(modelComponents.exitRates)); } model->printModelInformationToStream(std::cout); return model; diff --git a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index b33b01436..12db539c8 100644 --- a/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -30,7 +30,7 @@ namespace storm { template bool SparseMarkovAutomatonCslModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isCslStateFormula() || formula.isCslPathFormula() || (formula.isRewardPathFormula() && formula.isReachabilityRewardFormula()); + return formula.isCslStateFormula() || formula.isCslPathFormula() || (formula.isRewardPathFormula() && formula.isReachabilityRewardFormula()) || formula.isExpectedTimeOperatorFormula(); } template diff --git a/src/models/sparse/MarkovAutomaton.cpp b/src/models/sparse/MarkovAutomaton.cpp index 56a6400d1..c95957248 100644 --- a/src/models/sparse/MarkovAutomaton.cpp +++ b/src/models/sparse/MarkovAutomaton.cpp @@ -3,6 +3,8 @@ #include "src/exceptions/InvalidArgumentException.h" #include "src/utility/constants.h" #include "src/adapters/CarlAdapter.h" +#include "src/storage/FlexibleSparseMatrix.h" +#include "src/models/sparse/Dtmc.h" namespace storm { namespace models { @@ -217,6 +219,29 @@ namespace storm { } } + template + bool MarkovAutomaton::hasOnlyTrivialNondeterminism() const { + // Check every state + for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) { + // Get number of choices in current state + uint_fast64_t numberChoices = this->getTransitionMatrix().getRowGroupIndices()[state + 1] - this->getTransitionMatrix().getRowGroupIndices()[state]; + if (isMarkovianState(state)) { + assert(numberChoices == 1); + } + if (numberChoices > 1) { + assert(isProbabilisticState(state)); + return false; + } + } + return true; + } + + template + std::shared_ptr> MarkovAutomaton::convertToCTMC() { + assert(false) + } + + template class MarkovAutomaton; // template class MarkovAutomaton; diff --git a/src/models/sparse/MarkovAutomaton.h b/src/models/sparse/MarkovAutomaton.h index 731b845f3..ed807ab84 100644 --- a/src/models/sparse/MarkovAutomaton.h +++ b/src/models/sparse/MarkovAutomaton.h @@ -2,6 +2,7 @@ #define STORM_MODELS_SPARSE_MARKOVAUTOMATON_H_ #include "src/models/sparse/NondeterministicModel.h" +#include "src/models/sparse/Ctmc.h" #include "src/utility/OsDetection.h" namespace storm { @@ -121,6 +122,10 @@ namespace storm { */ void close(); + bool hasOnlyTrivialNondeterminism() const; + + std::shared_ptr> convertToCTMC(); + virtual void writeDotToStream(std::ostream& outStream, bool includeLabeling = true, storm::storage::BitVector const* subsystem = nullptr, std::vector const* firstValue = nullptr, std::vector const* secondValue = nullptr, std::vector const* stateColoring = nullptr, std::vector const* colors = nullptr, std::vector* scheduler = nullptr, bool finalizeOutput = true) const; std::size_t getSizeInBytes() const; diff --git a/src/utility/storm.h b/src/utility/storm.h index f297d9e41..f737b318e 100644 --- a/src/utility/storm.h +++ b/src/utility/storm.h @@ -277,6 +277,8 @@ namespace storm { storm::modelchecker::SparseDtmcEliminationModelChecker> modelchecker2(*dtmc); if (modelchecker2.canHandle(task)) { result = modelchecker2.check(task); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The property " << *formula << " is not supported on DTMCs."); } } } else if (model->getType() == storm::models::ModelType::Mdp) { @@ -300,9 +302,15 @@ namespace storm { result = modelchecker.check(task); } else if (model->getType() == storm::models::ModelType::MarkovAutomaton) { std::shared_ptr> ma = model->template as>(); - - storm::modelchecker::SparseMarkovAutomatonCslModelChecker> modelchecker(*ma); - result = modelchecker.check(task); + if (ma->hasOnlyTrivialNondeterminism()) { + // Markov automaton can be converted into CTMC + std::shared_ptr> ctmc = ma->convertToCTMC(); + storm::modelchecker::SparseCtmcCslModelChecker> modelchecker(*ctmc); + result = modelchecker.check(task); + } else { + storm::modelchecker::SparseMarkovAutomatonCslModelChecker> modelchecker(*ma); + result = modelchecker.check(task); + } } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The model type " << model->getType() << " is not supported."); }