Browse Source

Further simplified LTLHelper Interface a bit.

Support for LTL and HOA formulaes for *all* (sparse) model types
tempestpy_adaptions
Tim Quatmann 3 years ago
committed by Stefan Pranger
parent
commit
a81f5e284b
  1. 6
      src/storm/logic/ExtractMaximalStateFormulasVisitor.cpp
  2. 16
      src/storm/logic/ExtractMaximalStateFormulasVisitor.h
  3. 63
      src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp
  4. 2
      src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h
  5. 64
      src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp
  6. 1
      src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h
  7. 35
      src/storm/modelchecker/helper/ltl/SparseLTLHelper.cpp
  8. 39
      src/storm/modelchecker/helper/ltl/SparseLTLHelper.h
  9. 54
      src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp
  10. 53
      src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp
  11. 1
      src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h

6
src/storm/logic/ExtractMaximalStateFormulasVisitor.cpp

@ -7,11 +7,11 @@
namespace storm { namespace storm {
namespace logic { namespace logic {
ExtractMaximalStateFormulasVisitor::ExtractMaximalStateFormulasVisitor(ApToFormulaMap& extractedFormulas, std::map<std::string, std::string>& cachedFormulas) : extractedFormulas(extractedFormulas), cachedFormulas(cachedFormulas), nestingLevel(0) {
ExtractMaximalStateFormulasVisitor::ExtractMaximalStateFormulasVisitor(ApToFormulaMap& extractedFormulas) : extractedFormulas(extractedFormulas), nestingLevel(0) {
} }
std::shared_ptr<Formula> ExtractMaximalStateFormulasVisitor::extract(PathFormula const& f, ApToFormulaMap& extractedFormulas, std::map<std::string, std::string>& cachedFormulas) {
ExtractMaximalStateFormulasVisitor visitor(extractedFormulas, cachedFormulas);
std::shared_ptr<Formula> ExtractMaximalStateFormulasVisitor::extract(PathFormula const& f, ApToFormulaMap& extractedFormulas) {
ExtractMaximalStateFormulasVisitor visitor(extractedFormulas);
boost::any result = f.accept(visitor, boost::any()); boost::any result = f.accept(visitor, boost::any());
return boost::any_cast<std::shared_ptr<Formula>>(result); return boost::any_cast<std::shared_ptr<Formula>>(result);
} }

16
src/storm/logic/ExtractMaximalStateFormulasVisitor.h

@ -6,12 +6,18 @@
namespace storm { namespace storm {
namespace logic { namespace logic {
class ExtractMaximalStateFormulasVisitor : public CloneVisitor { class ExtractMaximalStateFormulasVisitor : public CloneVisitor {
public: public:
typedef std::map<std::string, std::shared_ptr<Formula const>> ApToFormulaMap; typedef std::map<std::string, std::shared_ptr<Formula const>> ApToFormulaMap;
static std::shared_ptr<Formula> extract(PathFormula const& f, ApToFormulaMap& extractedFormulas, std::map<std::string, std::string>& cachedFormulas);
/*!
* Finds state subformulae in f and replaces them by atomic propositions.
* @param extractedFormulas will be the mapping of atomic propositions to the subformulae they replace
* @return the formula with replaced state subformulae
* @note identical subformulae will be replaced by the same atomic proposition
*/
static std::shared_ptr<Formula> extract(PathFormula const& f, ApToFormulaMap& extractedFormulas);
virtual boost::any visit(BinaryBooleanPathFormula const& f, boost::any const& data) const override; virtual boost::any visit(BinaryBooleanPathFormula const& f, boost::any const& data) const override;
virtual boost::any visit(BoundedUntilFormula const& f, boost::any const& data) const override; virtual boost::any visit(BoundedUntilFormula const& f, boost::any const& data) const override;
@ -28,7 +34,7 @@ namespace storm {
virtual boost::any visit(RewardOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(RewardOperatorFormula const& f, boost::any const& data) const override;
private: private:
ExtractMaximalStateFormulasVisitor(ApToFormulaMap& extractedFormulas, std::map<std::string, std::string>& cachedFormulas);
ExtractMaximalStateFormulasVisitor(ApToFormulaMap& extractedFormulas);
std::shared_ptr<Formula> extract(std::shared_ptr<Formula> f) const; std::shared_ptr<Formula> extract(std::shared_ptr<Formula> f) const;
void incrementNestingLevel() const; void incrementNestingLevel() const;
@ -36,7 +42,7 @@ namespace storm {
ApToFormulaMap& extractedFormulas; ApToFormulaMap& extractedFormulas;
// A mapping from formula-strings to labels in order to use the same label for the equivalent formulas (as strings) // A mapping from formula-strings to labels in order to use the same label for the equivalent formulas (as strings)
std::map<std::string, std::string>& cachedFormulas;
mutable std::map<std::string, std::string> cachedFormulas;
std::size_t nestingLevel; std::size_t nestingLevel;
}; };

63
src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp

@ -96,54 +96,35 @@ namespace storm {
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
} }
template<typename SparseCtmcModelType>
std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeHOAPathProbabilities(Environment const& env, CheckTask<storm::logic::HOAPathFormula, ValueType> const& checkTask) {
storm::logic::HOAPathFormula const& pathFormula = checkTask.getFormula();
auto probabilisticTransitions = this->getModel().computeProbabilityMatrix();
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(probabilisticTransitions);
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, this->getModel());
auto formulaChecker = [&] (storm::logic::Formula const& formula) { return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); };
auto apSets = helper.computeApSets(pathFormula.getAPMapping(), formulaChecker);
std::vector<ValueType> numericResult = helper.computeDAProductProbabilities(env, *pathFormula.readAutomaton(), apSets);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
}
template<typename SparseCtmcModelType> template<typename SparseCtmcModelType>
std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) { std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) {
storm::logic::PathFormula const& pathFormula = checkTask.getFormula(); storm::logic::PathFormula const& pathFormula = checkTask.getFormula();
STORM_LOG_INFO("Extracting maximal state formulas for path formula: " << pathFormula);
storm::logic::ExtractMaximalStateFormulasVisitor::ApToFormulaMap extracted;
// Maintain a mapping from formula-strings to labels in order to reuse labels of equivalent (compared as strings) formulas
std::map<std::string, std::string> cached;
std::shared_ptr<storm::logic::Formula> ltlFormula = storm::logic::ExtractMaximalStateFormulasVisitor::extract(pathFormula, extracted, cached);
const SparseCtmcModelType& ctmc = this->getModel();
typedef typename storm::models::sparse::Dtmc<typename SparseCtmcModelType::ValueType> SparseDtmcModelType;
STORM_LOG_INFO("Computing embedded DTMC...");
// Compute probability matrix (embedded DTMC)
storm::storage::SparseMatrix<ValueType> probabilityMatrix = storm::modelchecker::helper::SparseCtmcCslHelper::computeProbabilityMatrix(ctmc.getTransitionMatrix(), ctmc.getExitRateVector());
// Copy of the state labelings of the CTMC
storm::models::sparse::StateLabeling labeling(ctmc.getStateLabeling());
// The embedded DTMC, used for building the product and computing the probabilities in the product
SparseDtmcModelType embeddedDtmc(std::move(probabilityMatrix), std::move(labeling));
storm::solver::SolveGoal<ValueType> goal(embeddedDtmc, checkTask);
STORM_LOG_INFO("Performing ltl probability computations in embedded DTMC...");
// TODO ?
if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isTraceSet()) {
STORM_LOG_TRACE("Writing model to model.dot");
std::ofstream modelDot("model.dot");
embeddedDtmc.writeDotToStream(modelDot);
modelDot.close();
}
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(embeddedDtmc.getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, embeddedDtmc);
// Compute Satisfaction sets for APs
auto formulaChecker = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) { return this->check(env, *formula); };
std::map<std::string, storm::storage::BitVector> apSets = helper.computeApSets(extracted, formulaChecker);
std::vector<ValueType> numericResult = helper.computeLTLProbabilities(env, *ltlFormula, apSets);
auto probabilisticTransitions = this->getModel().computeProbabilityMatrix();
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(probabilisticTransitions);
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, this->getModel());
auto formulaChecker = [&] (storm::logic::Formula const& formula) { return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); };
std::vector<ValueType> numericResult = helper.computeLTLProbabilities(env, pathFormula, formulaChecker);
// We can directly return the numericResult vector as the state space of the CTMC and the embedded DTMC are exactly the same
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
} }
template <typename SparseCtmcModelType> template <typename SparseCtmcModelType>
std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula, ValueType> const& checkTask) { std::unique_ptr<CheckResult> SparseCtmcCslModelChecker<SparseCtmcModelType>::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask<storm::logic::InstantaneousRewardFormula, ValueType> const& checkTask) {
storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula();

2
src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h

@ -30,6 +30,8 @@ namespace storm {
virtual std::unique_ptr<CheckResult> computeNextProbabilities(Environment const& env, CheckTask<storm::logic::NextFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeNextProbabilities(Environment const& env, CheckTask<storm::logic::NextFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeHOAPathProbabilities(Environment const& env, CheckTask<storm::logic::HOAPathFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(Environment const& env, CheckTask<storm::logic::StateFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(Environment const& env, CheckTask<storm::logic::StateFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override;

64
src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp

@ -111,57 +111,45 @@ namespace storm {
return result; return result;
} }
template<typename SparseMarkovAutomatonModelType>
std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeHOAPathProbabilities(Environment const& env, CheckTask<storm::logic::HOAPathFormula, ValueType> const& checkTask) {
storm::logic::HOAPathFormula const& pathFormula = checkTask.getFormula();
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(this->getModel().getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, this->getModel());
auto formulaChecker = [&] (storm::logic::Formula const& formula) { return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); };
auto apSets = helper.computeApSets(pathFormula.getAPMapping(), formulaChecker);
std::vector<ValueType> numericResult = helper.computeDAProductProbabilities(env, *pathFormula.readAutomaton(), apSets);
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
if (checkTask.isProduceSchedulersSet()) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler(this->getModel())));
}
return result;
}
template<typename SparseMarkovAutomatonModelType> template<typename SparseMarkovAutomatonModelType>
std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) { std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) {
storm::logic::PathFormula const& pathFormula = checkTask.getFormula(); storm::logic::PathFormula const& pathFormula = checkTask.getFormula();
STORM_LOG_INFO("Extracting maximal state formulas for path formula: " << pathFormula);
storm::logic::ExtractMaximalStateFormulasVisitor::ApToFormulaMap extracted;
// Maintain a mapping from formula-strings to labels in order to reuse labels of equivalent (compared as strings) formulas
std::map<std::string, std::string> cached;
std::shared_ptr<storm::logic::Formula> ltlFormula = storm::logic::ExtractMaximalStateFormulasVisitor::extract(pathFormula, extracted, cached);
const SparseMarkovAutomatonModelType& ma = this->getModel();
typedef typename storm::models::sparse::Mdp<typename SparseMarkovAutomatonModelType::ValueType> SparseMdpModelType;
STORM_LOG_INFO("Computing embedded MDP...");
storm::storage::SparseMatrix<ValueType> probabilityMatrix = ma.getTransitionMatrix();
// Copy of the state labelings of the MDP
storm::models::sparse::StateLabeling labeling(ma.getStateLabeling());
// The embedded MDP, used for building the product and computing the probabilities in the product
SparseMdpModelType embeddedMdp(std::move(probabilityMatrix), std::move(labeling));
storm::solver::SolveGoal<ValueType> goal(embeddedMdp, checkTask);
STORM_LOG_INFO("Performing ltl probability computations in embedded MDP...");
if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isTraceSet()) {
STORM_LOG_TRACE("Writing model to model.dot");
std::ofstream modelDot("model.dot");
embeddedMdp.writeDotToStream(modelDot);
modelDot.close();
}
storm::modelchecker::helper::SparseLTLHelper<ValueType, true> helper(embeddedMdp.getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, embeddedMdp);
// Compute Satisfaction sets for APs
auto formulaChecker = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) { return this->check(env, *formula); };
std::map<std::string, storm::storage::BitVector> apSets = helper.computeApSets(extracted, formulaChecker);
STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
std::vector<ValueType> numericResult = helper.computeLTLProbabilities(env, *ltlFormula, apSets);
storm::modelchecker::helper::SparseLTLHelper<ValueType, true> helper(this->getModel().getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel());
auto formulaChecker = [&] (storm::logic::Formula const& formula) { return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); };
std::vector<ValueType> numericResult = helper.computeLTLProbabilities(env, pathFormula, formulaChecker);
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
if (checkTask.isProduceSchedulersSet()) { if (checkTask.isProduceSchedulersSet()) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler(embeddedMdp)));
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler(this->getModel())));
} }
// We can directly return the numericResult vector as the state space of the CTMC and the embedded MDP are exactly the same
return result; return result;
} }
template<typename SparseMarkovAutomatonModelType> template<typename SparseMarkovAutomatonModelType>
std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) { std::unique_ptr<CheckResult> SparseMarkovAutomatonCslModelChecker<SparseMarkovAutomatonModelType>::computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) {
storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula();

1
src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h

@ -30,6 +30,7 @@ namespace storm {
virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeBoundedUntilProbabilities(Environment const& env, CheckTask<storm::logic::BoundedUntilFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeUntilProbabilities(Environment const& env, CheckTask<storm::logic::UntilFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeHOAPathProbabilities(Environment const& env, CheckTask<storm::logic::HOAPathFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::EventuallyFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::TotalRewardFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::TotalRewardFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(Environment const& env, CheckTask<storm::logic::StateFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(Environment const& env, CheckTask<storm::logic::StateFormula, ValueType> const& checkTask) override;

35
src/storm/modelchecker/helper/ltl/SparseLTLHelper.cpp

@ -1,10 +1,14 @@
#include "SparseLTLHelper.h" #include "SparseLTLHelper.h"
#include "storm/automata/LTL2DeterministicAutomaton.h" #include "storm/automata/LTL2DeterministicAutomaton.h"
#include "storm/automata/DeterministicAutomaton.h"
#include "storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h" #include "storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h"
#include "storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h" #include "storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h"
#include "storm/logic/ExtractMaximalStateFormulasVisitor.h"
#include "storm/solver/SolveGoal.h"
#include "storm/storage/StronglyConnectedComponentDecomposition.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h"
#include "storm/storage/MaximalEndComponentDecomposition.h" #include "storm/storage/MaximalEndComponentDecomposition.h"
#include "storm/storage/memorystructure/MemoryStructure.h" #include "storm/storage/memorystructure/MemoryStructure.h"
@ -108,18 +112,29 @@ namespace storm {
} }
template<typename ValueType, bool Nondeterministic> template<typename ValueType, bool Nondeterministic>
std::map<std::string, storm::storage::BitVector> SparseLTLHelper<ValueType, Nondeterministic>::computeApSets(std::map<std::string, std::shared_ptr<storm::logic::Formula const>> const& extracted, std::function<std::unique_ptr<CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> formulaChecker){
std::map<std::string, storm::storage::BitVector> apSets;
for (auto& p: extracted) {
STORM_LOG_INFO(" Computing satisfaction set for atomic proposition \"" << p.first << "\" <=> " << *p.second << "...");
std::vector<ValueType> SparseLTLHelper<ValueType, Nondeterministic>::computeLTLProbabilities(Environment const &env, storm::logic::PathFormula const& formula, CheckFormulaCallback const& formulaChecker) {
// Replace state-subformulae by atomic propositions (APs)
storm::logic::ExtractMaximalStateFormulasVisitor::ApToFormulaMap extracted;
std::shared_ptr<storm::logic::Formula> ltlFormula = storm::logic::ExtractMaximalStateFormulasVisitor::extract(formula, extracted);
STORM_LOG_ASSERT(ltlFormula->isPathFormula(), "Unexpected formula type.");
std::unique_ptr<CheckResult> subResultPointer = formulaChecker(p.second);
ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult();
auto sat = subResult.getTruthValuesVector();
// Compute Satisfaction sets for the APs (which represent the state-subformulae
auto apSets = computeApSets(extracted, formulaChecker);
STORM_LOG_INFO("Computing LTL probabilities for formula with " << apSets.size() << " atomic proposition(s).");
// Compute the resulting LTL probabilities
return computeLTLProbabilities(env, ltlFormula->asPathFormula(), apSets);
apSets[p.first] = std::move(sat);
STORM_LOG_INFO(" Atomic proposition \"" << p.first << "\" is satisfied by " << apSets[p.first].getNumberOfSetBits() << " states.");
}
template<typename ValueType, bool Nondeterministic>
std::map<std::string, storm::storage::BitVector> SparseLTLHelper<ValueType, Nondeterministic>::computeApSets(std::map<std::string, std::shared_ptr<storm::logic::Formula const>> const& extracted, CheckFormulaCallback const& formulaChecker) {
std::map<std::string, storm::storage::BitVector> apSets;
for (auto& p: extracted) {
STORM_LOG_DEBUG(" Computing satisfaction set for atomic proposition \"" << p.first << "\" <=> " << *p.second << "...");
apSets[p.first] = formulaChecker(*p.second);
} }
return apSets; return apSets;
} }
@ -579,7 +594,7 @@ namespace storm {
template<typename ValueType, bool Nondeterministic> template<typename ValueType, bool Nondeterministic>
std::vector <ValueType> SparseLTLHelper<ValueType, Nondeterministic>::computeLTLProbabilities(Environment const& env, storm::logic::Formula const& formula, std::map<std::string, storm::storage::BitVector>& apSatSets) {
std::vector <ValueType> SparseLTLHelper<ValueType, Nondeterministic>::computeLTLProbabilities(Environment const& env, storm::logic::PathFormula const& formula, std::map<std::string, storm::storage::BitVector>& apSatSets) {
std::shared_ptr<storm::logic::Formula const> ltlFormula; std::shared_ptr<storm::logic::Formula const> ltlFormula;
STORM_LOG_THROW((!Nondeterministic) || this->isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW((!Nondeterministic) || this->isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
if (Nondeterministic && this->getOptimizationDirection() == OptimizationDirection::Minimize) { if (Nondeterministic && this->getOptimizationDirection() == OptimizationDirection::Minimize) {

39
src/storm/modelchecker/helper/ltl/SparseLTLHelper.h

@ -1,16 +1,24 @@
#include "storm/modelchecker/helper/SingleValueModelCheckerHelper.h" #include "storm/modelchecker/helper/SingleValueModelCheckerHelper.h"
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
#include "storm/automata/DeterministicAutomaton.h"
#include "storm/storage/SparseMatrix.h" #include "storm/storage/SparseMatrix.h"
#include "storm/solver/SolveGoal.h"
#include "storm/storage/Scheduler.h"
#include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Dtmc.h"
#include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/Mdp.h"
#include "storm/logic/ExtractMaximalStateFormulasVisitor.h"
#include "storm/transformer/DAProductBuilder.h" #include "storm/transformer/DAProductBuilder.h"
namespace storm { namespace storm {
class Environment;
namespace logic {
class Formula;
class PathFormula;
}
namespace automata {
class DeterministicAutomaton;
}
namespace modelchecker { namespace modelchecker {
namespace helper { namespace helper {
@ -24,6 +32,8 @@ namespace storm {
public: public:
typedef std::function<storm::storage::BitVector(storm::logic::Formula const&)> CheckFormulaCallback;
/*! /*!
* The type of the product automaton (DTMC or MDP) that is used during the computation. * The type of the product automaton (DTMC or MDP) that is used during the computation.
*/ */
@ -44,13 +54,22 @@ namespace storm {
*/ */
storm::storage::Scheduler<ValueType> extractScheduler(storm::models::sparse::Model<ValueType> const& model); storm::storage::Scheduler<ValueType> extractScheduler(storm::models::sparse::Model<ValueType> const& model);
/*!
* Computes the LTL probabilities
* @param the LTL formula (allowing PCTL* like nesting)
* @param formulaChecker lambda that evaluates sub-formulas checks the provided formula and returns the set of states in which the formula holds
* @param the atomic propositions occuring in the formula together with the satisfaction sets
* @return a value for each state
*/
std::vector<ValueType> computeLTLProbabilities(Environment const &env, storm::logic::PathFormula const& formula, CheckFormulaCallback const& formulaChecker);
/*! /*!
* Computes the states that are satisfying the AP. * Computes the states that are satisfying the AP.
* @param mapping from Ap to formula
* @param lambda that checks the provided formula
* @param extracted mapping from Ap to formula
* @param formulaChecker lambda that checks the provided formula and returns the set of states in which the formula holds
* @return mapping from AP to satisfaction sets * @return mapping from AP to satisfaction sets
*/ */
static std::map<std::string, storm::storage::BitVector> computeApSets(std::map<std::string, std::shared_ptr<storm::logic::Formula const>> const& extracted, std::function<std::unique_ptr<CheckResult>(std::shared_ptr<storm::logic::Formula const> const& formula)> formulaChecker);
static std::map<std::string, storm::storage::BitVector> computeApSets(std::map<std::string, std::shared_ptr<storm::logic::Formula const>> const& extracted, CheckFormulaCallback const& formulaChecker);
/*! /*!
* Computes the (maximizing) probabilities for the constructed DA product * Computes the (maximizing) probabilities for the constructed DA product
@ -63,11 +82,11 @@ namespace storm {
/*! /*!
* Computes the LTL probabilities * Computes the LTL probabilities
* @param the LTL formula
* @param the atomic propositions and satisfaction sets
* @param formula the LTL formula (without PCTL*-like nesting)
* @param apSatSets a mapping from all atomic propositions occuring in the formula to the corresponding satisfaction set
* @return a value for each state * @return a value for each state
*/ */
std::vector<ValueType> computeLTLProbabilities(Environment const &env, storm::logic::Formula const& formula, std::map<std::string, storm::storage::BitVector>& apSatSets);
std::vector<ValueType> computeLTLProbabilities(Environment const &env, storm::logic::PathFormula const& formula, std::map<std::string, storm::storage::BitVector>& apSatSets);
private: private:
/*! /*!

54
src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp

@ -123,24 +123,14 @@ namespace storm {
template<typename SparseDtmcModelType> template<typename SparseDtmcModelType>
std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeHOAPathProbabilities(Environment const& env, CheckTask<storm::logic::HOAPathFormula, ValueType> const& checkTask) { std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeHOAPathProbabilities(Environment const& env, CheckTask<storm::logic::HOAPathFormula, ValueType> const& checkTask) {
storm::logic::HOAPathFormula const& pathFormula = checkTask.getFormula(); storm::logic::HOAPathFormula const& pathFormula = checkTask.getFormula();
STORM_LOG_INFO("Obtaining HOA automaton...");
storm::automata::DeterministicAutomaton::ptr da = pathFormula.readAutomaton();
STORM_LOG_INFO("Deterministic automaton from HOA file has "
<< da->getNumberOfStates() << " states, "
<< da->getAPSet().size() << " atomic propositions and "
<< *da->getAcceptance()->getAcceptanceExpression() << " as acceptance condition.");
const SparseDtmcModelType& dtmc = this->getModel();
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(dtmc.getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, dtmc);
// Compute Satisfaction sets for APs
storm::logic::ExtractMaximalStateFormulasVisitor::ApToFormulaMap extracted = pathFormula.getAPMapping();
auto formulaChecker = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) {return this->check(*formula); };
std::map<std::string, storm::storage::BitVector> apSets = helper.computeApSets(extracted, formulaChecker);
std::vector<ValueType> numericResult = helper.computeDAProductProbabilities(env, *da, apSets);
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(this->getModel().getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, this->getModel());
auto formulaChecker = [&] (storm::logic::Formula const& formula) { return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); };
auto apSets = helper.computeApSets(pathFormula.getAPMapping(), formulaChecker);
std::vector<ValueType> numericResult = helper.computeDAProductProbabilities(env, *pathFormula.readAutomaton(), apSets);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
} }
@ -148,30 +138,12 @@ namespace storm {
std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) { std::unique_ptr<CheckResult> SparseDtmcPrctlModelChecker<SparseDtmcModelType>::computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) {
storm::logic::PathFormula const& pathFormula = checkTask.getFormula(); storm::logic::PathFormula const& pathFormula = checkTask.getFormula();
STORM_LOG_INFO("Extracting maximal state formulas for path formula: " << pathFormula);
storm::logic::ExtractMaximalStateFormulasVisitor::ApToFormulaMap extracted;
// Maintain a mapping from formula-strings to labels in order to reuse labels of equivalent (compared as strings) formulas
std::map<std::string, std::string> cached;
std::shared_ptr<storm::logic::Formula> ltlFormula = storm::logic::ExtractMaximalStateFormulasVisitor::extract(pathFormula, extracted, cached);
const SparseDtmcModelType& dtmc = this->getModel();
// TODO ?
if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isTraceSet()) {
STORM_LOG_TRACE("Writing model to model.dot");
std::ofstream modelDot("model.dot");
dtmc.writeDotToStream(modelDot);
modelDot.close();
}
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(dtmc.getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, dtmc);
// Compute Satisfaction sets for APs
auto formulaChecker = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) { return this->check(env, *formula); };
std::map<std::string, storm::storage::BitVector> apSets = helper.computeApSets(extracted, formulaChecker);
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(this->getModel().getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, this->getModel());
auto formulaChecker = [&] (storm::logic::Formula const& formula) { return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); };
std::vector<ValueType> numericResult = helper.computeLTLProbabilities(env, pathFormula, formulaChecker);
std::vector<ValueType> numericResult = helper.computeLTLProbabilities(env, *ltlFormula, apSets);
return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); return std::unique_ptr<CheckResult>(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
} }

53
src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp

@ -14,8 +14,6 @@
#include "storm/logic/FragmentSpecification.h" #include "storm/logic/FragmentSpecification.h"
#include "storm/logic/ExtractMaximalStateFormulasVisitor.h"
#include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/StandardRewardModel.h"
#include "storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h" #include "storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h"
@ -167,44 +165,45 @@ namespace storm {
return result; return result;
} }
template<typename SparseMdpModelType>
std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeHOAPathProbabilities(Environment const& env, CheckTask<storm::logic::HOAPathFormula, ValueType> const& checkTask) {
storm::logic::HOAPathFormula const& pathFormula = checkTask.getFormula();
storm::modelchecker::helper::SparseLTLHelper<ValueType, false> helper(this->getModel().getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskDeterministic(helper, checkTask, this->getModel());
auto formulaChecker = [&] (storm::logic::Formula const& formula) { return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); };
auto apSets = helper.computeApSets(pathFormula.getAPMapping(), formulaChecker);
std::vector<ValueType> numericResult = helper.computeDAProductProbabilities(env, *pathFormula.readAutomaton(), apSets);
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
if (checkTask.isProduceSchedulersSet()) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler(this->getModel())));
}
return result;
}
template<typename SparseMdpModelType> template<typename SparseMdpModelType>
std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) { std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) {
storm::logic::PathFormula const& pathFormula = checkTask.getFormula(); storm::logic::PathFormula const& pathFormula = checkTask.getFormula();
STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model.");
STORM_LOG_INFO("Extracting maximal state formulas for path formula: " << pathFormula);
storm::logic::ExtractMaximalStateFormulasVisitor::ApToFormulaMap extracted;
// Maintain a mapping from formula-strings to labels in order to reuse labels of equivalent (compared as strings) formulas
std::map<std::string, std::string> cached;
std::shared_ptr<storm::logic::Formula> ltlFormula = storm::logic::ExtractMaximalStateFormulasVisitor::extract(pathFormula, extracted, cached);
const SparseMdpModelType& mdp = this->getModel();
if (storm::settings::getModule<storm::settings::modules::DebugSettings>().isTraceSet()) {
STORM_LOG_TRACE("Writing model to model.dot");
std::ofstream modelDot("model.dot");
this->getModel().writeDotToStream(modelDot);
modelDot.close();
}
storm::modelchecker::helper::SparseLTLHelper<ValueType, true> helper(mdp.getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, mdp);
// Compute Satisfaction sets for APs
auto formulaChecker = [&] (std::shared_ptr<storm::logic::Formula const> const& formula) { return this->check(env, *formula); };
std::map<std::string, storm::storage::BitVector> apSets = helper.computeApSets(extracted, formulaChecker);
std::vector<ValueType> numericResult = helper.computeLTLProbabilities(env, *ltlFormula, apSets);
storm::modelchecker::helper::SparseLTLHelper<ValueType, true> helper(this->getModel().getTransitionMatrix());
storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel());
auto formulaChecker = [&] (storm::logic::Formula const& formula) { return this->check(env, formula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); };
std::vector<ValueType> numericResult = helper.computeLTLProbabilities(env, pathFormula, formulaChecker);
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult))); std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(numericResult)));
if (checkTask.isProduceSchedulersSet()) { if (checkTask.isProduceSchedulersSet()) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler(mdp)));
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler(this->getModel())));
} }
return result; return result;
} }
template<typename SparseMdpModelType> template<typename SparseMdpModelType>
std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeConditionalProbabilities(Environment const& env, CheckTask<storm::logic::ConditionalFormula, ValueType> const& checkTask) { std::unique_ptr<CheckResult> SparseMdpPrctlModelChecker<SparseMdpModelType>::computeConditionalProbabilities(Environment const& env, CheckTask<storm::logic::ConditionalFormula, ValueType> const& checkTask) {
storm::logic::ConditionalFormula const& conditionalFormula = checkTask.getFormula(); storm::logic::ConditionalFormula const& conditionalFormula = checkTask.getFormula();

1
src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h

@ -41,6 +41,7 @@ namespace storm {
virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(Environment const& env, CheckTask<storm::logic::StateFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageProbabilities(Environment const& env, CheckTask<storm::logic::StateFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> computeLTLProbabilities(Environment const& env, CheckTask<storm::logic::PathFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> computeHOAPathProbabilities(Environment const& env, CheckTask<storm::logic::HOAPathFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> checkMultiObjectiveFormula(Environment const& env, CheckTask<storm::logic::MultiObjectiveFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> checkMultiObjectiveFormula(Environment const& env, CheckTask<storm::logic::MultiObjectiveFormula, ValueType> const& checkTask) override;
virtual std::unique_ptr<CheckResult> checkQuantileFormula(Environment const& env, CheckTask<storm::logic::QuantileFormula, ValueType> const& checkTask) override; virtual std::unique_ptr<CheckResult> checkQuantileFormula(Environment const& env, CheckTask<storm::logic::QuantileFormula, ValueType> const& checkTask) override;

Loading…
Cancel
Save