diff --git a/src/storm/transformer/MemoryIncorporation.cpp b/src/storm/transformer/MemoryIncorporation.cpp new file mode 100644 index 000000000..613a9af3b --- /dev/null +++ b/src/storm/transformer/MemoryIncorporation.cpp @@ -0,0 +1,100 @@ +#include "MemoryIncorporation.h" + +#include "storm/models/sparse/Mdp.h" +#include "storm/models/sparse/MarkovAutomaton.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/storage/memorystructure/MemoryStructureBuilder.h" +#include "storm/storage/memorystructure/NondeterministicMemoryStructureBuilder.h" +#include "storm/storage/memorystructure/SparseModelMemoryProduct.h" +#include "storm/storage/memorystructure/SparseModelNondeterministicMemoryProduct.h" +#include "storm/logic/Formulas.h" +#include "storm/logic/FragmentSpecification.h" +#include "storm/modelchecker/propositional/SparsePropositionalModelChecker.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" + +#include "storm/utility/macros.h" + +#include "storm/exceptions/NotImplementedException.h" +#include "storm/exceptions/NotSupportedException.h" +namespace storm { + namespace transformer { + + template + storm::storage::MemoryStructure getGoalMemory(SparseModelType const& model, storm::logic::Formula const& propositionalGoalStateFormula) { + STORM_LOG_THROW(propositionalGoalStateFormula.isInFragment(storm::logic::propositional()), storm::exceptions::NotSupportedException, "The subformula " << propositionalGoalStateFormula << " should be propositional."); + + storm::modelchecker::SparsePropositionalModelChecker mc(model); + storm::storage::BitVector goalStates = mc.check(propositionalGoalStateFormula)->asExplicitQualitativeCheckResult().getTruthValuesVector(); + + // Check if the formula is already satisfied for all initial states. In such a case the trivial memory structure suffices. + if (model.getInitialStates().isSubsetOf(goalStates)) { + STORM_LOG_INFO("One objective is already satisfied for all initial states."); + return storm::storage::MemoryStructureBuilder::buildTrivialMemoryStructure(model); + } + + + // Create a memory structure that stores whether a goal state has already been reached + storm::storage::MemoryStructureBuilder builder(2, model); + builder.setTransition(0, 0, ~goalStates); + builder.setTransition(0, 1, goalStates); + builder.setTransition(1, 1, storm::storage::BitVector(model.getNumberOfStates(), true)); + for (auto const& initState : model.getInitialStates()) { + builder.setInitialMemoryState(initState, goalStates.get(initState) ? 1 : 0); + } + return builder.build(); + } + + template + storm::storage::MemoryStructure getUntilFormulaMemory(SparseModelType const& model, storm::logic::Formula const& leftSubFormula, storm::logic::Formula const& rightSubFormula) { + auto notLeftOrRight = std::make_shared(storm::logic::BinaryBooleanStateFormula::OperatorType::Or, + std::make_shared(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, leftSubFormula.asSharedPointer()), + rightSubFormula.asSharedPointer()); + return getGoalMemory(model, *notLeftOrRight); + + } + + template + std::shared_ptr MemoryIncorporation::incorporateGoalMemory(SparseModelType const& model, std::vector> const& formulas) { + storm::storage::MemoryStructure memory = storm::storage::MemoryStructureBuilder::buildTrivialMemoryStructure(model); + + for (auto const& subFormula : formulas) { + STORM_LOG_THROW(subFormula->isOperatorFormula(), storm::exceptions::NotSupportedException, "The given Formula " << *subFormula << " is not supported."); + auto const& subsubFormula = subFormula->asOperatorFormula().getSubformula(); + if (subsubFormula.isEventuallyFormula()) { + memory = memory.product(getGoalMemory(model, subsubFormula.asEventuallyFormula().getSubformula())); + } else if (subsubFormula.isUntilFormula()) { + memory = memory.product(getUntilFormulaMemory(model, subsubFormula.asUntilFormula().getLeftSubformula(), subsubFormula.asUntilFormula().getRightSubformula())); + } else if (subsubFormula.isBoundedUntilFormula()) { + // For bounded formulas it is only reasonable to add the goal memory if it considers a single upper step/time bound. + auto const& buf = subsubFormula.asBoundedUntilFormula(); + if (!buf.isMultiDimensional() && !buf.getTimeBoundReference().isRewardBound() && (!buf.hasLowerBound() || (!buf.isLowerBoundStrict() && storm::utility::isZero(buf.template getLowerBound())))) { + memory = memory.product(getUntilFormulaMemory(model, buf.getLeftSubformula(), buf.getRightSubformula())); + } + } else if (subsubFormula.isGloballyFormula()) { + auto notPhi = std::make_shared(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, subsubFormula.asGloballyFormula().getSubformula().asSharedPointer()); + memory = memory.product(getGoalMemory(model, *notPhi)); + } else { + STORM_LOG_THROW(subsubFormula.isTotalRewardFormula() || subsubFormula.isCumulativeRewardFormula(), storm::exceptions::NotSupportedException, "The given Formula " << subsubFormula << " is not supported."); + } + } + + storm::storage::SparseModelMemoryProduct product = memory.product(model); + return std::dynamic_pointer_cast(product.build()); + } + + template + std::shared_ptr MemoryIncorporation::incorporateFullMemory(SparseModelType const& model, uint64_t memoryStates) { + auto memory = storm::storage::NondeterministicMemoryStructureBuilder().build(storm::storage::NondeterministicMemoryStructurePattern::Full, memoryStates); + return storm::storage::SparseModelNondeterministicMemoryProduct(model, memory).build(); + } + + template class MemoryIncorporation>; + template class MemoryIncorporation>; + + template class MemoryIncorporation>; + template class MemoryIncorporation>; + + } +} + + diff --git a/src/storm/transformer/MemoryIncorporation.h b/src/storm/transformer/MemoryIncorporation.h new file mode 100644 index 000000000..37e9c8158 --- /dev/null +++ b/src/storm/transformer/MemoryIncorporation.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "storm/storage/memorystructure/MemoryStructure.h" +#include "storm/logic/MultiObjectiveFormula.h" +#include "storm/logic/Formula.h" + +namespace storm { + namespace transformer { + + /*! + * Incorporates Memory into the state space of the given model, that is + * the resulting model is the crossproduct of of the given model plus + * some type of memory structure + */ + template + class MemoryIncorporation { + + typedef typename SparseModelType::ValueType ValueType; + typedef typename SparseModelType::RewardModelType RewardModelType; + + + + public: + + /*! + * Incorporates memory that stores whether a 'goal' state has already been reached. + */ + static std::shared_ptr incorporateGoalMemory(SparseModelType const& model, std::vector> const& formulas); + + /*! + * Incorporates a memory structure where the nondeterminism of the model decides which successor state to choose. + */ + static std::shared_ptr incorporateFullMemory(SparseModelType const& model, uint64_t memoryStates); + + }; + } +} + +